2.4.1
This commit is contained in:
commit
6466ec67ed
3046 changed files with 663075 additions and 0 deletions
32
.clang-format
Normal file
32
.clang-format
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
# Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 120
|
||||
PointerAlignment: Left
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
Standard: c++14
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
...
|
4
.clangd
Normal file
4
.clangd
Normal file
|
@ -0,0 +1,4 @@
|
|||
Diagnostics:
|
||||
UnusedIncludes: Strict
|
||||
InlayHints:
|
||||
Designators: No
|
81
.cproject
Normal file
81
.cproject
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="cdt.managedbuild.toolchain.gnu.base.1703525987">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.1703525987" moduleId="org.eclipse.cdt.core.settings" name="Default">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.base.1703525987" name="Default" optionalBuildProperties="" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||
<folderInfo id="cdt.managedbuild.toolchain.gnu.base.1703525987.286272243" name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.base.839081610" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.GNU_ELF" id="cdt.managedbuild.target.gnu.platform.base.16134557" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
|
||||
<builder arguments="-j12" command="make" id="cdt.managedbuild.target.gnu.builder.base.285467957" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1258891957" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1837414633" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.592090380" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1154097230" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1955960919" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1427539948" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.1374966898" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1235029049" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.assembler.base.1359322398" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1730089024" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry excluding="OUTPUT/|WORK/" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="flexisip.null.527299867" name="flexisip"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
<configuration configurationName="Default">
|
||||
<resource resourceType="PROJECT" workspacePath="/flexisip"/>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<scannerConfigBuildInfo instanceId="0.1713448483">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="0.1420834493">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="0.705448153">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
|
||||
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
|
||||
<buildOutputProvider>
|
||||
<openAction enabled="true" filePath=""/>
|
||||
<parser enabled="false"/>
|
||||
</buildOutputProvider>
|
||||
<scannerInfoProvider id="specsFile">
|
||||
<runAction arguments="-s -C scripts discovery" command="make" useDefault="true"/>
|
||||
<parser enabled="true"/>
|
||||
</scannerInfoProvider>
|
||||
</profile>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
</cproject>
|
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Build/install
|
||||
*build*/
|
||||
*install*/
|
||||
|
||||
# Unused
|
||||
test_deprecated/
|
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
### Any build directory ###
|
||||
/build*
|
||||
|
||||
### IDE or editor files ###
|
||||
*.kdev4
|
||||
*.settings
|
||||
*.kate*
|
||||
.DS_Store
|
||||
.vscode
|
||||
/CMakeLists.txt.user
|
||||
.idea/
|
||||
|
||||
### TEST ###
|
||||
BCUnitAutomated-Results.xml
|
||||
|
||||
### Direnv ###
|
||||
.direnv
|
51
.gitlab-ci-files/README.md
Normal file
51
.gitlab-ci-files/README.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Flexisip continuous integration
|
||||
|
||||
The files contained in this directories are responsible for continuous integration. Each yaml file is included in the root `.gitlab-ci.yml` of the Flexisip project.
|
||||
|
||||
## Basic documentation of Gitlab-CI keywords
|
||||
|
||||
A basic documentation of the keywords is available in French on the [internal wiki](https://wiki.linphone.org/xwiki/bin/view/Engineering/Fonctionnement%20Gitlab-CI/).
|
||||
It helps to understand the basics of Gitlab-CI.
|
||||
|
||||
## Flexisip tests
|
||||
|
||||
The Flexisip tests are run in the `tests-flexisip-mr` job of the `job-linux.yml` file. They rely on the current build from source of the Flexisip docker image done in the `docker-build-flexisip-src` job of the same file.
|
||||
|
||||
A Flexisip developper only needs to modify the following variables in `tests-flexisip-mr` for most usages :
|
||||
|
||||
- `LIBLINPHONE_DOCKER_TAG`
|
||||
- `LIME_SERVER_VERSION`
|
||||
- `ACCOUNT_MANAGER_VERSION`
|
||||
- `FILE_TRANSFER_SERVER_VERSION`
|
||||
|
||||
You can find more information in the comments of this job.
|
||||
|
||||
What the test jobs does :
|
||||
|
||||
- It creates a workspace to store the logs of all components, and coredumps
|
||||
- It launches docker-compose, running containers of Flexisip primary and auxiliary services. You can find all the services called in the docker-compose.yaml and docker-compose-standalone.yaml files of the [Flexisip-tester project](https://gitlab.linphone.org/BC/private/flexisip-tester).
|
||||
- It prints logs of the liblinphone_tester in Gitlab-CI output.
|
||||
- It uploads other logs in the artifacts.
|
||||
- It displays the backtrace of liblinphone_tester and flexisip if coredumps were generated during the tests.
|
||||
|
||||
## Files structure
|
||||
|
||||
The files of this directory are organized by system type and by distribution.
|
||||
Each file responsible for a Linux distribution has jobs inheriting from jobs located in `job-linux.yml` file.
|
||||
|
||||
Typically, this is a sample structure to illustrate :
|
||||
|
||||
- job-Linux
|
||||
- build
|
||||
- test
|
||||
- package
|
||||
- upload
|
||||
- job-linux-centos7
|
||||
- build-centos7 (extends `build`)
|
||||
- test-centos7 (extends `test`)
|
||||
- package-centos7 (extends `package`)
|
||||
- upload-centos7 (extends `upload`)
|
||||
- job-linux-ubuntu
|
||||
- build-ubuntu (extends `build`)
|
||||
- package-ubuntu (extends `package`)
|
||||
- upload-ubuntu (extends `upload`)
|
55
.gitlab-ci-files/deploy.sh
Executable file
55
.gitlab-ci-files/deploy.sh
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
|
||||
function print_usage {
|
||||
prog=$(basename $0)
|
||||
echo "syntax: $prog <dist>" 1>&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
if [ -z "$1" ] || [ "${1:0:1}" = '-' ]; then
|
||||
print_usage $0
|
||||
fi
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
print_usage $0
|
||||
fi
|
||||
|
||||
dist="$1"
|
||||
|
||||
|
||||
id=$(cat /dev/urandom | env LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1) || exit $?
|
||||
tmpdir="$MAKE_REPO_TMP/tmp-$id"
|
||||
rsync_dest="$DEPLOY_SERVER:$tmpdir/"
|
||||
|
||||
case "$dist" in
|
||||
'centos')
|
||||
make_repo_args="rpm $tmpdir $CENTOS_REPOSITORY"
|
||||
rsync_src='build/*.rpm'
|
||||
;;
|
||||
'rockylinux')
|
||||
make_repo_args="rpm $tmpdir $ROCKYLINUX_REPOSITORY"
|
||||
rsync_src='build/*.rpm'
|
||||
;;
|
||||
'debian')
|
||||
make_repo_args="deb $tmpdir $FREIGHT_PATH $RELEASE"
|
||||
echo "make_repo_args=$make_repo_args"
|
||||
rsync_src='build/*.deb build/*.ddeb'
|
||||
;;
|
||||
*)
|
||||
echo "invalid distribution type: '$dist'. Only 'centos', 'rockylinux' and 'debian' are valid" 1>&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ">>> Pushing packages into '$rsync_dest'"
|
||||
rsync -v $rsync_src $rsync_dest
|
||||
|
||||
echo ">>> Connecting on '$DEPLOY_SERVER'"
|
||||
ssh $DEPLOY_SERVER "
|
||||
echo '>>>> Making repository'
|
||||
make_repo $make_repo_args || exit 1
|
||||
|
||||
echo \">>>> Removing '$tmpdir'\"
|
||||
rm -r $tmpdir
|
||||
"
|
||||
|
54
.gitlab-ci-files/job-linux-archlinux.yml
Normal file
54
.gitlab-ci-files/job-linux-archlinux.yml
Normal file
|
@ -0,0 +1,54 @@
|
|||
.archlinux-image-variables:
|
||||
image: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-archlinux:$ARCHLINUX_IMAGE_VERSION
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON -DENABLE_UNIT_TESTS_NGHTTP2ASIO=OFF
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-archlinux-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .archlinux-image-variables
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-gcc rules
|
||||
|
||||
|
||||
job-archlinux-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .archlinux-image-variables
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-clang rules
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-archlinux-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .archlinux-image-variables
|
||||
# Uncomment when re-enabling tests
|
||||
# - .tester-artifacts
|
||||
rules:
|
||||
- !reference [job-archlinux-ninja-clang, rules]
|
||||
|
||||
|
||||
job-archlinux-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .archlinux-image-variables
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-archlinux-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .archlinux-image-variables
|
||||
# 2023-07-06: The combination of an Ubuntu (22 or 23) host and an Archlinux image somehow breaks port assignments for yet unknown reasons.
|
||||
# Symptoms: "Cannot assign requested address" errors from bctoolbox, sofia, and redis.
|
||||
- .rules-never-run # ⚠ See `rules.yml`
|
||||
needs:
|
||||
- job-archlinux-ninja-gcc
|
118
.gitlab-ci-files/job-linux-debian11.yml
Normal file
118
.gitlab-ci-files/job-linux-debian11.yml
Normal file
|
@ -0,0 +1,118 @@
|
|||
.debian11-image:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-debian11:$DEBIAN_11_IMAGE_VERSION
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-debian11-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .debian11-image
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-gcc rules
|
||||
|
||||
|
||||
job-debian11-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .debian11-image
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-clang rules
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-debian11-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .debian11-image
|
||||
|
||||
|
||||
job-debian11-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .debian11-image
|
||||
- .tester-artifacts
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON -DENABLE_COVERAGE=ON
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-debian11-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .debian11-image
|
||||
needs:
|
||||
- job-debian11-ninja-clang
|
||||
after_script:
|
||||
- ls -lah #default.profraw should exist
|
||||
- llvm-profdata merge -sparse default.profraw -o default.profdata
|
||||
artifacts:
|
||||
paths:
|
||||
- default.profdata
|
||||
- work/lib/libflexisip.so
|
||||
|
||||
|
||||
debian11-coverage:
|
||||
stage: coverage 📑
|
||||
tags: [ "docker-test-flexisip" ]
|
||||
extends:
|
||||
- .rules-dev
|
||||
- .debian11-image
|
||||
needs:
|
||||
- job-debian11-unit-test
|
||||
script:
|
||||
- export TERM=xterm-color
|
||||
- echo "Full coverage of Flexisip library"
|
||||
- llvm-cov show $PWD/work/lib/libflexisip.so -instr-profile=default.profdata include/flexisip src --ignore-filename-regex=src\/lib\/.* -use-color > flexisip_coverage_lines_full.txt
|
||||
- echo "Display coverage by file of Flexisip library"
|
||||
- llvm-cov report $PWD/work/lib/libflexisip.so -instr-profile=default.profdata include/flexisip src --ignore-filename-regex=src\/lib\/.* -use-color | tee flexisip_coverage_report_by_file.txt
|
||||
- echo "filtering work of report to get global coverage %"
|
||||
- cat flexisip_coverage_report_by_file.txt| grep -E "TOTAL" | grep -Po "\d+\.\d+\%" | sed -n '3p'
|
||||
- echo "Export results in JSON format"
|
||||
- llvm-cov export $PWD/work/lib/libflexisip.so -instr-profile=default.profdata -format=text include/flexisip src --ignore-filename-regex=src\/lib\/.* -use-color > flexisip_coverage_export.txt
|
||||
- echo "Export results in Lcov format"
|
||||
- llvm-cov export $PWD/work/lib/libflexisip.so -instr-profile=default.profdata -format=lcov include/flexisip src --ignore-filename-regex=src\/lib\/.* -use-color > flexisip_coverage_export.lcov
|
||||
- lcov_cobertura flexisip_coverage_export.lcov
|
||||
coverage: '/[0-9][0-9]\.[0-9]+\%/'
|
||||
artifacts:
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: coverage.xml
|
||||
paths:
|
||||
- default.profdata
|
||||
- flexisip_coverage_report_by_file.txt
|
||||
- flexisip_coverage_lines_full.txt
|
||||
- flexisip_coverage_export.lcov
|
||||
- flexisip_coverage_export.txt
|
||||
- coverage.xml
|
||||
expire_in: 1 week
|
||||
|
||||
#################################################
|
||||
# DEB
|
||||
#################################################
|
||||
|
||||
job-debian11-deb:
|
||||
extends:
|
||||
- .job-linux-deb
|
||||
- .debian11-image
|
||||
needs:
|
||||
- job: job-debian11-unit-test
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-debian11-ninja-clang
|
||||
optional: true
|
||||
artifacts: false
|
||||
|
||||
|
||||
job-debian11-deb-deploy:
|
||||
extends: .job-debian-deb-deploy
|
||||
variables:
|
||||
RELEASE: bullseye
|
||||
FREIGHT_PATH: $DEBIAN_FREIGHT_CONF_PATH
|
||||
dependencies:
|
||||
- job-debian11-deb
|
95
.gitlab-ci-files/job-linux-debian12.yml
Normal file
95
.gitlab-ci-files/job-linux-debian12.yml
Normal file
|
@ -0,0 +1,95 @@
|
|||
.debian12-image:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-debian12:$DEBIAN_12_IMAGE_VERSION
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-debian12-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .debian12-image
|
||||
- .rules-manual # ⚠ See `rules.yml`, override .job-makefile-gcc rules
|
||||
|
||||
|
||||
job-debian12-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .debian12-image
|
||||
- .rules-manual # ⚠ See `rules.yml`, override .job-makefile-clang rules
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-debian12-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .debian12-image
|
||||
# Debian 12 packages GCC 12 (fitting!) for which our cmake has special-caseing,
|
||||
# so let's override the .job-ninja-gcc rules to run it in dev pipelines
|
||||
- .rules-dev # ⚠ See `rules.yml`
|
||||
|
||||
|
||||
job-debian12-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .debian12-image
|
||||
- .tester-artifacts
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-debian12-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .debian12-image
|
||||
needs:
|
||||
- job-debian12-ninja-clang
|
||||
artifacts:
|
||||
paths:
|
||||
- work/lib/libflexisip.so
|
||||
|
||||
#################################################
|
||||
# DEB
|
||||
#################################################
|
||||
|
||||
job-debian12-deb:
|
||||
extends:
|
||||
- .job-linux-deb
|
||||
- .debian12-image
|
||||
needs:
|
||||
- job: job-debian12-unit-test
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-debian12-ninja-clang
|
||||
optional: true
|
||||
artifacts: false
|
||||
|
||||
# Test installation of the DEB package and check its feature list
|
||||
job-debian12-deb-check-features:
|
||||
stage: check-package 📤
|
||||
tags: [ "docker" ]
|
||||
image: debian:12
|
||||
rules:
|
||||
- !reference [job-debian12-deb, rules]
|
||||
needs:
|
||||
- job: job-debian12-deb
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- apt update
|
||||
- apt install -y ./build/*.deb
|
||||
- !reference [.script-check-features, script]
|
||||
|
||||
job-debian12-deb-deploy:
|
||||
extends: .job-debian-deb-deploy
|
||||
variables:
|
||||
RELEASE: bookworm
|
||||
FREIGHT_PATH: $DEBIAN_FREIGHT_CONF_PATH
|
||||
dependencies:
|
||||
- job-debian12-deb
|
16
.gitlab-ci-files/job-linux-minimal.yml
Normal file
16
.gitlab-ci-files/job-linux-minimal.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
.minimal-image:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-minimal:$MINIMAL_IMAGE_VERSION
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-minimal-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .minimal-image
|
||||
- .rules-dev # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_PRESENCE=OFF -DENABLE_REDIS=OFF -DENABLE_SNMP=OFF -DENABLE_SOCI=OFF -DENABLE_TRANSCODER=OFF -DENABLE_MDNS=OFF -DENABLE_EXTERNAL_AUTH_PLUGIN=OFF -DENABLE_JWE_AUTH_PLUGIN=OFF -DENABLE_CONFERENCE=OFF -DENABLE_SOCI_POSTGRESQL_BACKEND=OFF -DENABLE_B2BUA=OFF -DENABLE_UNIT_TESTS=OFF -DENABLE_FLEXIAPI=OFF
|
||||
|
92
.gitlab-ci-files/job-linux-rocky8.yml
Normal file
92
.gitlab-ci-files/job-linux-rocky8.yml
Normal file
|
@ -0,0 +1,92 @@
|
|||
variables:
|
||||
ROCKY8_CMAKE_OPTIONS: -DINTERNAL_LIBHIREDIS=ON
|
||||
ROCKY8_CMAKE_OPTIONS_UNIT_TESTS: -DINTERNAL_LIBHIREDIS=ON -DENABLE_UNIT_TESTS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON
|
||||
|
||||
.rocky8-image-variables:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-rocky8:$ROCKY_8_IMAGE_VERSION
|
||||
variables:
|
||||
CMAKE_OPTIONS: ${ROCKY8_CMAKE_OPTIONS}
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-rocky8-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .rocky8-image-variables
|
||||
|
||||
|
||||
job-rocky8-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .rocky8-image-variables
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-rocky8-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .rocky8-image-variables
|
||||
|
||||
|
||||
job-rocky8-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .rocky8-image-variables
|
||||
- .tester-artifacts
|
||||
variables:
|
||||
# -DCMAKE_PREFIX_PATH=/usr/local: Unit tests require libnghttp2_asio, which has been build and intalled into /usr/local
|
||||
CMAKE_OPTIONS: ${ROCKY8_CMAKE_OPTIONS_UNIT_TESTS}
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-rocky8-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .rocky8-image-variables
|
||||
needs:
|
||||
- job-rocky8-ninja-clang
|
||||
|
||||
#################################################
|
||||
# RPM
|
||||
#################################################
|
||||
|
||||
job-rocky8-rpm:
|
||||
extends:
|
||||
- .job-linux-rpm
|
||||
- .rocky8-image-variables
|
||||
needs:
|
||||
- job: job-rocky8-unit-test
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-rocky8-ninja-clang
|
||||
optional: true
|
||||
artifacts: false
|
||||
|
||||
# Test installation of the RPM package and check its feature list
|
||||
job-rocky8-rpm-check-features:
|
||||
stage: check-package 📤
|
||||
tags: [ "docker" ]
|
||||
extends:
|
||||
- .rocky8-image-variables
|
||||
rules:
|
||||
- !reference [job-rocky8-rpm, rules]
|
||||
needs:
|
||||
- job: job-rocky8-rpm
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- !reference [job-rocky9-rpm-check-features, script]
|
||||
|
||||
job-rocky8-rpm-deploy:
|
||||
extends: .job-rpm-deploy
|
||||
dependencies:
|
||||
- job-rocky8-rpm
|
||||
variables:
|
||||
DISTRIB: rockylinux
|
128
.gitlab-ci-files/job-linux-rocky9.yml
Normal file
128
.gitlab-ci-files/job-linux-rocky9.yml
Normal file
|
@ -0,0 +1,128 @@
|
|||
variables:
|
||||
ROCKY9_CMAKE_OPTIONS_UNIT_TESTS: -DENABLE_UNIT_TESTS=ON -DENABLE_UNIT_TESTS_MYSQL=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON
|
||||
|
||||
.rocky9-image-variables:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-rocky9:$ROCKY_9_IMAGE_VERSION
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-rocky9-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .rocky9-image-variables
|
||||
|
||||
|
||||
job-rocky9-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .rocky9-image-variables
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-rocky9-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .rocky9-image-variables
|
||||
|
||||
|
||||
job-rocky9-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .rocky9-image-variables
|
||||
- .tester-artifacts
|
||||
variables:
|
||||
# -DCMAKE_PREFIX_PATH=/usr/local: Unit tests require libnghttp2_asio, which has been build and intalled into /usr/local
|
||||
CMAKE_OPTIONS: ${ROCKY9_CMAKE_OPTIONS_UNIT_TESTS}
|
||||
|
||||
job-rocky9-ninja-clang-nosoci:
|
||||
extends:
|
||||
- job-rocky9-ninja-clang
|
||||
variables:
|
||||
CMAKE_OPTIONS: ${ROCKY9_CMAKE_OPTIONS_UNIT_TESTS} -DENABLE_SOCI=OFF -DENABLE_B2BUA=ON -DENABLE_CONFERENCE=ON
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-rocky9-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .rocky9-image-variables
|
||||
needs:
|
||||
- job-rocky9-ninja-clang
|
||||
|
||||
job-rocky9-unit-test-nosoci:
|
||||
extends:
|
||||
- job-rocky9-unit-test
|
||||
needs:
|
||||
- job-rocky9-ninja-clang-nosoci
|
||||
|
||||
#################################################
|
||||
# XWiki reference documentation
|
||||
#################################################
|
||||
|
||||
job-rocky9-xwiki-doc-deploy:
|
||||
stage: deploy 🚀
|
||||
tags: [ "docker" ]
|
||||
extends:
|
||||
- .rules-deploy # ⚠ See `rules.yml`
|
||||
- .rocky9-image-variables
|
||||
script:
|
||||
- prefix=/opt/belledonne-communications
|
||||
- builddir=wikiBuild
|
||||
- sudo mkdir -p $prefix
|
||||
- sudo chown bc:bc $prefix
|
||||
- mkdir $builddir
|
||||
- cmake -S . -B $builddir -G Ninja -DCMAKE_INSTALL_PREFIX=$prefix -DCMAKE_PREFIX_PATH=$prefix $DEFAULT_CMAKE_OPTIONS
|
||||
- cmake --build $builddir
|
||||
- /usr/bin/python3 ./doc/xw.py --flexisip-binary $builddir/bin/flexisip -H $XWIKI_HOSTNAME -u $XWIKI_USERNAME -p $XWIKI_PASSWORD
|
||||
|
||||
#################################################
|
||||
# RPM
|
||||
#################################################
|
||||
|
||||
job-rocky9-rpm:
|
||||
extends:
|
||||
- .job-linux-rpm
|
||||
- .rocky9-image-variables
|
||||
needs:
|
||||
- job: job-rocky9-unit-test
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-rocky9-unit-test-nosoci
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-rocky9-ninja-clang
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-rocky9-ninja-clang-nosoci
|
||||
optional: true
|
||||
artifacts: false
|
||||
|
||||
# Test installation of the RPM package and check its feature list
|
||||
job-rocky9-rpm-check-features:
|
||||
stage: check-package 📤
|
||||
tags: [ "docker" ]
|
||||
extends:
|
||||
- .rocky9-image-variables
|
||||
rules:
|
||||
- !reference [job-rocky9-rpm, rules]
|
||||
needs:
|
||||
- job: job-rocky9-rpm
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- sudo yum -y --nogpgcheck localinstall ./build/*.rpm
|
||||
- !reference [.script-check-features, script]
|
||||
|
||||
job-rocky9-rpm-deploy:
|
||||
extends: .job-rpm-deploy
|
||||
dependencies:
|
||||
- job-rocky9-rpm
|
||||
variables:
|
||||
DISTRIB: rockylinux
|
77
.gitlab-ci-files/job-linux-ubuntu-22-04.yml
Normal file
77
.gitlab-ci-files/job-linux-ubuntu-22-04.yml
Normal file
|
@ -0,0 +1,77 @@
|
|||
.ubuntu-22-04-image:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-ubuntu-22-04:$UBUNTU_22_04_IMAGE_VERSION
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-ubuntu-22-04-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .ubuntu-22-04-image
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-gcc rules
|
||||
|
||||
|
||||
job-ubuntu-22-04-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .ubuntu-22-04-image
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-clang rules
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-ubuntu-22-04-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .ubuntu-22-04-image
|
||||
|
||||
|
||||
job-ubuntu-22-04-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .ubuntu-22-04-image
|
||||
- .tester-artifacts
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-ubuntu-22-04-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .ubuntu-22-04-image
|
||||
needs:
|
||||
- job-ubuntu-22-04-ninja-clang
|
||||
|
||||
#################################################
|
||||
# DEB
|
||||
#################################################
|
||||
|
||||
job-ubuntu-22-04-deb:
|
||||
extends:
|
||||
- .job-linux-deb
|
||||
- .ubuntu-22-04-image
|
||||
- .rules-manual-deploy # ⚠ See `rules.yml`, override .job-linux-deb rules
|
||||
needs:
|
||||
- job: job-ubuntu-22-04-unit-test
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-ubuntu-22-04-ninja-clang
|
||||
optional: true
|
||||
artifacts: false
|
||||
|
||||
|
||||
job-ubuntu-22-04-deb-deploy:
|
||||
extends:
|
||||
- .job-debian-deb-deploy
|
||||
- .ubuntu-22-04-image
|
||||
variables:
|
||||
RELEASE: jammy
|
||||
FREIGHT_PATH: $UBUNTU_FREIGHT_CONF_PATH
|
||||
dependencies:
|
||||
- job-ubuntu-22-04-deb
|
77
.gitlab-ci-files/job-linux-ubuntu-24-04.yml
Normal file
77
.gitlab-ci-files/job-linux-ubuntu-24-04.yml
Normal file
|
@ -0,0 +1,77 @@
|
|||
.ubuntu-24-04-image:
|
||||
image:
|
||||
name: gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-ubuntu-24-04:$UBUNTU_24_04_IMAGE_VERSION
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-ubuntu-24-04-makefile-gcc:
|
||||
extends:
|
||||
- .job-makefile-gcc
|
||||
- .ubuntu-24-04-image
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-gcc rules
|
||||
|
||||
|
||||
job-ubuntu-24-04-makefile-clang:
|
||||
extends:
|
||||
- .job-makefile-clang
|
||||
- .ubuntu-24-04-image
|
||||
- .rules-never-run # ⚠ See `rules.yml`, override .job-makefile-clang rules
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-ubuntu-24-04-ninja-gcc:
|
||||
extends:
|
||||
- .job-ninja-gcc
|
||||
- .ubuntu-24-04-image
|
||||
|
||||
|
||||
job-ubuntu-24-04-ninja-clang:
|
||||
extends:
|
||||
- .job-ninja-clang
|
||||
- .ubuntu-24-04-image
|
||||
- .tester-artifacts
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON
|
||||
|
||||
#################################################
|
||||
# UNIT TESTS
|
||||
#################################################
|
||||
|
||||
job-ubuntu-24-04-unit-test:
|
||||
extends:
|
||||
- .unit-test
|
||||
- .ubuntu-24-04-image
|
||||
needs:
|
||||
- job-ubuntu-24-04-ninja-clang
|
||||
|
||||
#################################################
|
||||
# DEB
|
||||
#################################################
|
||||
|
||||
job-ubuntu-24-04-deb:
|
||||
extends:
|
||||
- .job-linux-deb
|
||||
- .ubuntu-24-04-image
|
||||
- .rules-manual-deploy # ⚠ See `rules.yml`, override .job-linux-deb rules
|
||||
needs:
|
||||
- job: job-ubuntu-24-04-unit-test
|
||||
optional: true
|
||||
artifacts: false
|
||||
- job: job-ubuntu-24-04-ninja-clang
|
||||
optional: true
|
||||
artifacts: false
|
||||
|
||||
|
||||
job-ubuntu-24-04-deb-deploy:
|
||||
extends:
|
||||
- .job-debian-deb-deploy
|
||||
- .ubuntu-24-04-image
|
||||
variables:
|
||||
RELEASE: noble
|
||||
FREIGHT_PATH: $UBUNTU_FREIGHT_CONF_PATH
|
||||
dependencies:
|
||||
- job-ubuntu-24-04-deb
|
413
.gitlab-ci-files/job-linux.yml
Normal file
413
.gitlab-ci-files/job-linux.yml
Normal file
|
@ -0,0 +1,413 @@
|
|||
#################################################
|
||||
# Global
|
||||
#################################################
|
||||
|
||||
.set-max-jobs: &set-max-jobs
|
||||
- |
|
||||
case "$CMAKE_GENERATOR" in
|
||||
'Unix Makefiles')
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=$MAKEFILE_JOBS ;;
|
||||
'Ninja')
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=$NINJA_JOBS ;;
|
||||
*)
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=1 ;;
|
||||
esac
|
||||
echo "CMAKE_BUILD_PARALLEL_LEVEL='$CMAKE_BUILD_PARALLEL_LEVEL'"
|
||||
|
||||
|
||||
.linux-ccache:
|
||||
cache:
|
||||
key: $CI_JOB_NAME
|
||||
paths:
|
||||
- ccache/
|
||||
before_script:
|
||||
- git submodule foreach --recursive git fetch --tags --force
|
||||
- "[[ -f /opt/rh/devtoolset-8/enable ]] && source /opt/rh/devtoolset-8/enable"
|
||||
- mkdir -p ccache
|
||||
- echo "max_size = $CCACHE_SIZE" > ccache/ccache.conf
|
||||
- export CCACHE_BASEDIR=${PWD}
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
- ccache -s
|
||||
after_script:
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
- ccache -s
|
||||
|
||||
|
||||
.job-linux-build:
|
||||
stage: build 🏗
|
||||
tags: [ "docker" ]
|
||||
extends: .linux-ccache
|
||||
script:
|
||||
- *set-max-jobs
|
||||
- mkdir work && cd work
|
||||
- cmake -G "$CMAKE_GENERATOR" $DEFAULT_CMAKE_OPTIONS -DCMAKE_INSTALL_PREFIX="$PWD/../OUTPUT" $CMAKE_OPTIONS ..
|
||||
- cmake --build .
|
||||
|
||||
# Files required by the flexisip_tester bin
|
||||
.tester-artifacts:
|
||||
artifacts:
|
||||
paths:
|
||||
- work/bin/flexisip_tester
|
||||
- work/lib{,64}/
|
||||
- "**grammar"
|
||||
- tester/cert
|
||||
- tester/config
|
||||
- tester/images
|
||||
- tester/scripts
|
||||
- tester/sounds
|
||||
|
||||
#################################################
|
||||
# RPM
|
||||
#################################################
|
||||
|
||||
.job-linux-rpm:
|
||||
stage: package 📦
|
||||
tags: [ "docker" ]
|
||||
extends:
|
||||
- .rules-default # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: 'Ninja'
|
||||
script:
|
||||
- "[[ -f /opt/rh/devtoolset-8/enable ]] && source /opt/rh/devtoolset-8/enable"
|
||||
- *set-max-jobs
|
||||
- mkdir build && cd build
|
||||
- cmake -G $CMAKE_GENERATOR $DEFAULT_PACKAGING_CMAKE_OPTIONS $CMAKE_OPTIONS -DCPACK_GENERATOR=RPM ..
|
||||
- cmake --build . --target package
|
||||
artifacts:
|
||||
paths:
|
||||
- build/*.rpm
|
||||
- .gitlab-ci-files/deploy.sh
|
||||
when: always
|
||||
expire_in: 1 week
|
||||
|
||||
.job-rpm-deploy:
|
||||
stage: deploy 🚀
|
||||
tags: [ "deploy" ]
|
||||
extends: .rules-deploy # ⚠ See `rules.yml`
|
||||
variables:
|
||||
# Do not clone, only use artifacts (TODO 'none' doesn't clean, we are using 'fetch' until we find a way)
|
||||
GIT_STRATEGY: fetch
|
||||
script: ./.gitlab-ci-files/deploy.sh ${DISTRIB}
|
||||
|
||||
#################################################
|
||||
# DEB
|
||||
#################################################
|
||||
|
||||
.job-linux-deb:
|
||||
stage: package 📦
|
||||
tags: [ "docker" ]
|
||||
extends:
|
||||
- .rules-default # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: 'Ninja'
|
||||
script:
|
||||
- *set-max-jobs
|
||||
- mkdir build && cd build
|
||||
- cmake -G $CMAKE_GENERATOR $DEFAULT_PACKAGING_CMAKE_OPTIONS $CMAKE_OPTIONS -DCPACK_GENERATOR=DEB ..
|
||||
- cmake --build . --target package
|
||||
artifacts:
|
||||
paths:
|
||||
- build/*.deb
|
||||
- build/*.ddeb
|
||||
when: always
|
||||
expire_in: 1 week
|
||||
|
||||
|
||||
.job-debian-deb-deploy:
|
||||
stage: deploy 🚀
|
||||
tags: [ "deploy" ]
|
||||
extends: .rules-deploy # ⚠ See `rules.yml`
|
||||
variables:
|
||||
# Do not clone, only use artifacts (TODO 'none' doesn't clean, we are using 'fetch' until we find a way)
|
||||
GIT_STRATEGY: fetch
|
||||
script: ./.gitlab-ci-files/deploy.sh debian
|
||||
|
||||
#################################################
|
||||
# DOCKER
|
||||
#################################################
|
||||
|
||||
.job-flexisip-image-deploy:
|
||||
stage: image
|
||||
tags: [ "linux-deploy" ]
|
||||
extends: .rules-deploy # ⚠ See `rules.yml`
|
||||
script:
|
||||
- mkdir -p docker/DEBS && mv build/*.{deb,ddeb} docker/DEBS
|
||||
- cd docker
|
||||
- make flexisip-deb-build
|
||||
- make flexisip-deb-push
|
||||
|
||||
# Enable this to use tests-flexisip-mr
|
||||
#docker-build-flexisip-src:
|
||||
# stage: build 🏗
|
||||
# tags: [ "linux-nuc-build" ]
|
||||
# extends: .rules-dev # ⚠ See `rules.yml`
|
||||
# variables:
|
||||
# DOCKER_BUILD_OPTIONS: "--no-cache --force-rm -t flexisip-from-src:$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHA -f docker/flex-from-src --build-arg=njobs=12 --build-arg=build_type=RelWithDebInfo"
|
||||
# script:
|
||||
# - docker image ls
|
||||
# - echo $DOCKER_BUILD_OPTIONS
|
||||
# - docker build $DOCKER_BUILD_OPTIONS .
|
||||
# - docker image ls
|
||||
|
||||
#################################################
|
||||
# Nightly only
|
||||
#################################################
|
||||
|
||||
.job-linux-build-nightly:
|
||||
extends:
|
||||
- .job-linux-build
|
||||
- .rules-nightly # ⚠ See `rules.yml`
|
||||
|
||||
#################################################
|
||||
# Build Makefile
|
||||
#################################################
|
||||
|
||||
.job-makefile-gcc:
|
||||
extends: .job-linux-build-nightly
|
||||
variables:
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
|
||||
|
||||
.job-makefile-clang:
|
||||
extends: .job-linux-build-nightly
|
||||
variables:
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
||||
#################################################
|
||||
# Build Ninja
|
||||
#################################################
|
||||
|
||||
.job-ninja-gcc:
|
||||
extends:
|
||||
- .job-linux-build
|
||||
- .rules-manual # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
|
||||
|
||||
.job-ninja-clang:
|
||||
extends:
|
||||
- .job-linux-build
|
||||
- .rules-dev # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
||||
#################################################
|
||||
# Tests
|
||||
#################################################
|
||||
|
||||
.unit-test:
|
||||
stage: test 🧪
|
||||
tags: [ "docker-test-flexisip" ]
|
||||
extends: .rules-dev # ⚠ See `rules.yml`
|
||||
variables:
|
||||
# Do not clone, only use artifacts (TODO 'none' doesn't clean, we are using 'fetch' until we find a way)
|
||||
GIT_STRATEGY: fetch
|
||||
script:
|
||||
- export LD_LIBRARY_PATH=/usr/local/lib
|
||||
- export LSAN_OPTIONS="suppressions=./sanitizer_ignore.txt"
|
||||
- ./work/bin/flexisip_tester --verbose --xml || exit $?
|
||||
artifacts:
|
||||
reports:
|
||||
junit:
|
||||
- BCUnitAutomated-Results.xml
|
||||
when: always
|
||||
expire_in: 1 week
|
||||
|
||||
# Disabled because of too much random test errors for a valid result for now.
|
||||
#
|
||||
# tests-flexisip-mr:
|
||||
# stage: test 🧪
|
||||
# tags: [ "linux-nuc"]
|
||||
# allow_failure: true
|
||||
# extends: .rules-dev # ⚠ See `rules.yml`
|
||||
# needs :
|
||||
# - docker-build-flexisip-src
|
||||
# variables:
|
||||
# #Branch of the Flexisip-tester project to use. Could be modified to test fixes or features in the Flexisip-tester
|
||||
# FLEXISIP_TESTER_BRANCH: "release/flexisip_2.2"
|
||||
#
|
||||
# #This value specifies the workspace where we from all tests outputs.
|
||||
# workspace: "${CI_PROJECT_DIR}/liblinphone_tester_workspace"
|
||||
#
|
||||
# #Flexisip docker image is build from source in the build stage (job docker-build-flexisip-src)
|
||||
# #No need to modify these value
|
||||
# FLEXISIP_DOCKER_TAG: "$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHA"
|
||||
#
|
||||
# # Docker run options are only used for coredump display if any
|
||||
# # We are forced to copy the same string as "workspace" because we can't use nested variables in the same place (i.e. in variable declaration)
|
||||
# docker_run_options: "-v ${CI_PROJECT_DIR}/liblinphone_tester_workspace:/home/bc/linphone-sdk-build/linphone-sdk/desktop/work"
|
||||
# flexisip_docker_run_options: "-v ${CI_PROJECT_DIR}/liblinphone_tester_workspace:/root"
|
||||
#
|
||||
# script:
|
||||
# # Retrieve the SDK commit sha used by Flexisip
|
||||
# - cd linphone-sdk
|
||||
# - export LIBLINPHONE_DOCKER_TAG=$(git rev-parse --verify HEAD)
|
||||
# - echo "SDK commit sha " $LIBLINPHONE_DOCKER_TAG
|
||||
# - cd ..
|
||||
#
|
||||
# # used to ensure there will be not network name conflict for parallel
|
||||
# # docker-compose executions
|
||||
# - export COMPOSE_PROJECT_NAME=$RANDOM
|
||||
# - echo "Compose project name " $COMPOSE_PROJECT_NAME
|
||||
#
|
||||
# - export FLEXISIP_TESTER_IPV4_PREFIX="172.0.`expr $COMPOSE_PROJECT_NAME % 255`"
|
||||
# - echo "Flexisip tester private ipv4 prefix " $FLEXISIP_TESTER_IPV4_PREFIX
|
||||
#
|
||||
# - export FLEXISIP_TESTER_IPV6_SUBNET="2001:3200:3200:`printf '%x\n' $COMPOSE_PROJECT_NAME`::/64"
|
||||
# - echo "Flexisip tester private ipv6 subnet " $FLEXISIP_TESTER_IPV6_SUBNET
|
||||
#
|
||||
# - export FLEXISIP_TESTER_IPV6_GATEWAY="2001:3200:3200:`printf '%x\n' $COMPOSE_PROJECT_NAME`::1"
|
||||
# - export FLEXISIP_TESTER_IPV6_PROBING_ADDR=$FLEXISIP_TESTER_IPV6_GATEWAY
|
||||
# - echo "Flexisip tester private ipv6 gateway" $FLEXISIP_TESTER_IPV6_GATEWAY
|
||||
#
|
||||
# - echo "Liblinphone tester version:" $LIBLINPHONE_DOCKER_TAG
|
||||
# - echo $workspace
|
||||
#
|
||||
# - git clone -b $FLEXISIP_TESTER_BRANCH --single-branch git@gitlab.linphone.org:BC/private/flexisip-tester --jobs 12
|
||||
#
|
||||
# #We make sure that the variables we set here can be accessed by the docker-compose scripts (in the flexisip-tester project).
|
||||
# - export FLEXISIP_DOCKER_TAG="$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHA"
|
||||
# - export LIBLINPHONE_DOCKER_TAG=$LIBLINPHONE_DOCKER_TAG
|
||||
#
|
||||
# - |
|
||||
# if [ -z $workspace ]; then
|
||||
# echo "Error, $workspace should be set. Aborting to avoid unwanted rm"
|
||||
# exit 1
|
||||
# fi
|
||||
#
|
||||
# - mkdir -p $workspace
|
||||
# - rm -rf $workspace/*
|
||||
#
|
||||
# - mkdir -p $workspace/{bin,flexiapi,ext,lime,lime-ext}
|
||||
#
|
||||
# # workaround for logs writing
|
||||
# - chmod -R 777 $workspace
|
||||
#
|
||||
# # Handle multiple runs by unsetting variable
|
||||
# # Overriding docker-compose.yaml values with docker-compose-standalone.yaml
|
||||
# # in the ways specified with docker docs (either OR or AND, depending on key)
|
||||
#
|
||||
# - |
|
||||
# docker_compose_options="--env-file ${CI_PROJECT_DIR}/flexisip-tester/docker/.env"
|
||||
# for name in 'docker-compose.yaml' 'docker-compose-standalone.yaml'; do
|
||||
# docker_compose_options="$docker_compose_options -f ${CI_PROJECT_DIR}/flexisip-tester/docker/$name"
|
||||
# done
|
||||
#
|
||||
# #Tester's options like parallel mode are defined in the docker-compose-standalone.yaml file of the flexisip-tester project
|
||||
#
|
||||
# - export FLEXISIP_LOGS="$workspace"
|
||||
# - export LIBLINPHONE_LOGS="$workspace"
|
||||
#
|
||||
# - export FLEXISIP_WORKSPACE="$workspace"
|
||||
#
|
||||
# - echo $docker_run_options
|
||||
#
|
||||
# - cd $workspace
|
||||
#
|
||||
# # Stop and remove containers, networks and volumes from previous tests.
|
||||
# # Already done after tests, should do nothing except if previous job crashed.
|
||||
# - docker-compose $docker_compose_options down --volumes --remove-orphans
|
||||
#
|
||||
# - echo "COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME" > savedEnv
|
||||
#
|
||||
# # commented -d option to have debug logs on standard output in case of
|
||||
# # buggy or silent log artifacts
|
||||
# # We output only liblinphone_tester on stdout
|
||||
#
|
||||
# #-V, --renew-anon-volumes Recreate anonymous volumes instead of retrieving data from the previous containers.
|
||||
# #--exit-code-from Exits with the return code from the specified container (implies --abort-on-container-exit)
|
||||
# #In the grep we are searching only for the logs related to liblinphone_tester and docker build, so we remove output from all other services.
|
||||
#
|
||||
# - docker-compose $docker_compose_options up --build -V --exit-code-from liblinphone_tester |& tee logs_all | grep -vE 'redis_server[_-]1|flexisip[_-]1|flexisip-regevent[_-]1|flexisip-external[_-]1|flexisip-external-domain[_-]1|lime-server[_-]1|lime-server[_-]1|lime-external-server[_-]1|dbserver[_-]1|account-manager[_-]1|file-transfer-server[_-]1|http-proxy[_-]1|ldap-server[_-]1' || EXIT=$?
|
||||
#
|
||||
# #docker-compose log command isn't used anymore because of bad performance
|
||||
# #the logs were converted by docker in json format, then reconverted to txt, which is useless (doing this made the job last for 20-30 minutes for 9 minutes of tests)
|
||||
#
|
||||
# - |
|
||||
# for service in $(docker-compose $docker_compose_options ps --services); do
|
||||
# if [[ "${service}" == "flexisip" ]]; then
|
||||
# continue
|
||||
# fi
|
||||
# filename="${service}_stdout.log"
|
||||
# echo -n "Writting ${filename}..."
|
||||
# grep $service logs_all >> ${filename}.log
|
||||
# echo " done"
|
||||
# done
|
||||
#
|
||||
# #we wait for each grep to end before stopping containers
|
||||
# - wait
|
||||
#
|
||||
# # The sleep command was removed because we now wait for the db socket to open (in compose file) before launching tests
|
||||
#
|
||||
# # Stop and remove containers, networks and volumes from previous tests
|
||||
# - docker-compose $docker_compose_options down --volumes --remove-orphans || true
|
||||
#
|
||||
# - gzip *.log
|
||||
#
|
||||
# - gzip */*.log
|
||||
#
|
||||
# - exit $EXIT
|
||||
#
|
||||
# after_script:
|
||||
#
|
||||
# #content of $workspace (set like this because the variable can't be resolved here)
|
||||
# - cd ${CI_PROJECT_DIR}/liblinphone_tester_workspace
|
||||
# # we specify commands to launch for each coredump of liblinphone_tester
|
||||
# - echo "set debug-file-directory ../lib64" | tee gdb_options
|
||||
# - echo "thread apply all bt" | tee -a gdb_options
|
||||
# # searching for core files and if there are some, launch gdb on all of it
|
||||
# # xargs -L1 means that the command in argument will be executed for each
|
||||
# # line (core dump) found in find output
|
||||
# # The docker syntax is error proning : to override the entrypoint with
|
||||
# # args, we enter the entrypoint first, then the name of the image, then the
|
||||
# # args to the entrypoint command.
|
||||
# # "|| true " is used here to continue the script even if the find fails
|
||||
# - FIND_EXIT=0
|
||||
# - find . -type f -name "core.liblin*" | grep . || FIND_EXIT=$?
|
||||
# - echo $FIND_EXIT
|
||||
# - if [[ $FIND_EXIT = 0 ]]; then find . -type f -name "core.liblin*" | xargs -L1 docker run $docker_run_options --entrypoint gdb "$LIBLINPHONE_DOCKER_IMAGE:$LIBLINPHONE_DOCKER_TAG" ../bin/liblinphone_tester -x gdb_options; fi || true
|
||||
# - unset FIND_EXIT
|
||||
# # we specify commands to launch for each coredump of flexisip_tester
|
||||
# - echo "set debug-file-directory /opt/belledonne-communications/lib" | tee gdb_options
|
||||
# - echo "thread apply all bt" | tee -a gdb_options
|
||||
# - echo $flexisip_docker_run_options
|
||||
# - find . -type f -name "core.flexisip*"
|
||||
# - echo $FLEXISIP_DOCKER_IMAGE
|
||||
# - echo $FLEXISIP_DOCKER_TAG
|
||||
# - echo $flexisip_docker_run_options
|
||||
# - FIND_EXIT=0
|
||||
# - find . -type f -name "core.flexisip*" | grep . || FIND_EXIT=$?
|
||||
# - echo $FIND_EXIT
|
||||
# - if [[ $FIND_EXIT = 0 ]]; then find . -type f -name "core.flexisip*" | xargs -L1 docker run $flexisip_docker_run_options --entrypoint gdb "$FLEXISIP_DOCKER_IMAGE:$FLEXISIP_DOCKER_TAG" /opt/belledonne-communications/bin/flexisip -x gdb_options; fi || true
|
||||
#
|
||||
# # simplifing artifacts browsing
|
||||
# # Moving artifacts to ease browsing from web view
|
||||
# # initially, all the paths needed to be browsed entirely to see artifacts
|
||||
# # now there is only the folder "results" to check
|
||||
# - mkdir -p ${CI_PROJECT_DIR}/results/ext
|
||||
# - chmod 777 ${CI_PROJECT_DIR}/results
|
||||
# - cp -r BCUnitAutomated* ${CI_PROJECT_DIR}/results
|
||||
# - cp -r *.log.gz ${CI_PROJECT_DIR}/results
|
||||
# - cp -r ext/*.log* ${CI_PROJECT_DIR}/results/ext
|
||||
#
|
||||
# # Remove network (useful in case of crash or cancel), loading the random generated project name saved during execution
|
||||
# - source savedEnv
|
||||
# - docker network rm "$COMPOSE_PROJECT_NAME"_default "$COMPOSE_PROJECT_NAME"_flexisip_internal_private || true
|
||||
#
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - results/*
|
||||
# when: always
|
||||
# reports:
|
||||
# junit:
|
||||
# - liblinphone_tester_workspace/BCUnitAutomated-Results.xml
|
||||
# expire_in: 4 week
|
55
.gitlab-ci-files/job-macosx.yml
Normal file
55
.gitlab-ci-files/job-macosx.yml
Normal file
|
@ -0,0 +1,55 @@
|
|||
.job-macosx:
|
||||
stage: build 🏗
|
||||
tags: [ "macosx-min-xcode12.2" ]
|
||||
|
||||
# Temporarily allows macosx jobs to fail because the machine that
|
||||
# was executing the macOS jobs is broken. Remove when it is
|
||||
# fixed.
|
||||
allow_failure: true
|
||||
|
||||
script:
|
||||
- ccache -s
|
||||
- export OPENSSL_ROOT_DIR=/usr/local/opt/openssl
|
||||
- export MYSQL_DIR=/usr/local/opt/mysql-client
|
||||
- export CMAKE_BUILD_PARALLEL_LEVEL=$NJOBS
|
||||
- mkdir work
|
||||
- cmake -S . -B work -G "$CMAKE_GENERATOR" $DEFAULT_MACOS_CMAKE_OPTIONS $CMAKE_OPTIONS -DCMAKE_PREFIX_PATH=/usr/local/opt/mbedtls@2 -DENABLE_SOCI_POSTGRESQL_BACKEND=OFF -DENABLE_UNIT_TESTS=ON -DENABLE_UNIT_TESTS_NGHTTP2ASIO=OFF
|
||||
- cmake --build work -- $ADDITIONAL_BUILD_OPTIONS
|
||||
- ccache -s
|
||||
|
||||
|
||||
#################################################
|
||||
# Makefile
|
||||
#################################################
|
||||
|
||||
job-macosx-makefile:
|
||||
extends:
|
||||
- .job-macosx
|
||||
- .rules-nightly # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
NJOBS: $MAKEFILE_JOBS
|
||||
|
||||
#################################################
|
||||
# Ninja
|
||||
#################################################
|
||||
|
||||
job-macosx-ninja:
|
||||
extends:
|
||||
- .job-macosx
|
||||
- .rules-dev # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
NJOBS: $NINJA_JOBS
|
||||
|
||||
#################################################
|
||||
# Xcode
|
||||
#################################################
|
||||
|
||||
job-macosx-xcode:
|
||||
extends:
|
||||
- .job-macosx
|
||||
- .rules-nightly # ⚠ See `rules.yml`
|
||||
variables:
|
||||
CMAKE_GENERATOR: Xcode
|
||||
NJOBS: $MAX_NUMBER_TASK_XCODE
|
83
.gitlab-ci-files/rules.yml
Normal file
83
.gitlab-ci-files/rules.yml
Normal file
|
@ -0,0 +1,83 @@
|
|||
# https://docs.gitlab.com/ee/ci/yaml/index.html#rules
|
||||
#
|
||||
# All `rules` should be gathered in this file.
|
||||
#
|
||||
# Gitlab lets us merge job definitions through inheritance with the `extends` section.
|
||||
# However, if two jobs merged in this fashion define the same section (e.g. `rules`) the sections themselves will not be
|
||||
# merged: the last will override the first. In the case of arrays (like `scripts` or `rules`) this is a problem,
|
||||
# because we usually would like to merge them, but there is no mechanism to do so.
|
||||
#
|
||||
# A workaround is to use YAML anchors (`&` and `*`) to reuse previously defined `rules` items, and ease refactoring.
|
||||
# However, YAML anchors only work within the same file (so not across Gitlab `include` boundaries).
|
||||
# Hence: this file.
|
||||
#
|
||||
# Every time you need a new set of `rules` for a job, you SHOULD define it here, reusing other `rules` items as
|
||||
# building blocks, then use `extends` to apply it to your job.
|
||||
# (This is to ease maintenance, as rules can then be changed quickly in one place.)
|
||||
#
|
||||
# You SHOULD NOT write `rules` outside this file. (This is to ease debugging, because, as explained above, `rules` can
|
||||
# override one another in an inheritance tree. This is not a strict rule however, and can be bypassed when justified.)
|
||||
#
|
||||
# This file MUST only contain hidden jobs (beginning with `.`) and these jobs MUST only contain a `rules` section
|
||||
|
||||
# Jobs that always run with the default gitlab policy
|
||||
.rules-default:
|
||||
rules:
|
||||
- &manual-override
|
||||
if: $MANUAL_OVERRIDE
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- &otherwise-run # Default gitlab policy that we have to explicitely add back
|
||||
when: on_success
|
||||
|
||||
# Jobs that always run, except for DEPLOY_ONLY pipelines.
|
||||
.rules-dev:
|
||||
rules:
|
||||
- *manual-override
|
||||
- &exclude-from-deploy
|
||||
if: $DEPLOY_ONLY
|
||||
when: never
|
||||
- *otherwise-run
|
||||
|
||||
# Jobs that only run in NIGHTLY pipelines
|
||||
.rules-nightly:
|
||||
rules:
|
||||
- *manual-override
|
||||
- if: '$NIGHTLY == null'
|
||||
when: never
|
||||
- *exclude-from-deploy
|
||||
- *otherwise-run
|
||||
|
||||
# Jobs that run in NIGHTLY pipelines, are added in manual mode to all pipelines, except for DEPLOY_ONLY ones.
|
||||
.rules-manual:
|
||||
rules:
|
||||
- *exclude-from-deploy
|
||||
- if: '$NIGHTLY != null'
|
||||
when: on_success
|
||||
- when: manual
|
||||
allow_failure: true # This allows pipeline to continue without blocking on only manual jobs.
|
||||
|
||||
# Jobs that run in NIGHTLY pipelines, are added in manual mode to all pipelines.
|
||||
.rules-manual-deploy:
|
||||
rules:
|
||||
- if: '$NIGHTLY != null'
|
||||
when: on_success
|
||||
- when: manual
|
||||
allow_failure: true # This allows pipeline to continue without blocking on only manual jobs.
|
||||
|
||||
# Jobs that run only for DEPLOY or DEPLOY_ONLY pipelines.
|
||||
.rules-deploy:
|
||||
rules:
|
||||
- *manual-override
|
||||
- if: $DEPLOY
|
||||
when: on_success
|
||||
- if: $DEPLOY_ONLY
|
||||
when: on_success
|
||||
- when: never
|
||||
|
||||
# Use this rule when you don't want a job to be run but still want to make it easily available by removing this rule.
|
||||
# e.g. when you are adding a new platform or upgrading an existing one, and you want to run thorough tests
|
||||
.rules-never-run:
|
||||
rules:
|
||||
- *manual-override
|
||||
- when: never
|
16
.gitlab-ci-files/scripts.yml
Normal file
16
.gitlab-ci-files/scripts.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
# This file MUST only contain hidden jobs (beginning with `.`)
|
||||
|
||||
# Check available features of an installed flexisip binary
|
||||
.script-check-features:
|
||||
script:
|
||||
- FLEXISIP_BIN=/opt/belledonne-communications/bin/flexisip
|
||||
- VERSION_STRING=$($FLEXISIP_BIN --version)
|
||||
- echo $VERSION_STRING | grep B2BUA
|
||||
- echo $VERSION_STRING | grep Conference
|
||||
- echo $VERSION_STRING | grep Presence
|
||||
- echo $VERSION_STRING | grep Redis
|
||||
- echo $VERSION_STRING | grep RegEvent
|
||||
- echo $VERSION_STRING | grep Transcoder
|
||||
- echo $VERSION_STRING | grep Soci
|
||||
# No graphical dependencies
|
||||
- "! ldd $FLEXISIP_BIN | grep --extended-regexp 'X|GL'"
|
67
.gitlab-ci.yml
Normal file
67
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
#################################################
|
||||
# Base configuration
|
||||
#################################################
|
||||
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
GIT_SUBMODULE_UPDATE_FLAGS: --jobs 8
|
||||
|
||||
CCACHE_SIZE: 2G
|
||||
|
||||
# For build and test on Linux
|
||||
DEFAULT_CMAKE_OPTIONS: '-DCMAKE_BUILD_TYPE=Debug'
|
||||
# For build on MacOS
|
||||
DEFAULT_MACOS_CMAKE_OPTIONS: ''
|
||||
# For packaging, deb and rpm
|
||||
DEFAULT_PACKAGING_CMAKE_OPTIONS: '-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/opt/belledonne-communications -DSYSCONF_INSTALL_DIR=/etc -DFLEXISIP_SYSTEMD_INSTALL_DIR=/usr/lib/systemd/system'
|
||||
|
||||
# Docker image version
|
||||
ARCHLINUX_IMAGE_VERSION: 20250127_update_clang
|
||||
ROCKY_8_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
ROCKY_9_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
DEBIAN_10_IMAGE_VERSION: 220240911_remove_protobuf
|
||||
DEBIAN_11_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
DEBIAN_12_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
MINIMAL_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
UBUNTU_22_04_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
UBUNTU_24_04_IMAGE_VERSION: 20240911_remove_protobuf
|
||||
|
||||
#https://docs.gitlab.com/ee/ci/yaml/index.html#workflow
|
||||
workflow:
|
||||
rules:
|
||||
# Allow merge request pipelines
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TITLE !~ /^Draft:.*/
|
||||
# Allow scheduled pipelines
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
|
||||
before_script:
|
||||
- |
|
||||
if [ "$GIT_STRATEGY" != "none" ]; then
|
||||
git submodule foreach --recursive git fetch --tags --force
|
||||
fi
|
||||
|
||||
#################################################
|
||||
# Platforms to test
|
||||
#################################################
|
||||
|
||||
include:
|
||||
- '.gitlab-ci-files/rules.yml'
|
||||
- '.gitlab-ci-files/scripts.yml'
|
||||
- '.gitlab-ci-files/job-linux.yml'
|
||||
- '.gitlab-ci-files/job-linux-archlinux.yml'
|
||||
- '.gitlab-ci-files/job-linux-rocky8.yml'
|
||||
- '.gitlab-ci-files/job-linux-rocky9.yml'
|
||||
- '.gitlab-ci-files/job-linux-debian11.yml'
|
||||
- '.gitlab-ci-files/job-linux-debian12.yml'
|
||||
- '.gitlab-ci-files/job-linux-minimal.yml'
|
||||
- '.gitlab-ci-files/job-linux-ubuntu-22-04.yml'
|
||||
- '.gitlab-ci-files/job-linux-ubuntu-24-04.yml'
|
||||
- '.gitlab-ci-files/job-macosx.yml'
|
||||
|
||||
stages:
|
||||
- build 🏗
|
||||
- test 🧪
|
||||
- coverage 📑
|
||||
- package 📦
|
||||
- check-package 📤
|
||||
- deploy 🚀
|
15
.gitmodules
vendored
Normal file
15
.gitmodules
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
[submodule "submodules/externals/sofia-sip"]
|
||||
path = submodules/externals/sofia-sip
|
||||
url = https://gitlab.linphone.org/BC/public/external/sofia-sip.git
|
||||
[submodule "submodules/externals/hiredis"]
|
||||
path = submodules/externals/hiredis
|
||||
url = https://gitlab.linphone.org/BC/public/external/hiredis.git
|
||||
[submodule "submodules/externals/jansson"]
|
||||
path = submodules/externals/jansson
|
||||
url = https://gitlab.linphone.org/BC/public/external/jansson.git
|
||||
[submodule "submodules/externals/jose"]
|
||||
path = submodules/externals/jose
|
||||
url = https://gitlab.linphone.org/BC/public/external/jose.git
|
||||
[submodule "linphone-sdk"]
|
||||
path = linphone-sdk
|
||||
url = https://gitlab.linphone.org/BC/public/linphone-sdk.git
|
27
.project
Normal file
27
.project
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>flexisip</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
12
AUTHORS
Normal file
12
AUTHORS
Normal file
|
@ -0,0 +1,12 @@
|
|||
Copyright Belledonne Communications SARL, all rights reserved.
|
||||
|
||||
Authors:
|
||||
Simon Morlat
|
||||
Guillaume Beraudo
|
||||
Jehan Monnier
|
||||
Guillaume Bienkoswki
|
||||
Sylvain Berfini
|
||||
Margaux Clerc
|
||||
Ghislain Mary
|
||||
Gautier Pelloux-Prayer
|
||||
Yann Diorcet
|
664
CHANGELOG.md
Normal file
664
CHANGELOG.md
Normal file
|
@ -0,0 +1,664 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
Group changes to describe their impact on the project, as follows:
|
||||
|
||||
| **Group name** | **Description** |
|
||||
|----------------|-----------------------------------------------------------------------------|
|
||||
| Added | New features |
|
||||
| Changed | Changes in existing functionality |
|
||||
| Deprecated | Once-stable features removed in upcoming releases |
|
||||
| Removed | Deprecated features removed in this release |
|
||||
| Fixed | Any bug fixes |
|
||||
| Security | To invite users to upgrade in case of vulnerabilities |
|
||||
| Known Issues | Issues whose fix has not been tested and cannot be included in this release |
|
||||
|
||||
## [2.4.1]
|
||||
### [Added]
|
||||
- **B2BUA, Conference, Presence, Proxy, RegEvent:** periodically log the server memory usage (on Linux and with debug
|
||||
log level).
|
||||
|
||||
### [Fixed]
|
||||
- **B2BUA, Conference, Presence, Proxy, RegEvent:** error in Flexisip startup phase (daemon mode) caused the watchdog process to freeze
|
||||
- **RegEvent:** server did not support several subscriptions to the same record key
|
||||
- **RegEvent:** not disabling call-logs and zrtp-secrets DBs caused crash at init
|
||||
- **Sofia-SIP:** idle-timeout was not set in TLS connections if no message was received
|
||||
- **Proxy:** invalid P-Preferred-Identity could lead to crash
|
||||
- **B2BUA, Conference, Presence, Proxy, RegEvent:** watchdog logs could not be printed into journald
|
||||
- **Conference server:** compatibility issue between conference server using linphone-SDK 5.3 and clients using linphone-SDK 5.4.
|
||||
- **Proxy:** drastically improved performances when retrieving undelivered chat messages from the database at startup.
|
||||
|
||||
## [2.4.0] - 2025-01-30
|
||||
### [Added]
|
||||
- **B2BUA server/SIP Bridge:**
|
||||
- Now supports bridging **incoming** (external) calls.
|
||||
I.e. calls from clients registered on third-party domains/proxies to clients registered on the local domain/proxies.
|
||||
This requires a corresponding external account for each user.
|
||||
Please refer to [the SIP Bridge documentation] for details.
|
||||
- [`one-connection-per-account`](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/A.%20Configuration%20Reference%20Guide/2.4.0/b2bua-server#HB2buaserver):
|
||||
Let the B2BUA use a separate connection (port) for each (external) account it manages. This can be used to work around DoS protection and rate-limiting systems on external proxies.
|
||||
- **Proxy/Router:** new parameter `module::Router/static-targets` that lists sip addresses which will always be added to
|
||||
the list of contacts fetched from the registrar database when routing INVITE and MESSAGE requests.
|
||||
- **Proxy/NatHelper:** new strategy to route requests through NATs called
|
||||
"flow-token" ([RFC5626](https://datatracker.ietf.org/doc/html/rfc5626))
|
||||
- new parameter `module::NatHelper/nat-traversal-strategy` to indicate the strategy to use for routing requests
|
||||
through NATs (`contact-correction` or `flow-token`).
|
||||
- new parameter `module::NatHelper/force-flow-token` to force the use of flow-token under specific conditions (
|
||||
boolean expression).
|
||||
- **Configuration:** you can now indicate a unit (ms, s, min, h, d, m, y) along with the value for a duration
|
||||
parameter in the configuration file.
|
||||
See [File Syntax](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/Configuration/#HFilesyntax) for more
|
||||
information.
|
||||
- **Registrar:** Keep-alive Redis requests for subscription connections.
|
||||
Flexisip can now be more robust to middle-ware aggressively dropping idle connections.
|
||||
- **Conference and B2BUA servers:** new
|
||||
parameters `b2bua-server/audio-port`, `b2bua-server/video-port`, `conference-server/audio-port`
|
||||
and `conference-server/video-port` to specify which port (or range of ports) to use for RTP and RTCP traffic.
|
||||
- **Conference server:**
|
||||
- new parameter `conference-server/call-timeout` to kill all incoming calls that last longer than
|
||||
the defined value.
|
||||
- compatibility with clients using Linphone SDK 5.4.
|
||||
- **Build:**
|
||||
- Support for Ubuntu 24.04.
|
||||
- Support for Clang 18.
|
||||
- Support for GCC 14.
|
||||
- **Pusher:**
|
||||
- Clearer message when Apple Push Notification Service (APNS) certificates are not read accessible.
|
||||
- `--call-id` option to customise the content of the push notification payload
|
||||
|
||||
### [Fixed]
|
||||
- **B2BUA, Conference, Linphone Daemon, Presence, Proxy, RegEvent:** All associated SystemD services now properly wait for the network to be online before starting.
|
||||
(Fixes interface binding issues on boot.)
|
||||
- **Proxy:**
|
||||
- **NatHelper:** `module::NatHelper/contact-correction-param` is now properly removed from the `Contact` URI by the last hop in the proxy chain.
|
||||
- **RegistrarDb:** Failing to subscribe to a Redis Pub/Sub channel is now properly handled and logged, to help troubleshoot ACL issues in Redis' config.
|
||||
(Pub/Sub channels are used internally to trigger push notifications when devices register.)
|
||||
- **ForkCallContext:** Ringing devices now receive the appropriate "Accepted Elsewhere" status via push notifications when another device accepts the call in a multi-proxy configuration.
|
||||
- **Conference server:** Group chats no longer see their title overwritten to "ICE processing concluded" when the conference server's connection to Redis is slow or non-existant.
|
||||
- **RPM:** no longer breaks the Flexisip Account Manager (FAM) if it had been installed first. The SELinux `var_log_t` label is now properly applied to Flexisip's log files only.
|
||||
- **B2BUA server:** bridged calls put on hold (paused) using `a=inactive` can now be properly resumed.
|
||||
- **Sofia SIP:** Incoming messages exceeding the maximum acceptable size are now answered with a 400, and can no longer cause a congestion blocking a socket.
|
||||
- **CLI:** `REGISTRAR_DELETE` now properly deletes contacts identified by a `+sip.instance=` URI parameter.
|
||||
|
||||
### [Changed]
|
||||
- **B2BUA:**
|
||||
- The schema of the `b2bua-server::sip-bridge/providers` JSON configuration file has been overhauled to accommodate for the new incoming call bridging feature, and now offers many more configuration options.
|
||||
Please refer to [the SIP Bridge documentation] for details.
|
||||
- Custom header `flexisip-b2bua` is renamed to `X-Flexisip-B2BUA`.
|
||||
(This header is no longer used by the proxy which instead relies on the `User-Agent` header. However the B2BUA server still adds it to its messages for backwards compatibility.)
|
||||
- `b2bua-server/user-agent` can now include an optional `{version}` placeholder that will be replaced with the currently running Flexisip version.
|
||||
- **Build:** refactor of the build system to meet new CMake standards.
|
||||
- **Configuration:**
|
||||
- Flexisip will now refuse to launch if duplicated keys are found in the configuration file.
|
||||
(An explanatory message will be logged.)
|
||||
- Configuration values (anything to the right of an `=` sign in the config file) can now be 10x larger (up to 20KiB = 20480 ASCII characters), allowing for e.g. long and complex filter expressions.
|
||||
- **Proxy/PushNotification:** Invite/Cancel feature is now only used for Apple voip push notifications.
|
||||
- **Proxy/NatHelper:** parameter `module::NatHelper/contact-verified-param` is
|
||||
renamed `module::NatHelper/contact-correction-param`.
|
||||
- **Proxy/MediaRelay:** In early media mode, the ringing device that answered last is now the one sending audio/video.
|
||||
(Each new early media response takes over send capability.)
|
||||
- **Internal:**
|
||||
- Refactored software architecture (removed singletons) so you can now run several flexisip instances on
|
||||
the same machine.
|
||||
- Flexisip tester can now be used without the need for installation.
|
||||
- **EventLogs:** Event IDs are now generated with the SHA 256 algorithm to ensure reproducibility. (In lieu of C++'s `std::hash<string>`.)
|
||||
- **Logs:** Log messages from the Sofia SIP library are now only displayed if Flexisip is configured in `debug` logging level.
|
||||
A new config option `global/sofia-level`, has been added to tweak which messages are shown in that case.
|
||||
(This new option can be adjusted on a running instance via [the `CONFIG_SET` CLI command](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/3.%20Operate/Examining%20run-time%20statistics/#HAccessstatisticsandconfiguration))
|
||||
- **RPM:** The package now depends on `policycoreutils`, `policycoreutils-python-utils`, and `selinux-policy-targeted` to ensure its ability to set SELinux labels.
|
||||
- **CLI:** Improved messages around `REGISTRAR_*` commands.
|
||||
- **Pusher:** Added "Flexisip" to default push notification infos to make the origin of the PN clearer.
|
||||
|
||||
### [Deprecated]
|
||||
- **Windows push notifications:** these push notifications are not handled anymore.
|
||||
- parameter `module::PushNotification/windowsphone` no longer has any effect.
|
||||
- parameter `module::PushNotification/windowsphone-package-sid` no longer has any effect.
|
||||
- parameter `module::PushNotification/windowsphone-application-secret` no longer has any effect.
|
||||
- **Proxy/registrar:** parameter `module::Registrar/redis-server-timeout` no longer has any effect. This parameter is not
|
||||
really deprecated. It is not used for the moment but may be used in the future.
|
||||
- **Plugin:** The JweAuth plugin will be removed in Flexisip 2.5.
|
||||
|
||||
### [Removed]
|
||||
- **Ubuntu 18.04:** support discontinued as distribution has reached end-of-life (2023-05-31).
|
||||
- **CentOS 7:** support discontinued as distribution has reached end-of-life (2024-06-30).
|
||||
- **Debian 10:** support discontinued as distribution has reached end-of-life (2024-06-30).
|
||||
- **Proxy/Registrar:** `module::Registrar/redis-record-serializer` (deprecated in 2.0.0)
|
||||
- **Build:** `ENABLE_PROTOBUF` CMake option.
|
||||
This option only enabled a Protobuf backend for the serialization of records in Redis. It could no longer be used since the deprecation of the `redis-record-serializer` config option (see above).
|
||||
|
||||
### [Known Issues]
|
||||
- **Presence server:** Intermittent crash when updating the list of subscribers
|
||||
- **Sofia-SIP:**
|
||||
- Exponential memory usage when parsing data from a TCP socket.
|
||||
(A 5MB socket buffer can lead to 26GB of parsing buffers.)
|
||||
- Memory usage spike when the system clock jumps forward in time.
|
||||
(As can happen when NTP connection is (re-)established, leading to OOM in the worst case where e.g. the system clock inits at epoch (1970-01-01) because of a dead battery.)
|
||||
- **RPM:** Rocky 8 may refuse to install the package because it detects a conflict with the SystemD package.
|
||||
- **Proxy:** No "Missing call" notification will be sent if a call is cancelled after being unanswered for more than 30 seconds.
|
||||
|
||||
[the SIP Bridge documentation]: https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/Configuration/Back-to-back%20User%20Agent%20(b2bua)/SIP%20Bridge
|
||||
|
||||
## [2.3.4] - 2024-07-24
|
||||
### [Added]
|
||||
- **Proxy/Registrar:** add 'max-contacts-per-registration' to reject REGISTER requests containing more Contact headers
|
||||
than the specified limit.
|
||||
- **Dependencies:** added `python3-google-auth` and `python3-requests` to package dependencies.
|
||||
- **Build:** added CMake variable `FLEXISIP_VERSION` to enable build without GIT repository.
|
||||
|
||||
### [Changed]
|
||||
- **Build:** disabled default configuration file generation when crosscompiling.
|
||||
- **flexisip_cli.py:** API change, REGISTRAR_DELETE now returns an empty record instead of "Error 404" when deleting
|
||||
the last contact of a Record, OR when attempting to delete a contact from a non-existent Record.
|
||||
|
||||
### [Fixed]
|
||||
- **Proxy:** fix a crash when parsing an invalid "Contact" header value.
|
||||
- **Proxy/NatHelper:** fix wrong "Contact" header correction in response when the proxy is first and last hop.
|
||||
- **Configuration:** fix a crash when configuring an invalid boolean expression.
|
||||
- **Proxy/PushNotification:** fix missing "to-tag" parameter on "110 Push Sent" when `module::PushNotification` is
|
||||
enabled and filter parameter `module::PushNotification/add-to-tag-filter` evaluates to true.
|
||||
- **Proxy/Router:** fix no call is routed to callee when `module::Router/fork-late`
|
||||
and `module::Router/message-fork-late` are enabled.
|
||||
- **Proxy/PushNotification:** fix several issues on the new Firebase V1 push notifications client.
|
||||
- **Proxy/EventLogs:** fix wrong computation of event id. Previous method was sensitive to an inversion of "From"
|
||||
and "To" header values.
|
||||
- **B2BUA server:** fix behavior of the B2BUA. It was erroneously trying to resume a call that was paused with
|
||||
a=inactive in SDP.
|
||||
- **Proxy/Forward:** fix missing contact paths processing for mid-dialog requests intended to GRUU addresses. Fetched
|
||||
paths from database were not translated into Route headers before forwarding the request.
|
||||
- **Proxy/Router:** fix Proxy does not send terminal response in case of an early cancelled call
|
||||
when `module::Router/fork-late` is on. This case could happen when a client had an offline device and/or did not have
|
||||
the time to answer to the INVITE request before the CANCELED request (from the caller) arrived to the Proxy.
|
||||
|
||||
### [Deprecated]
|
||||
- **Proxy/EventLog:** parameter `event-logs/flexiapi-token` is renamed `event-logs/flexiapi-api-key`. It still works but
|
||||
deprecated, please use the new name.
|
||||
|
||||
## [2.3.3] - 2023-12-14
|
||||
### [Added]
|
||||
- **Presence:** last activity date is sent with long term presence.
|
||||
- **B2BUA server:** you can now force the usage of a specific video codec. See the `video-codec` config for more
|
||||
information.
|
||||
- **B2BUA server:** add a configurable time limit on calls and fix a bug where calls where limited to 30 minutes.
|
||||
See the `max-call-duration` config for more information.
|
||||
- **B2BUA server:** allow to use other transport protocol than TCP.
|
||||
- **B2BUA server:** you can now choose the User-Agent header for outgoing B2BUA request with the `user-agent` config.
|
||||
- **Proxy/push-notification:** you can now choose between a HTTP/1 or a HTTP/2 client for the generic push-notification
|
||||
service. See the `external-push-protocol` config for more information.
|
||||
- **[Experimental]** **Proxy/push-notification:** you can choose to use the new Firebase v1 API to send Android push
|
||||
notifications. See `firebase-service-accounts` config for more information. Use with caution, this feature is
|
||||
experimental.
|
||||
|
||||
### [Changed]
|
||||
- **Proxy/logs:** improve Redis request logging in case of errors.
|
||||
- **Proxy/router:** add a configuration parameter to choose database connection pool size for message persistence.
|
||||
See the `message-database-pool-size` config for more information.
|
||||
- **Packaging:** Flexisip will create default configurations files on first install.
|
||||
|
||||
### [Fixed]
|
||||
- **B2BUA server:** fix a bug where Trenscrypter mode placed outgoing calls using the request address instead of
|
||||
the `To` header from the incoming call.
|
||||
- **Packaging:** fix Systemctl warning and service restart on Rocky Linux 9 after package update.
|
||||
- **Proxy:** fix a server hangup that occurred on TLS connection timeout.
|
||||
- **Proxy/push-notification:** fix crashes around HTTP/2 client that occurred on iOS push notification sending.
|
||||
- **Proxy/http/2 client:** fix a problem where frames where not sent directly after an HTTP/2 window size update.
|
||||
- **Proxy/registrar:** fix a race condition on rapid consecutive REGISTERs that may lead to a crash.
|
||||
- **Proxy/router:** fix bug where a 5xx response was preferred over a 6xx response for some INVITEs.
|
||||
- **Proxy/forward:** fix a bug where stateless CANCEL could be forwarded without the Reason header.
|
||||
|
||||
## [2.3.2] - 2023-09-07
|
||||
### [Fixed]
|
||||
- **Proxy/media-relay:** fix `candidates` media attributes being wiped out of all INVITE responses. This buggy behaviour
|
||||
was introduced in 2.3.1 while attempting to handle a response **with** ICE candidates to an INVITE **without** ICE
|
||||
candidates.
|
||||
- **Proxy/registrar:** fix a regression in a domain-registration scenario with "relay-reg-to-domains" enabled, where the
|
||||
backend server fails to route to the intermediate proxy.
|
||||
|
||||
## [2.3.1] - 2023-08-30
|
||||
### [Added]
|
||||
- **B2BUA server:** add the 'no-rtp-timeout' parameter that allows to set the delay before the call is automatically
|
||||
hung up because no RTP data is received.
|
||||
|
||||
### [Fixed]
|
||||
- **Proxy/authentication:** fix behavior differences of 'soci-password-request' according to which Soci backend
|
||||
is used. With SQlite backend the :authid placeholder was mandatory, which is not conform with parameter docstring,
|
||||
whereas it was optional with MySQL backend. It is now optional whatever the backend in use.
|
||||
- **Proxy/media-relay:** fix bad behavior when the MediaRelay forwards an INVITE without ICE candidate and the
|
||||
callee send back a response with ICE candidates. In this case, the media relay didn't masquerade the connection
|
||||
address of the response.
|
||||
- **Proxy/push-notification:** add support of 'google' legacy pn-type.
|
||||
- **Conference & B2BUA servers:** remove liblinphone debug messages from standard output when '-d' command-line
|
||||
option isn't used.
|
||||
|
||||
## [2.3.0] - 2023-08-21
|
||||
### [Added]
|
||||
- **Flexisip proxy:** add `global/tport-message-queue-size` parameter to set the max number of SIP messages to be
|
||||
queued for writing when a socket is full.
|
||||
- **Flexisip proxy:** add support for REGISTER requests with several Contact headers.
|
||||
- **Flexisip proxy:** reply to OPTIONS requests with “200 Ok”. Useful to keep a connection alive by using OPTIONS
|
||||
requests.
|
||||
- **Flexisip proxy:** add `module::Registrar/redis-auth-user` parameter to allow authentication to Redis servers via
|
||||
user/password.
|
||||
- **Conference server:** add audio/video conferencing capability.
|
||||
- **B2BUA:** forwarding of [RFC2833](https://datatracker.ietf.org/doc/html/rfc2833) and SIP INFO DTMFs.
|
||||
- **flexisip_cli.py:** add `REGISTRAR_UPSERT` command that allows to modify or insert any registrar binding for a given
|
||||
Address of Record.
|
||||
- **External authentication plugin:** add the SNI header in order to establish TLS connections with HTTPS virtual hosts.
|
||||
- Packaging for Rocky Linux 9 and Debian 12.
|
||||
- **[Experimental]** New EventLog backend based on an HTTP REST API.
|
||||
|
||||
### [Changed]
|
||||
- **Flexisip proxy:** enforce compliance with [RFC3261](https://datatracker.ietf.org/doc/html/rfc3261) when processing
|
||||
REGISTER requests. The Call-ID is no longer used as unique-id when no `+sip-instance` parameter has been set in the
|
||||
Contact-URI; the Contact-URI is used instead by using URI comparison logic as described
|
||||
in [RFC3261 – Section 10.2.4](https://datatracker.ietf.org/doc/html/rfc3261#section-10.2.4). The CSeq value is now
|
||||
used to avoid replay attacks or SIP race conditions.
|
||||
|
||||
## [2.2.5] - 2023-08-02
|
||||
### [Added]
|
||||
- **Presence server:** add timestamp of last activity to the presence notification when the status of the user is 'away'
|
||||
or their client is no longer active.
|
||||
|
||||
### [Fixed]
|
||||
- **Proxy:** fix system file descriptor limit detection bug that was eventually causing Flexisip to run out of file
|
||||
descriptors to handle all of its connections on some OS.
|
||||
- **Proxy – ContactRouteInserter:** increase the max size of the 'CtRtxxxxx' parameter to 512 bytes to ensure that a
|
||||
full domain name can be stored.
|
||||
- **Proxy – ExternalPushNotification:** fix bad behavior when an iOS client uses legacy push parameters while
|
||||
registering and the 'app-id' parameter doesn't end with '.prod' or '.dev'. It caused the '$app-id' placeholder to be
|
||||
replaced by a truncated 'app-id'. The fix makes Flexisip assume the 'app-id' ends with '.prod' if the user agent
|
||||
hasn't specified the last component.
|
||||
|
||||
## [2.2.4] - 2023-04-20
|
||||
### [Fixed]
|
||||
- Bug in SofiaSip that causes the proxy to choose a not fully established TCP connection when it needs to send a SIP
|
||||
message to a user agent. That causes some SIP message losses.
|
||||
- Make the proxy to answer “200 Ok” to OPTIONS requests that are directly addressed to itself.
|
||||
- Crash when the “Generic Push Notifications” feature is enabled (`module::PushNotification/external-push-uri`) but no
|
||||
Firebase API key has been put in `firebase-projects-api-keys` parameter.
|
||||
- Fix a bug that causes some PUBLISH requests that was not related to presence information to be forwarded to the
|
||||
presence server.
|
||||
|
||||
## [2.2.3] - 2023-04-11
|
||||
### [Fixed]
|
||||
- CLI: print a more explicit message when the CLI cannot connect to the server socket due to permissions.
|
||||
- Pusher: allow to set a custom payload for Firebase push notifications requests, as it is for Apple.
|
||||
- Presence server: ensure that capabilities of each device of a user are concatenated by union while sending a NOTIFY
|
||||
request to the subscriber.
|
||||
- Proxy server: make the generic pusher to replace the $app-id parameter by the right value.
|
||||
|
||||
## [2.2.2] - 2023-02-24
|
||||
### [Fixed]
|
||||
- Issue in packaging and deployment scripts.
|
||||
|
||||
## [2.2.1] - 2023-02-24
|
||||
### [Added]
|
||||
|
||||
- 'global/tport-message-queue-size' parameter in flexisip.conf. Allows to set the size of the message queue which is
|
||||
used when a SIP message cannot be sent because the socket is full.
|
||||
|
||||
### [Changed]
|
||||
|
||||
- Format of `--key` option of `./flexisip_pusher` tool. The option only takes the Firebase authentication token now.
|
||||
|
||||
### [Fixed]
|
||||
|
||||
- Bug that caused the number of contacts for a given AoR to grow indefinitely when there was no '+sip.instance'
|
||||
parameter in the Contact-URI.
|
||||
- Push notification was not sent to the second device when two devices had the same 'pn-prid' but distinct '
|
||||
pn-provider'.
|
||||
- Messages were not forwarded with the same order as when they were received, should 'save-fork-late-message-in-db'
|
||||
feature have been enabled.
|
||||
- 6xx responses were not prioritized on 4xx responses when the proxy had to forward a final response to the caller.
|
||||
- Compilation with `ENABLE_SOCI=OFF` was broken.
|
||||
- Crash when the “Periodic Binding Refresh” mechanism (rfc8599) was
|
||||
enabled (module::PushNotification/register-wakeup-interval>=0)
|
||||
- The MediaRelay let the video stream pass in one direction only when the call was in early-media.
|
||||
- Flexisip depended of useless runtime libraries such as libGLEW, libX11, etc.
|
||||
- The ExternalAuthentication module didn't set the SNI header when it connected on the HTTPS server.
|
||||
|
||||
## [2.2.0] - 2022-10-28
|
||||
### [Added]
|
||||
|
||||
- [Back-to-back user agent service](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/C.%20Features/3.%20Back-to-back%20User%20Agent%20server)
|
||||
- `module::Router/message-database-enabled` parameter: allow to store the chat messages that are waiting for delivery
|
||||
in a SQL database instead of memory (experimental).
|
||||
Associated parameters: `message-database-backend`, `message-database-connection-string`.
|
||||
- [Filter syntax](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/Configuration/Filter%20syntax/) getter
|
||||
additions:
|
||||
- `contact.uri.{user,domain,params}`: get parts of the Contact-URI of the current SIP message;
|
||||
- `content-type`: get the full Content-type of the body as string.
|
||||
- `module::ExternalAuth/trusted-hosts` parameter: allow to let requests coming from given IP addresses pass the
|
||||
ExternalAuth module. This module is provided by 'libexternal-auth' plugin.
|
||||
- Make the proxy to answer to double-CRLF ping sequence (RFC5626 §4.4.1).
|
||||
- Use double-CRLF ping sequence (RFC5626 §4.4.1) to maintain connections made by the domain registration feature.
|
||||
- Packaging for Rocky Linux 8, Debian 11, Ubuntu 22.04 LTS.
|
||||
|
||||
### [Changed]
|
||||
|
||||
- Improve the usage of iOS remote push notifications for notifying incoming calls. This is useful for home-automation
|
||||
applications that haven't any VoIP push notification token. In such a case, Flexisip will send several alert PNs to
|
||||
the application until one called device accept the call, and then, send a final alert PN to all the other devices
|
||||
telling that the call has been answered elsewhere. Furthermore, all the called devices receive a final PN should
|
||||
the caller cancel the call. Related parameters: `module::PushNotification/call-remote-push-interval`.
|
||||
- The body of the SIP messages are hidden by default except the body of type `application/sdp`. This behaviour may be
|
||||
customized by `global/show-body-for` parameter that allows to modify the condition that discriminates which request
|
||||
should have their body displayed.
|
||||
|
||||
### [Fixed]
|
||||
|
||||
- Make the MediaRelay module to handle UPDATE requests.
|
||||
- Issue where a 200 Ok for REGISTER coming from an upstream server is discarded instead of being routed back the
|
||||
originator of the REGISTER. Only concerns user of `module::Registrar/reg-on-response` feature.
|
||||
- Avoid push notification sending while forwarding INVITE requests with `Replace` header.
|
||||
- Issue with domain registration digest authentication which failed because of the selection of a different SRV node
|
||||
between first and authenticated request.
|
||||
- Add a mechanism to ensure that all devices receive an INVITE followed by a CANCEL when a caller cancel a call
|
||||
invitation. This is useful for iOS devices that are ringing before receiving the INVITE request because they
|
||||
are notified by a VoIP push notification. Thus, such devices need to receive a CANCEL request to stop ringing.
|
||||
|
||||
### [Deprecated]
|
||||
|
||||
- `conference-server/enable-one-to-one-chat-room` parameter. Will force to `true` in further versions.
|
||||
- Package for Debian 9.
|
||||
|
||||
## [2.1.6] - 2023-09-22
|
||||
### [Fixed]
|
||||
- Backport of several fixes concerning our HTTP/2 client code.
|
||||
|
||||
## [2.1.5] - 2022-06-09
|
||||
### [Fixed]
|
||||
|
||||
- `reg-on-response` parameter no longer worked since Flexisip 2.1.0
|
||||
|
||||
## [2.1.4] - 2022-05-19
|
||||
### [Fixed]
|
||||
|
||||
- Fix warning about failing SQL request on conference server starting.
|
||||
- Make Flexisip to require Hiredis >= 0.14.
|
||||
- Remove Sofia-SIP implementation of some functions that must be found on system.
|
||||
|
||||
## [2.1.3] - 2022-03-18
|
||||
### [Fixed]
|
||||
|
||||
- ExternalPusher: the response to each HTTP request systematically has a delay of a few seconds when using a TCP
|
||||
connection instead of TLS.
|
||||
- Race condition around Redis SUBSCRIBEs/UNSUBSCRIBEs that causes Flexisip to wrongly thinks that it is subscribed to
|
||||
some fork contexts. Finally, that causes to have end-users' device receiving push notifications for a message but no
|
||||
message is delivered by Flexisip once the application registers again.
|
||||
- Weakness in the module replacement algorithm that causes some modules coming
|
||||
from plugins to be inserted in bad position in the modules list.
|
||||
|
||||
## [2.1.2] - 2021-12-22
|
||||
### [Added]
|
||||
- `rtp_bind_address` configuration parameter, which allow to choose the listening address of the media relay.
|
||||
- Allow boolean expression filter to access the Contact header of the request.
|
||||
|
||||
### [Fixed]
|
||||
- Have the CMake script to install flexisip-version.h header and embed it in the RPM/DEB package.
|
||||
- Crash of the proxy when using `REGISTERAR_DELETE` command in flexisip_cli.
|
||||
- Fix problems in migration of old protobuf-encoded Registrar entries.
|
||||
|
||||
## [2.1.1] - 2021-10-25
|
||||
### [Fixed]
|
||||
- Fix an issue in the CPack script that caused the name of CentOS packages to not conform with CentOS format, because
|
||||
the distribution tag (el7, el8, etc.) was missing.
|
||||
|
||||
## [2.1.0] - 2021-10-20
|
||||
### [Added]
|
||||
- New Flexisip service, 'RegEvent server', available through flexisip-regevent SystemD service.
|
||||
The RegEvent server is in charge of responding to SIP SUBSCRIBEs for the 'reg' event as defined by
|
||||
[RFC3680 - A Session Initiation Protocol (SIP) Event Package for Registrations](https://tools.ietf.org/html/rfc3680).
|
||||
To generate the outgoing NOTIFY, it relies upon the registrar database, as setup in module::Registrar section.
|
||||
- **Proxy** New transport URI parameter: `tls-allow-missing-client-certificate=<true/false>`. This allows to accept TLS
|
||||
connections from clients which haven't any X.509 certificate even if `tls-verify-incoming` has been enabled. Valid for
|
||||
SIPS transport only.
|
||||
- **Proxy** Add `module::DoSProtection/white-list` parameter in flexisip.conf to allow packets from given IP addresses
|
||||
to bypass the DoS protection system.
|
||||
- **Proxy** Add `module::Authentication/realm` parameter that allows to force the realm offered by the proxy to user
|
||||
agents during authentication (401/407 responses).
|
||||
- **Conference server** Several factory URIs can be handled by the server.
|
||||
- **Push notifications** New option `--custom-payload` for flexisip_pusher utility that allows to manually set the
|
||||
payload sent to push notificaiton server (Apple push only).
|
||||
- **Flexisip CLI** Add `REGISTRAR_DUMP` CLI command to dump all addresses of record registered locally.
|
||||
- **Packaging** Support of CentOS 8 and Debian 10 GNU/Linux distributions.
|
||||
|
||||
### [Changed]
|
||||
- **Proxy** `regex` operator of filter expressions in flexisip.conf now
|
||||
uses [ECMAScript grammar](https://en.cppreference.com/w/cpp/regex/ecmascript) from C++ specification.
|
||||
- **Proxy** Firebase push notifications are now sent by using HTTP/2 protocol.
|
||||
- **Presence server** Moving `soci-user-with-phone-request` and `soci-users-with-phones-request` parameters
|
||||
from _[module::Authenticaiton]_ section to _[presence-server]_.
|
||||
- **Conference server** Conformance to 1.1 specification.
|
||||
- **Packaging** Packaging process has entirely been reworked in order to embed Flexisip and Linphone SDK inside a single
|
||||
package. Thus, a given version of Flexisip is strongly bound to a specific version of Linphone SDK.
|
||||
|
||||
### [Deprecated]
|
||||
- **Presence server** Setting `module::Authentication/soci-user-with-phone-request` and
|
||||
`module::Authentication/soci-users-with-phones-request` parameters still works but will raise a warning.
|
||||
|
||||
### [Removed]
|
||||
- **Proxy/Push notifications** `pn-silent` push parameter has no more effect.
|
||||
- **Proxy/Push notifications** Remove legacy `form-uri` key-value from Firebase push notification body.
|
||||
|
||||
## [2.0.9] - 2021-08-10
|
||||
### [Fixed]
|
||||
- **Proxy** Reverts the previous fix which prevents that two contacts with the same push parameters be registered for
|
||||
the same user. Side effects which caused some users to not receive messages or calls have been observed in production.
|
||||
|
||||
## [2.0.8] - 2021-08-09
|
||||
### [Added]
|
||||
- **Proxy** Adding 'fallback-route-filter' parameter in 'module::Router' section. This parameter allows to prevent some
|
||||
SIP requests to be forwarded to the fallback route when all the forked transactions have failed. The parameter expects
|
||||
a boolean expression as the filter parameter at the beggining of each module::\* sections. The fallback route is used
|
||||
when the boolean expression is evaluated to _true_.
|
||||
|
||||
### [Fixed]
|
||||
- **Proxy** Prevent SIP client to registers two distinct contacts (distinct UID) which would have the same push
|
||||
notification parameters. That often happens when Linphone is uninstalled and installed again on an iOS device, causing
|
||||
the instance UID to be generated again but keeping the same push notification tokens. That causes the device to
|
||||
receives several push notifications for each SIP request because Flexisip assumes that each contact URI matches a
|
||||
distinct device. To avoid this scenario, Flexisip automatically removes the old contact URI to ensure the unicity
|
||||
of the push notification parameters.
|
||||
|
||||
## [2.0.7] - 2021-07-09
|
||||
### [Fixed]
|
||||
- **Proxy** Fix a bug that caused the fallback route to be used even if the forked request had succeeded.
|
||||
|
||||
## [2.0.6] - 2021-07-07
|
||||
### [Fixed]
|
||||
- **Proxy** INVITE requests was systematically forked to the fallback route (if set) independently of the status of each
|
||||
received response. Furthermore, the fallback destination was called alongside the real contact addresses of the called
|
||||
identity.
|
||||
|
||||
## [2.0.5] - 2021-06-09
|
||||
### [Added]
|
||||
- **Flexisip CLI** Add three new counters: count-basic-forks, count-call-forks and count-message-forks.
|
||||
|
||||
### [Fixed]
|
||||
- **Apple push notifications** Set the 'apns-push-type' header.
|
||||
- **Apple push notifications** Correctly set the 'apns-expiration' header, basing on some parameters of module::Router
|
||||
(call-fork-timeout and message-delivery-timeout).
|
||||
- **Apple push notifications** Prevent the TLS connection from blocking the main thread for more than one second while
|
||||
connecting.
|
||||
- **Android push notifications** Fix typo in the name of one key in the PNR payload. ('form-uri' -> 'from-uri'). The old
|
||||
key will be supported until Flexisip 2.1.
|
||||
- **External Authentication plugin** Correctly print the HTTP response from the authentication server in the log.
|
||||
- **External Authentication plugin** Fix bug that caused the HTTP response to be matched with the bad request when
|
||||
several request was sent simultaneously.
|
||||
- **Filter parameter** Fix crash on evaluation when 'contains' operator has no left-hand operand. Makes Flexisip to
|
||||
abort on starting otherwise.
|
||||
- **Flexisip CLI** Fix crash with Python3 < 3.7.
|
||||
- **Memory usage** Fix several memory leaks.
|
||||
- **XWiki doc generator** Fix bad output syntax when bullet points are used in parameter descriptions.
|
||||
- **XWiki doc generator** Generate documentation for the experimental modules.
|
||||
|
||||
## [2.0.4] - 2021-03-01
|
||||
### [Fixed]
|
||||
- **Authentication** Prevent password mismatch error when hashed passwords are in upper case in the user database.
|
||||
- **Push Notifications** Prevent the PushNotification module from sending an out-of-dialog "180 Ringing" reply when an
|
||||
in-dialog 180 reply has already been forwarded back by the Router module.
|
||||
- **Apple push notifications** The new HTTP/2 client now automatically close the connection with the APNS after one
|
||||
minute of inactivity to prevent the connection to be silently destroyed by aggressive routers. That improve PNR
|
||||
sending reliability.
|
||||
- **Android push notifications** Use timeouts that has been set in the Router module settings to fill the TTL with the
|
||||
push notification request.
|
||||
See [Flexisip's specification around push notifications](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/D.%20Specifications/Push%20notifications/#HContentofthepushnotificationssentbyFlexisip)
|
||||
for more information about the involved parameters.
|
||||
- **Media relay** Fix an issue while processing a SDP without ICE containing an IPv6 connection address, and Flexisip
|
||||
has no IPv6 address available.
|
||||
Previously, an empty connection address was set by the MediaRelay module, causing a blank call. Now, the IPv4 address
|
||||
will be used as fallback, which will work if the network provides NAT64 service.
|
||||
- **Proxy server** Fix several huge memory leaks. No more memory leaks issues are known on the proxy component today.
|
||||
- **Conference server** The transport address now allows to restrict the listening interface. Before, the conference was
|
||||
listening on all interfaces independently of the transport host.
|
||||
|
||||
### [Removed]
|
||||
- 'pn-silent' custom Contact parameter for push notifications.
|
||||
|
||||
## [2.0.3] - 2020-11-13
|
||||
### [Fixed]
|
||||
- Apple push notification client: the body of HTTP/2 GOAWAY frames wasn't printed in log, which doesn't allow to know
|
||||
the disconnection reason.
|
||||
- Fix a regression that causes to have an empty pub-gruu parameter in the Contact header of forwarded REGISTERs.
|
||||
- Fix potential crash or at least memory corruption when both "route" and "default-transport" are set in the
|
||||
ForwardModule. The default-transport will not be applied when route is used.
|
||||
- MediaRelay: fix ICE restart not being detected or notified on the offered side. This causes relay candidates to be not
|
||||
added in the 200 Ok, which can break RTP communication.
|
||||
|
||||
## [2.0.2] - 2020-10-14
|
||||
### [Fixed]
|
||||
- Fix a crash that occures when module::Registrar/reg-on-response feature is enabled. It happens when the “200
|
||||
Registration successful” response is received from the backend server.
|
||||
|
||||
## [2.0.1] - 2020-10-13
|
||||
### [Changed]
|
||||
- Usage of HTTP2 protocol to send Apple push notification requests. No change in PushNotification module configuration
|
||||
required.
|
||||
|
||||
### [Fixed]
|
||||
- Crash when trying to fetch domain records from registrar DB.
|
||||
- Avoid MediaRelay's channel to continuously swap between IPv6 and IPv4 during ICE connectivity checks. Indeed, this
|
||||
causes some connectivity checks to fail because some stun requests sent over IPv6 are answered over IPv4 and vice
|
||||
versa. The workaround implemented consists in locking the destination chosen by the MediaRelay's channels (when
|
||||
receiving a packet) for a minimum of 5 seconds. The switch to a new destination is allowed only if the previous
|
||||
destination has been unused over the last 5 seconds.
|
||||
|
||||
## [2.0.0] – 2020-07-31
|
||||
### [Added]
|
||||
**New settings**
|
||||
- `global/contextual-log-filter` ([Contextual log feature](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/C.%20Features/Contextual%20logs/))
|
||||
- `global/contextual-log-level` ([Contextual log feature](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/C.%20Features/Contextual%20logs/))
|
||||
- `global/log-filename`: allows to choose the name of the log file.
|
||||
- `module::Authentication/realm-regex`: allows to choose how the authentication module deduces the realm from the "From"
|
||||
header.
|
||||
- `module::PushNotification/retransmission-count` (PNR retransmission feature)
|
||||
- `module::PushNotification/retransmission-interval` (PNR retransmission feature)
|
||||
- `module::PushNotification/display-from-uri`: controls whether the "From" URI is print in PN payloads.
|
||||
- `module::MediaRelay/force-public-ip-for-sdp-masquerading`: force the MediaRelay module to put the public IP address of
|
||||
the proxy while modifying the SDP body of INVITE requests. Only useful when the server is behind a NAT router.
|
||||
- `conference-server/check-capabalities` (
|
||||
see [Reference Documentation](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/A.%20Configuration%20Reference%20Guide/2.0.0/conference-server))
|
||||
|
||||
**Proxy**
|
||||
- [Contextual log feature](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/C.%20Features/Contextual%20logs/)
|
||||
- External authentication plugin.
|
||||
- Push Notification Request (PNR) retransmission feature. Allow to send PNR several time when no response for the first
|
||||
PNR has been received from the push server.
|
||||
- Add support for loc-key and loc-args to Firebase, in order to be compatible with apps implementing the same logic as
|
||||
for iOS when handling push notifications coming from Flexisip.
|
||||
- EventLog: log the value of 'Priority' header for each request event.
|
||||
- Support of [RFC 8599](https://tools.ietf.org/html/rfc8599) for the transmission of the PushNotification information
|
||||
through REGISTER requests.
|
||||
|
||||
**Presence**
|
||||
- Support
|
||||
of [“Server known resource lists” feature](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/C.%20Features/Presence%20server/#HServerknownresourcelists).
|
||||
|
||||
**Miscellaneous**
|
||||
- Add an option (`--rewrite-config`) to Flexisip command-line interface to dump a new configuration file with up-to-date
|
||||
doc strings but keeping the setting that have been set explicitly by the user.
|
||||
|
||||
### [Changed]
|
||||
**Settings**
|
||||
- Default value changes:
|
||||
- `global/enable-snmp`: `true` -> `false`
|
||||
- `gloabl/dump-cores`: `true` -> `false`
|
||||
- `module::Router/message-delivery-timeout`: 1w
|
||||
- `module::Router/message-accept-timeout`: 5s
|
||||
- `module::Forward/params-to-remove`: adding `pn-provider`, `pn-prid`, `pn-param`
|
||||
- `presence-server/max-thread`: `200` -> `50`
|
||||
- `presence-server/max-thread-queue-size`: `200` -> `50`
|
||||
|
||||
- Parameter renaming:
|
||||
- `event-logs/dir` -> `event-logs/filesystem-directory`
|
||||
- `module::Registrar/datasource` -> `module::Registrar/file-path`
|
||||
- `module::Registrar/name-message-expires` -> `module::Registrar/message-expires-param-name`
|
||||
- `presence-server/soci-connection-string` -> `presence-server/rls-database-connection`
|
||||
- `presence-server/external-list-subscription-request` -> `presence-server/rls-database-request`
|
||||
- `presence-server/max-thread` -> `presence-server/rls-database-max-thread`
|
||||
- `presence-server/max-thread-queue-size` -> `presence-server/rls-database-max-thread-queue-size`
|
||||
|
||||
- `[monitor]` section marked as experimental.
|
||||
- `[module::Presence]` section is no more marked as experimental.
|
||||
|
||||
**Proxy**
|
||||
- `REGISTRAR_CLEAR` sub-command of `flexisip_cli` can now clear registration of a given SIP identity.
|
||||
- Improvement of the performance of the boolean expression engine used by module filters.
|
||||
- Breaking of the event log database schema.
|
||||
- [Push Notifications] The "From" URI is no more printed in the PN payload as first element of loc-args list.
|
||||
Use `module::PushNotification/display-from-uri` setting to restore this behaviour.
|
||||
|
||||
**Miscellaneous**
|
||||
- Log files are now named flexisip-proxy.log, flexisip-conference.log flexisip-presence.log by default.
|
||||
- Log rotation is fully handled by Logrotate script (
|
||||
see [“Logging” documentation page](https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/Configuration/Logs/#HLogrotation)).
|
||||
- `--dump-all-default` option dumps a configuration file with all the parameters commented out.
|
||||
- `--dump-default` allow to dump default settings for non-module sections.
|
||||
- Generation of plugins default settings and documentation by '--dump-all-default' option when they have been loaded
|
||||
using `--set global/plugins=<plugin-list>`.
|
||||
|
||||
### [Deprecated]
|
||||
**New deprecated settings**
|
||||
- `global/use-maddr`
|
||||
- `global/max-log-size`
|
||||
- `module::Registrar/redis-record-serializer`
|
||||
- `module::Router/fork`
|
||||
- `module::Router/stateful`
|
||||
|
||||
### [Removed]
|
||||
**Removed settings**
|
||||
- `global/debug`
|
||||
- `module::Authentication/enable-test-accounts-creation`
|
||||
- `module::Authentication/hashed-password`
|
||||
- `module::Router/generated-contact-route`
|
||||
- `module::Router/generated-contact-expected-realm`
|
||||
- `module::Router/generate-contact-even-on-filled-aor`
|
||||
- `module::Router/preroute`
|
||||
- `module::PushNotification/google`
|
||||
- `module::PushNotification/google-*`
|
||||
|
||||
### [Fixed]
|
||||
**Proxy**
|
||||
- Aborted calls not logged in the event log.
|
||||
- Missing line-feed in filesystem event logs.
|
||||
- Prevent loops due to fallback routes, when two Flexisip servers have a fallback route to each other.
|
||||
- Abort server start if `module::Presence/presence-server` setting has an invalid SIP URI.
|
||||
- Don't set tag in “110 Push sent” responses. It makes no sense as a proxy doesn't have to create dialogs.
|
||||
- Prevent “110 Push sent” response from being sent after “180 Ringing”.
|
||||
- Prevent sending of multiple “110 Push sent” responses when a call is forked into several legs.
|
||||
- Prevent server abort on registration with an invalid Address-of-Record.
|
||||
- Crash when processing a REGISTER with an invalid Contact URI.
|
||||
- Bad behaviour when receiving a REGISTER request which contains a '@' in its CallID.
|
||||
- Failing authentication when the user part of the "From" URI has escaped sequences.
|
||||
- Improve Firebase's push notification resilience against broken sockets.
|
||||
- Remove empty 'pub-gruu' params from contact headers of OK response when `module::Registrar/reg-on-response` is on.
|
||||
- SystemD service not restarted on package update.
|
||||
- Fix MediaRelay ICE processing when the server has both IPv6 and IPv6 addresses. Previously, only ICE relay candidates
|
||||
with the "preferred" connectivity was offered. However, the way the "preferred" connectivity is guessed is not
|
||||
reliable, especially when sending the INVITE to the callee, and it can change during a call, for example when one of
|
||||
the parties moves from an IPv6-only LTE network to an IPv4-only network. For these reasons, it is preferable that ICE
|
||||
relay candidates are added for both IPv4 and IPv6.
|
||||
|
||||
**Conference**
|
||||
- Fix becoming admin again after leaving and reentering a chat room.
|
310
CMakeLists.txt
Normal file
310
CMakeLists.txt
Normal file
|
@ -0,0 +1,310 @@
|
|||
############################################################################
|
||||
# CMakeLists.txt
|
||||
# Copyright (C) 2010-2024 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
# CMP0076 is required to use relative path in target_sources.
|
||||
cmake_policy(SET CMP0076 NEW)
|
||||
# CMP0077 is required to correctly force the value of subprojects' cache variables.
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
|
||||
# Require C++17
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# -O0 disables optimizations. Any level of optimization (higher than 0) will throw off debuggers while stepping through source code.
|
||||
# With sanitizers enabled, fortifying source requires some optimizations. This is unwanted in Debug builds.
|
||||
set(CMAKE_C_FLAGS_DEBUG_INIT "-g -O0 -U_FORTIFY_SOURCE -fdiagnostics-color=always")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG_INIT ${CMAKE_C_FLAGS_DEBUG_INIT})
|
||||
|
||||
include("./linphone-sdk/bctoolbox/cmake/BCToolboxCMakeUtils.cmake")
|
||||
if(FLEXISIP_VERSION)
|
||||
message(WARNING "Ignoring git version, using provided \"${FLEXISIP_VERSION}\" instead")
|
||||
set(FLEXISIP_FULL_VERSION ${FLEXISIP_VERSION})
|
||||
else()
|
||||
# Set project version by using the Git describe
|
||||
bc_compute_full_version(FLEXISIP_FULL_VERSION)
|
||||
endif()
|
||||
bc_parse_full_version("${FLEXISIP_FULL_VERSION}" major minor patch)
|
||||
project(flexisip VERSION "${major}.${minor}.${patch}" LANGUAGES C CXX)
|
||||
unset(major)
|
||||
unset(minor)
|
||||
unset(patch)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CMakeDependentOption)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(FeatureSummary)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(GNUInstallDirs)
|
||||
include("cmake/FlexisipUtils.cmake")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(IS_DEBUG TRUE)
|
||||
else()
|
||||
set(IS_DEBUG FALSE)
|
||||
endif()
|
||||
|
||||
option(ENABLE_SANITIZERS "Turn on sanitizers, like the LSAN memory leak detector" ${IS_DEBUG})
|
||||
option(ENABLE_STRICT "Pass strict flags to the compiler" ON)
|
||||
option(ENABLE_STRICT_LINPHONESDK "Pass strict flags to the compiler for all Linphone SDK submodules" OFF)
|
||||
option(ENABLE_DATEHANDLER "Build DateHandler module" OFF)
|
||||
option(ENABLE_PDFDOC "Build PDF documentation" OFF)
|
||||
option(ENABLE_MONOTONIC_CLOCK_REGISTRATIONS "Enable monotonic clock for registrations" OFF)
|
||||
option(ENABLE_PRESENCE "Build with presence server support" ON)
|
||||
option(ENABLE_REDIS "Build with Redis support" ON)
|
||||
option(ENABLE_SNMP "Build with SNMP support" ON)
|
||||
option(ENABLE_SOCI "Build with SOCI support" ON)
|
||||
option(ENABLE_TRANSCODER "Build with transcoder support" ON)
|
||||
option(ENABLE_MDNS "Build with multicast DNS support" OFF)
|
||||
option(ENABLE_EXTERNAL_AUTH_PLUGIN "Enable ExternalAuth plugin support" ON)
|
||||
option(ENABLE_JWE_AUTH_PLUGIN "[Deprecated] Enable JweAuth plugin support" ON)
|
||||
option(ENABLE_UNIT_TESTS "Enable Flexisip unit tests (low level tests)" OFF)
|
||||
add_ccache_option(ON)
|
||||
option(ENABLE_COVERAGE "Enable flexisip clang test coverage reports (add instrumentation)" OFF)
|
||||
option(ENABLE_MSGPACK "[Deprecated] Build with support for MessagePack for Record serializing" OFF)
|
||||
option(ENABLE_FLEXIAPI "Support for sending usage statistics (messages, calls, conferences) to the Flexisip Account Manager" ON)
|
||||
option(INTERNAL_LIBSRTP2 "Build SRTP2 source code present as linphone-sdk submodule instead of searching it in system libraries" ON)
|
||||
option(INTERNAL_JSONCPP "Build and use vendored Jsoncpp source code instead of searching for it in system libraries" OFF)
|
||||
|
||||
cmake_dependent_option(INTERNAL_LIBHIREDIS "Build libhiredis source code present as Flexisip submodule instead of searching it in system libraries" OFF "ENABLE_REDIS" OFF)
|
||||
cmake_dependent_option(ENABLE_CONFERENCE "Build conference support" ON "ENABLE_SOCI" OFF)
|
||||
cmake_dependent_option(ENABLE_SOCI_POSTGRESQL_BACKEND "Build with SOCI Postgre sql backend support" ON "ENABLE_SOCI" OFF)
|
||||
cmake_dependent_option(ENABLE_B2BUA "Enable Back2back user agent support" ON "ENABLE_SOCI" OFF)
|
||||
cmake_dependent_option(ENABLE_UNIT_TESTS_NGHTTP2ASIO "Enable unit tests requiring libnghttp2_asio" ON "ENABLE_UNIT_TESTS" ON)
|
||||
cmake_dependent_option(ENABLE_SPECIFIC_FEATURES "Enable media relay specific features" OFF "ENABLE_TRANSCODER" OFF)
|
||||
|
||||
set(CPACK_GENERATOR "" CACHE STRING "Generator to use for making package. Supported values: 'RPM', 'DEB'")
|
||||
set(SYSCONF_INSTALL_DIR "" CACHE STRING
|
||||
"Configuration directory, the place where Flexisip expects its flexisip.conf file to reside. Always equal to '${CMAKE_INSTALL_FULL_SYSCONFDIR}' if empty."
|
||||
)
|
||||
set(FLEXISIP_SYSTEMD_INSTALL_DIR "" CACHE STRING
|
||||
"Where to install the SystemD units. Always equal to '${CMAKE_INSTALL_FULL_DATAROOTDIR}/systemd/system' if empty."
|
||||
)
|
||||
|
||||
if(ENABLE_CONFERENCE OR ENABLE_B2BUA)
|
||||
set(LIBLINPHONE_REQUIRED ON)
|
||||
set(HAVE_LIBLINPHONE YES)
|
||||
set(HAVE_LIBLINPHONECXX YES)
|
||||
elseif(ENABLE_UNIT_TESTS)
|
||||
set(LIBLINPHONE_REQUIRED ON)
|
||||
else()
|
||||
set(LIBLINPHONE_REQUIRED OFF)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SOCI OR LIBLINPHONE_REQUIRED)
|
||||
set(SOCI_REQUIRED ON)
|
||||
else()
|
||||
set(SOCI_REQUIRED OFF)
|
||||
endif()
|
||||
|
||||
# It seems -fsanitize=address and -Wuninitialized don't play well together
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Sanitizer"
|
||||
AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||
)
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105616
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 13.2.1)
|
||||
set(HAS_GCC_BUG_105616 ON)
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562
|
||||
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 12.3.0)
|
||||
set(HAS_GCC_BUG_105562 ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Place the built libraries and executables in top level directories 'lib' and 'bin' in the build tree.
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir.")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir.")
|
||||
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.")
|
||||
|
||||
# Advanced options (i.e. hidden to the user by default)
|
||||
option(ENABLE_LIBLINPHONE_TESTER "Build liblinphone_tester executable." OFF)
|
||||
mark_as_advanced(ENABLE_LIBLINPHONE_TESTER)
|
||||
|
||||
# Handle the default value of installation paths. That ensures that they are
|
||||
# always relative to the install prefix when the user hasn't set them explicitly.
|
||||
if(SYSCONF_INSTALL_DIR STREQUAL "")
|
||||
set(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
|
||||
endif()
|
||||
if(FLEXISIP_SYSTEMD_INSTALL_DIR STREQUAL "")
|
||||
set(FLEXISIP_SYSTEMD_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/systemd/system")
|
||||
endif()
|
||||
|
||||
# Build libflexisip and all its dependencies as shared libraries
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
|
||||
if(NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX)
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
|
||||
message(STATUS "Setting install rpath to ${CMAKE_INSTALL_RPATH}")
|
||||
endif()
|
||||
|
||||
set(CONFIG_DIR "${SYSCONF_INSTALL_DIR}/flexisip")
|
||||
message(STATUS "Config dir: ${CONFIG_DIR}")
|
||||
|
||||
set(INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
function(FIND_PROGRAM_REQUIRED varname progname)
|
||||
find_program(${varname} NAMES "${progname}")
|
||||
if(NOT ${varname})
|
||||
message(FATAL_ERROR "Program '${progname}' is required but could not be found")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
set(INTERNAL_MBEDTLS ON)
|
||||
include("cmake/ExternalDependencies.cmake")
|
||||
include("cmake/LinphoneSDK.cmake")
|
||||
|
||||
# Required packages
|
||||
|
||||
find_package(LibNgHttp2 REQUIRED)
|
||||
find_package(Threads)
|
||||
find_package(XercesC)
|
||||
|
||||
# Dummy executable used by the type-safe abstractions over POSIX processes
|
||||
find_program(DUMMY_EXEC NAMES true REQUIRED)
|
||||
|
||||
check_function_exists(arc4random HAVE_ARC4RANDOM)
|
||||
find_file(HAVE_SYS_PRCTL_H NAMES sys/prctl.h)
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
# Enable std::filesystem on old implementations (GNU <9.1, LLVM <9.0)
|
||||
link_libraries("stdc++fs")
|
||||
|
||||
# Options
|
||||
if(ENABLE_SNMP)
|
||||
# todo: Not quite ready
|
||||
FIND_PROGRAM_REQUIRED(NET_SNMP_PROG net-snmp-config)
|
||||
find_path(NET_SNMP_INCLUDE_DIRS NAMES net-snmp/net-snmp-config.h)
|
||||
if(NOT NET_SNMP_INCLUDE_DIRS)
|
||||
message(FATAL_ERROR "SNMP header files not found")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${NET_SNMP_PROG}" "--agent-libs" OUTPUT_VARIABLE NET_SNMP_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SPECIFIC_FEATURES)
|
||||
set(MEDIARELAY_SPECIFIC_FEATURES_ENABLED ON)
|
||||
endif()
|
||||
|
||||
|
||||
if(ENABLE_MONOTONIC_CLOCK_REGISTRATIONS)
|
||||
set(MONOTONIC_CLOCK_REGISTRATIONS ON)
|
||||
endif()
|
||||
|
||||
if(ENABLE_DATEHANDLER)
|
||||
set(HAVE_DATEHANDLER ON)
|
||||
endif()
|
||||
|
||||
if(ENABLE_REDIS AND NOT INTERNAL_LIBHIREDIS)
|
||||
find_package(Hiredis 0.14 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(ENABLE_PDFDOC)
|
||||
FIND_PROGRAM_REQUIRED(PDFLATEX_PROG pdflatex)
|
||||
endif()
|
||||
|
||||
if(ENABLE_MSGPACK)
|
||||
find_path(MSGPACK_INCLUDE_DIRS NAMES msgpack.hpp HINTS /usr/local/include REQUIRED)
|
||||
add_definitions("-DENABLE_MSGPACK")
|
||||
endif()
|
||||
|
||||
# Allow to use SLOGD and LOGD macros.
|
||||
add_definitions("-DBCTBX_DEBUG_MODE")
|
||||
|
||||
|
||||
find_package(OpenSSL 0.9.8 REQUIRED)
|
||||
|
||||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
|
||||
include_directories(
|
||||
"include"
|
||||
"src"
|
||||
"src/plugin"
|
||||
"src/presence"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/src"
|
||||
)
|
||||
|
||||
set(BELR_GRAMMARS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/belr/grammars")
|
||||
|
||||
configure_file(cmake/flexisip-config.h.in flexisip-config.h)
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/flexisip-config.h PROPERTIES GENERATED ON)
|
||||
add_compile_definitions("HAVE_CONFIG_H")
|
||||
|
||||
# Compute and set compilation options
|
||||
bc_init_compilation_flags(CPP_BUILD_FLAGS C_BUILD_FLAGS CXX_BUILD_FLAGS ENABLE_STRICT)
|
||||
|
||||
if(ENABLE_SANITIZERS)
|
||||
set(SANITIZERS_FLAG "-fsanitize=address,undefined")
|
||||
add_compile_options(
|
||||
${SANITIZERS_FLAG}
|
||||
"-fno-omit-frame-pointer"
|
||||
"-fno-optimize-sibling-calls"
|
||||
)
|
||||
add_link_options(${SANITIZERS_FLAG})
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(ENABLE_STRICT)
|
||||
list(APPEND CXX_BUILD_FLAGS
|
||||
"-Werror=unused-result" # Packaging (on Ubuntu) has this on, so better catch it sooner
|
||||
"-Werror=maybe-uninitialized" # GCC on CentOS 7 treats this as an error
|
||||
)
|
||||
endif()
|
||||
# -Werror=varargs seems to do false positives with GCC 4.9.x
|
||||
if(CMAKE_CXX_COMPILER_VERSION MATCHES "^4\\.9\\.[0-9]+$")
|
||||
list(APPEND CXX_BUILD_FLAGS "-Wno-error=varargs")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7)
|
||||
# Old compiler (gcc6 on Debian 9 Stretch) are giving us some toubles...
|
||||
list(APPEND CXX_BUILD_FLAGS "-Wno-error=unused-variable" "-Wno-error=attributes")
|
||||
else()
|
||||
# GCC on CentOS 7 treats this as an error
|
||||
list(APPEND CXX_BUILD_FLAGS "-Werror=format-truncation=1")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# Old compiler (clang3 on Debian 9 Stretch) are giving us some toubles...
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
|
||||
list(APPEND CXX_BUILD_FLAGS "-Wno-error=unused-variable" "-Wno-error=unknown-attributes")
|
||||
endif()
|
||||
endif()
|
||||
add_compile_options(${CPP_BUILD_FLAGS} ${CXX_BUILD_FLAGS})
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(scripts)
|
||||
add_subdirectory(share)
|
||||
|
||||
if(ENABLE_UNIT_TESTS)
|
||||
add_subdirectory(tester)
|
||||
endif()
|
||||
|
||||
# Packaging
|
||||
add_subdirectory(packaging)
|
661
COPYING
Normal file
661
COPYING
Normal file
|
@ -0,0 +1,661 @@
|
|||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
179
README.md
Normal file
179
README.md
Normal file
|
@ -0,0 +1,179 @@
|
|||
# Flexisip
|
||||
|
||||
Flexisip is a comprehensive, modular and scalable SIP server suite written in C++17. It offers a wide range of
|
||||
functionalities, including:
|
||||
|
||||
* **Proxy Server**: acts as a central hub for routing SIP messages.
|
||||
* **Push Notification Service**: delivers SIP notifications (in-calls, messages) to mobile devices even when the app
|
||||
is not actively running.
|
||||
* **Presence Server**: enables users to see the online status of others and their availability for calls.
|
||||
* **Conference Server**: enables group voice and video calls.
|
||||
* **Back-to-Back User Agent (B2BUA) Server**: enables caller identity translation, media-level transcoding and SIP
|
||||
trunking.
|
||||
* **RegEvent Server**: notify tier domains of user registration
|
||||
|
||||
## Deployment and Applications:
|
||||
|
||||
* **Server-based VoIP Service**: Flexisip can be deployed on server machines to run a full-fledged SIP VoIP service.
|
||||
This is exemplified by the free linphone.org service, which has been powered by Flexisip since 2011. Users can create
|
||||
SIP accounts on this service to connect with each other.
|
||||
* **Embedded Solutions**: Flexisip can also be embedded and run seamlessly on smaller hardware systems, making it
|
||||
suitable for various embedded applications.
|
||||
|
||||
# License
|
||||
|
||||
Copyright © Belledonne Communications
|
||||
|
||||
Flexisip is dual licensed, and can be licensed and distributed:
|
||||
|
||||
- under a GNU Affero GPLv3 license for free (see COPYING file for details)
|
||||
- under a proprietary license, for closed source projects. Contact Belledonne Communications for any question about
|
||||
[costs and services](https://www.linphone.org/en/flexisip-sip-server/#flexisip-license).
|
||||
|
||||
# Documentation
|
||||
|
||||
- [Supported features and RFCs](https://www.linphone.org/en/flexisip-sip-server/#flexisip-software)
|
||||
- [Flexisip documentation](https://www.linphone.org/en/flexisip-sip-server/#flexisip-documentation)
|
||||
|
||||
# Dependencies
|
||||
|
||||
| Dependency | Description | Mandatory | Enabled by default |
|
||||
|:----------------|:--------------------------------------------------------------------------------------------------------------------------------------|:---------:|:------------------:|
|
||||
| OpenSSL | TLS stack. | X | |
|
||||
| LibNgHttp2 | HTTP2 stack. | X | |
|
||||
| libsrtp2 | Secure RTP (SRTP) and UST Reference Implementations | X | |
|
||||
| SQLite3 | Library for handling SQlite3 file | X | |
|
||||
| libmysql-client | Client library for MySQL database. | X | |
|
||||
| Hiredis | Redis DB client library, used for Registrar DB and communications between Flexisip instances of a same cluster. (-DENABLE\_REDIS=YES) | | X |
|
||||
| NetSNMP | SNMP library, used for SNMP support. (-DENABME\_SNMP=YES) | | X |
|
||||
| XercesC | XML parser. (-DENABLE\_PRESENCE=YES) | | X |
|
||||
| jsoncpp | JSON parsing and writing (-DENABLE\_B2BUA=YES) | | X |
|
||||
|
||||
# Compilation
|
||||
|
||||
## Required build tools
|
||||
|
||||
- C and C++ compiler. GCC and Clang are supported *as long as they are recent enough for building C++17 code*. On
|
||||
Redhat/CentOS 7, we recommend installing gcc-7 from https://www.softwarecollections.org/en/scls/rhscl/devtoolset-7/ .
|
||||
The default gcc-4.8 is not sufficient.
|
||||
- CMake >= 3.13
|
||||
- make or Ninja
|
||||
- Python >= 3
|
||||
- Doxygen
|
||||
- Git
|
||||
|
||||
## Building Flexisip with CMake
|
||||
|
||||
Create a build directory and configure the project:
|
||||
|
||||
### From cloned GIT repository
|
||||
|
||||
```bash
|
||||
mkdir ./build
|
||||
cmake -S . -B ./build
|
||||
make -C ./build -j<njobs>
|
||||
```
|
||||
|
||||
### Custom
|
||||
When built outside a git repository, you have to manually mention Flexisip and Linphone-SDK versions.
|
||||
|
||||
```bash
|
||||
mkdir ./build
|
||||
cmake -S . -B ./build -DFLEXISIP_VERSION=<version> -DLINPHONESDK_VERSION=<version>
|
||||
make -C ./build -j<njobs>
|
||||
```
|
||||
|
||||
### Some tips
|
||||
|
||||
Check *CMakeLists.txt* to know the list of the available options and their default value. To change an option, invoke
|
||||
*CMake* again and specify the option you need to change.
|
||||
For instance, here is how to disable the presence server feature:
|
||||
|
||||
```bash
|
||||
cmake ./build -DENABLE_PRESENCE=OFF
|
||||
make -C ./build -j<njobs>
|
||||
```
|
||||
|
||||
You may also use *ccmake* or *cmake-gui* utilities to interactively configure the project:
|
||||
|
||||
```bash
|
||||
ccmake ./build
|
||||
make -C ./build -j<njobs>
|
||||
```
|
||||
|
||||
## Building RPM or DEB packages
|
||||
|
||||
This procedure will help you generate a unique RPM package containing Flexisip, all its dependencies and the
|
||||
corresponding package for debug symbols.
|
||||
The following options are relevant for packaging:
|
||||
|
||||
| Option | Description |
|
||||
|:-----------------------|:---------------------------------------------------------------------------|
|
||||
| `CMAKE_INSTALL_PREFIX` | Prefix path where the package will install the files. |
|
||||
| `SYSCONF_INSTALL_DIR` | Directory where Flexisip expects to find its default configuration. |
|
||||
| `CMAKE_BUILD_TYPE` | Set it to “RelWithDebInfo” to have debug symbols in the debuginfo package. |
|
||||
| `CPACK_GENERATOR` | Package type: “RPM” or “DEB”. |
|
||||
|
||||
```bash
|
||||
cmake ./build -DCMAKE_INSTALL_PREFIX=/opt/belledonne-communications -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSYSCONF_INSTALL_DIR=/etc -DCPACK_GENERATOR=RPM
|
||||
make -C ./build -j<njobs> package
|
||||
```
|
||||
|
||||
Packages are now available in the `./build` directory.
|
||||
|
||||
[More info on RPM packaging](./packaging/rpm/README.md)
|
||||
|
||||
## Docker
|
||||
|
||||
A docker image can be built from sources using the following command:
|
||||
|
||||
```bash
|
||||
docker build -t flexisip --build-arg='njobs=<njobs>' -f docker/flex-from-src .
|
||||
```
|
||||
|
||||
## Nix ❄️
|
||||
|
||||
Flexisip can also be compiled with [Nix]. From the root of the repository, you can obtain a development shell using:
|
||||
|
||||
```sh
|
||||
nix-shell
|
||||
```
|
||||
|
||||
Or with Flakes enabled:
|
||||
|
||||
```sh
|
||||
nix develop
|
||||
```
|
||||
|
||||
Nix makes it easier to have a reproducible development environment on any Linux distribution, and doesn't interfere with
|
||||
other installed tooling. It is just an additional, **optional** way to build flexisip.
|
||||
|
||||
### Example build commands:
|
||||
|
||||
```sh
|
||||
CC=gcc CXX=g++ BUILD_DIR_NAME="build" cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -S . -B ./$BUILD_DIR_NAME -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="$PWD/$BUILD_DIR_NAME/install" -DENABLE_UNIT_TESTS=ON -DENABLE_STRICT_LINPHONESDK=OFF -DINTERNAL_JSONCPP=OFF
|
||||
cd build
|
||||
clear && cmake --build . --target install && LSAN_OPTIONS="suppressions=../sanitizer_ignore.txt" bin/flexisip_tester --resource-dir "../tester/" --verbose
|
||||
```
|
||||
|
||||
### Note to maintainers
|
||||
|
||||
At the exception to [`shell.nix`](./shell.nix), `.nix` files should live inside the [`nix/`](./nix/) folder.
|
||||
|
||||
All `.nix` files should be formatted with `nixpkgs-fmt`.
|
||||
|
||||
[Nix]: https://nixos.org/
|
||||
|
||||
# Configuration
|
||||
|
||||
Flexisip needs a configuration file to run correctly.
|
||||
Use `./flexisip --dump-all-default > flexisip.conf` to generate a documented default configuration file.
|
||||
|
||||
# Developer notes
|
||||
|
||||
With sofia-sip, you can choose between `msg_dup()` and `msg_copy()`, `sip_from_dup()` and `sip_from_copy()`, _etc_.
|
||||
The difference isn't well documented in the sofia-sip documentation, but it is important to understand that:
|
||||
|
||||
- `*_dup()` makes a copy of the structure plus all included strings inside (deep copy).
|
||||
- `*_copy()` just makes a copy of the structure, not the strings pointed by it (shallow copy). **These functions are
|
||||
dangerous**; use `*_dup()` versions in doubt.
|
51
cmake/ExternalDependencies.cmake
Executable file
51
cmake/ExternalDependencies.cmake
Executable file
|
@ -0,0 +1,51 @@
|
|||
############################################################################
|
||||
# ExternalDependencies.cmake
|
||||
# Copyright (C) 2010-2023 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
############################################################################
|
||||
# Add some external dependencies as subproject
|
||||
############################################################################
|
||||
|
||||
# Configure and add SofiaSip
|
||||
function(add_sofiasip) # Use function of override variable without propagating the change afterwards
|
||||
set(ENABLE_UNIT_TESTS OFF)
|
||||
add_subdirectory("submodules/externals/sofia-sip")
|
||||
endfunction()
|
||||
add_sofiasip()
|
||||
|
||||
# Add libhiredis
|
||||
if(ENABLE_REDIS AND INTERNAL_LIBHIREDIS)
|
||||
function(add_hiredis)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options set at this level
|
||||
|
||||
add_subdirectory("submodules/externals/hiredis")
|
||||
target_compile_definitions(hiredis INTERFACE "INTERNAL_LIBHIREDIS")
|
||||
endfunction()
|
||||
add_hiredis()
|
||||
endif()
|
||||
|
||||
# Configure and add Jose
|
||||
if(ENABLE_JWE_AUTH_PLUGIN)
|
||||
function(add_jose)
|
||||
add_subdirectory("submodules/externals/jose")
|
||||
endfunction()
|
||||
add_jose()
|
||||
endif()
|
85
cmake/FindHiredis.cmake
Normal file
85
cmake/FindHiredis.cmake
Normal file
|
@ -0,0 +1,85 @@
|
|||
############################################################################
|
||||
# FindHiredis.cmake
|
||||
# Copyright (C) 2017 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# - Find the libhiredis library
|
||||
#
|
||||
# HIREDIS_FOUND - system has libhiredis
|
||||
# HIREDIS_INCLUDE_DIRS - the libhiredis include directory
|
||||
# HIREDIS_LIBRARIES - The libraries needed to use libhiredis
|
||||
# HIREDIS_ASYNC_ENABLED - The found libhiredis library supports async commands
|
||||
|
||||
|
||||
# Find out the include directory
|
||||
find_path(HIREDIS_INCLUDE_DIRS
|
||||
NAMES hiredis/hiredis.h
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
# Find out the path to the library
|
||||
find_library(HIREDIS_LIBRARIES
|
||||
NAMES hiredis
|
||||
)
|
||||
|
||||
if(HIREDIS_INCLUDE_DIRS AND HIREDIS_LIBRARIES)
|
||||
# Extract the version number from the header files
|
||||
function(extract_version version_header range output_var)
|
||||
string(TOUPPER ${range} range)
|
||||
set(define_line_regex "^#define HIREDIS_${range} ([0-9]+)$")
|
||||
file(STRINGS ${version_header} define_line REGEX "${define_line_regex}")
|
||||
if(NOT define_line)
|
||||
message(FATAL_ERROR "HIREDIS_${range} isn't defined in '${version_header}'")
|
||||
endif()
|
||||
string(REGEX REPLACE ${define_line_regex} "\\1" version_range_value "${define_line}")
|
||||
set(${output_var} ${version_range_value} PARENT_SCOPE)
|
||||
endfunction()
|
||||
set(version_header "${HIREDIS_INCLUDE_DIRS}/hiredis/hiredis.h")
|
||||
extract_version(${version_header} major HIREDIS_VERSION_MAJOR)
|
||||
extract_version(${version_header} minor HIREDIS_VERSION_MINOR)
|
||||
extract_version(${version_header} patch HIREDIS_VERSION_PATCH)
|
||||
set(HIREDIS_VERSION "${HIREDIS_VERSION_MAJOR}.${HIREDIS_VERSION_MINOR}.${HIREDIS_VERSION_PATCH}")
|
||||
|
||||
# Check that the async mode is supported
|
||||
cmake_push_check_state(RESET)
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES ${HIREDIS_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${HIREDIS_LIBRARIES})
|
||||
check_symbol_exists("redisAsyncCommand" "hiredis/async.h" HIREDIS_ASYNC_ENABLED)
|
||||
cmake_pop_check_state()
|
||||
if(NOT HIREDIS_ASYNC_ENABLED)
|
||||
message(FATAL_ERROR "redisAsyncCommand() not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Define HIREDIS_FOUND output variable and define the 'hiredis' imported target
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Hiredis
|
||||
REQUIRED_VARS HIREDIS_INCLUDE_DIRS HIREDIS_LIBRARIES
|
||||
VERSION_VAR HIREDIS_VERSION
|
||||
)
|
||||
if (HIREDIS_FOUND)
|
||||
add_library(hiredis SHARED IMPORTED)
|
||||
set_target_properties(hiredis PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${HIREDIS_INCLUDE_DIR}"
|
||||
IMPORTED_LOCATION "${HIREDIS_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(HIREDIS_INCLUDE_DIRS HIREDIS_LIBRARIES HIREDIS_ASYNC_ENABLED)
|
44
cmake/FindJansson.cmake
Normal file
44
cmake/FindJansson.cmake
Normal file
|
@ -0,0 +1,44 @@
|
|||
############################################################################
|
||||
# FindJansson.cmake
|
||||
# Copyright (C) 2018 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# - Find Jansson include files and library
|
||||
#
|
||||
# JANSSON_FOUND - System has jansson
|
||||
# JANSSON_INCLUDE_DIRS - The jansson include directories
|
||||
# JANSSON_LIBRARIES - The libraries needed to use jansson
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(PC_JANSSON QUIET jansson)
|
||||
|
||||
find_path(JANSSON_INCLUDE_DIRS
|
||||
NAMES jansson.h
|
||||
HINTS ${PC_JANSSON_INCLUDE_DIRS}
|
||||
)
|
||||
find_library(JANSSON_LIBRARIES
|
||||
NAMES jansson
|
||||
HINTS ${PC_JANSSON_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Jansson REQUIRED_VARS JANSSON_INCLUDE_DIRS JANSSON_LIBRARIES)
|
||||
|
||||
mark_as_advanced(JANSSON_INCLUDE_DIRS JANSSON_LIBRARIES)
|
44
cmake/FindJose.cmake
Normal file
44
cmake/FindJose.cmake
Normal file
|
@ -0,0 +1,44 @@
|
|||
############################################################################
|
||||
# FindJose.cmake
|
||||
# Copyright (C) 2018 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# - Find Jose include files and library
|
||||
#
|
||||
# JOSE_FOUND - System has jose
|
||||
# JOSE_INCLUDE_DIRS - The jose include directories
|
||||
# JOSE_LIBRARIES - The libraries needed to use jose
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(PC_JOSE QUIET jose)
|
||||
|
||||
find_path(JOSE_INCLUDE_DIRS
|
||||
NAMES jose/jose.h
|
||||
HINTS ${PC_JOSE_INCLUDE_DIRS}
|
||||
)
|
||||
find_library(JOSE_LIBRARIES
|
||||
NAMES jose
|
||||
HINTS ${PC_JOSE_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Jose REQUIRED_VARS JOSE_INCLUDE_DIRS JOSE_LIBRARIES)
|
||||
|
||||
mark_as_advanced(JOSE_INCLUDE_DIRS JOSE_LIBRARIES)
|
44
cmake/FindLibNgHttp2.cmake
Normal file
44
cmake/FindLibNgHttp2.cmake
Normal file
|
@ -0,0 +1,44 @@
|
|||
############################################################################
|
||||
# FindNgHttp2.cmake
|
||||
# Copyright (C) 2010-2020 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# Find libnghttp2 and defined the associated target.
|
||||
#
|
||||
# Target name: LibNgHttp2
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(LIBNGHTTP2_INCLUDE_DIR nghttp2/nghttp2.h)
|
||||
find_library(LIBNGHTTP2_LIBRARY nghttp2)
|
||||
|
||||
find_package_handle_standard_args(LibNgHttp2 REQUIRED_VARS LIBNGHTTP2_INCLUDE_DIR LIBNGHTTP2_LIBRARY)
|
||||
|
||||
if (LIBNGHTTP2_FOUND)
|
||||
add_library(LibNgHttp2 SHARED IMPORTED)
|
||||
set_target_properties(LibNgHttp2 PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LIBNGHTTP2_INCLUDE_DIR}"
|
||||
IMPORTED_LOCATION "${LIBNGHTTP2_LIBRARY}"
|
||||
)
|
||||
endif()
|
||||
|
||||
unset(NGHTTP2_INCLUDE_DIR)
|
||||
unset(NGHTTP2_LIBRARY)
|
||||
|
44
cmake/FindLibNgHttp2Asio.cmake
Normal file
44
cmake/FindLibNgHttp2Asio.cmake
Normal file
|
@ -0,0 +1,44 @@
|
|||
############################################################################
|
||||
# FindLibNgHttp2Asio.cmake
|
||||
# Copyright (C) 2010-2021 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# Find libnghttp2_asio and defined the associated target.
|
||||
#
|
||||
# Target name: LibNgHttp2Asio
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(LIBNGHTTP2ASIO_INCLUDE_DIR nghttp2/asio_http2.h)
|
||||
find_library(LIBNGHTTP2ASIO_LIBRARY nghttp2_asio)
|
||||
|
||||
find_package_handle_standard_args(LibNgHttp2Asio REQUIRED_VARS LIBNGHTTP2ASIO_INCLUDE_DIR LIBNGHTTP2_LIBRARY)
|
||||
|
||||
if (LIBNGHTTP2ASIO_FOUND)
|
||||
add_library(LibNgHttp2Asio SHARED IMPORTED)
|
||||
set_target_properties(LibNgHttp2Asio PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LIBNGHTTP2ASIO_INCLUDE_DIR}"
|
||||
IMPORTED_LOCATION "${LIBNGHTTP2ASIO_LIBRARY}"
|
||||
)
|
||||
target_link_libraries(LibNgHttp2Asio INTERFACE LibNgHttp2)
|
||||
endif()
|
||||
|
||||
unset(NGHTTP2_ASIO_INCLUDE_DIR)
|
||||
unset(NGHTTP2_ASIO_LIBRARY)
|
111
cmake/FindODB.cmake
Normal file
111
cmake/FindODB.cmake
Normal file
|
@ -0,0 +1,111 @@
|
|||
#
|
||||
# This module defines the following variables:
|
||||
#
|
||||
# ODB_USE_FILE - Path to the UseODB.cmake file. Use it to include the ODB use file.
|
||||
# The use file defines the needed functionality to compile and use
|
||||
# odb generated headers.
|
||||
#
|
||||
# ODB_FOUND - All required components and the core library were found
|
||||
# ODB_INCLUDR_DIRS - Combined list of all components include dirs
|
||||
# ODB_LIBRARIES - Combined list of all componenets libraries
|
||||
#
|
||||
# ODB_LIBODB_FOUND - Libodb core library was found
|
||||
# ODB_LIBODB_INCLUDE_DIRS - Include dirs for libodb core library
|
||||
# ODB_LIBODB_LIBRARIES - Libraries for libodb core library
|
||||
#
|
||||
# For each requested component the following variables are defined:
|
||||
#
|
||||
# ODB_<component>_FOUND - The component was found
|
||||
# ODB_<component>_INCLUDE_DIRS - The components include dirs
|
||||
# ODB_<component>_LIBRARIES - The components libraries
|
||||
#
|
||||
# <component> is the original or uppercase name of the component
|
||||
#
|
||||
# The component names relate directly to the odb module names.
|
||||
# So for the libodb-mysql.so library, the component is named mysql,
|
||||
# for the libodb-qt.so module it's qt, and so on.
|
||||
#
|
||||
|
||||
set(ODB_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/UseODB.cmake")
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
function(find_odb_api component)
|
||||
string(TOUPPER "${component}" component_u)
|
||||
set(ODB_${component_u}_FOUND FALSE PARENT_SCOPE)
|
||||
|
||||
pkg_check_modules(PC_ODB_${component} QUIET "libodb-${component}")
|
||||
|
||||
find_path(ODB_${component}_INCLUDE_DIR
|
||||
NAMES odb/${component}/version.hxx
|
||||
HINTS
|
||||
${ODB_LIBODB_INCLUDE_DIRS}
|
||||
${PC_ODB_${component}_INCLUDE_DIRS})
|
||||
|
||||
find_library(ODB_${component}_LIBRARY
|
||||
NAMES odb-${component} libodb-${component}
|
||||
HINTS
|
||||
${ODB_LIBRARY_PATH}
|
||||
${PC_ODB_${component}_LIBRARY_DIRS})
|
||||
|
||||
set(ODB_${component_u}_INCLUDE_DIRS ${ODB_${component}_INCLUDE_DIR} CACHE STRING "ODB ${component} include dirs")
|
||||
set(ODB_${component_u}_LIBRARIES ${ODB_${component}_LIBRARY} CACHE STRING "ODB ${component} libraries")
|
||||
|
||||
mark_as_advanced(ODB_${component}_INCLUDE_DIR ODB_${component}_LIBRARY)
|
||||
|
||||
if(ODB_${component_u}_INCLUDE_DIRS AND ODB_${component_u}_LIBRARIES)
|
||||
set(ODB_${component_u}_FOUND TRUE PARENT_SCOPE)
|
||||
set(ODB_${component}_FOUND TRUE PARENT_SCOPE)
|
||||
|
||||
list(APPEND ODB_INCLUDE_DIRS ${ODB_${component_u}_INCLUDE_DIRS})
|
||||
list(REMOVE_DUPLICATES ODB_INCLUDE_DIRS)
|
||||
set(ODB_INCLUDE_DIRS ${ODB_INCLUDE_DIRS} PARENT_SCOPE)
|
||||
|
||||
list(APPEND ODB_LIBRARIES ${ODB_${component_u}_LIBRARIES})
|
||||
list(REMOVE_DUPLICATES ODB_LIBRARIES)
|
||||
set(ODB_LIBRARIES ${ODB_LIBRARIES} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
pkg_check_modules(PC_LIBODB QUIET "libodb")
|
||||
|
||||
set(ODB_LIBRARY_PATH "" CACHE STRING "Common library search hint for all ODB libs")
|
||||
|
||||
find_path(libodb_INCLUDE_DIR
|
||||
NAMES odb/version.hxx
|
||||
HINTS
|
||||
${PC_LIBODB_INCLUDE_DIRS})
|
||||
|
||||
find_library(libodb_LIBRARY
|
||||
NAMES odb libodb
|
||||
HINTS
|
||||
${ODB_LIBRARY_PATH}
|
||||
${PC_LIBODB_LIBRARY_DIRS})
|
||||
|
||||
find_program(odb_BIN
|
||||
NAMES odb
|
||||
HINTS
|
||||
${libodb_INCLUDE_DIR}/../bin)
|
||||
|
||||
set(ODB_LIBODB_INCLUDE_DIRS ${libodb_INCLUDE_DIR} CACHE STRING "ODB libodb include dirs")
|
||||
set(ODB_LIBODB_LIBRARIES ${libodb_LIBRARY} CACHE STRING "ODB libodb library")
|
||||
set(ODB_EXECUTABLE ${odb_BIN} CACHE STRING "ODB executable")
|
||||
|
||||
mark_as_advanced(libodb_INCLUDE_DIR libodb_LIBRARY odb_BIN)
|
||||
|
||||
if(ODB_LIBODB_INCLUDE_DIRS AND ODB_LIBODB_LIBRARIES)
|
||||
set(ODB_LIBODB_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
set(ODB_INCLUDE_DIRS ${ODB_LIBODB_INCLUDE_DIRS})
|
||||
set(ODB_LIBRARIES ${ODB_LIBODB_LIBRARIES})
|
||||
|
||||
foreach(component ${ODB_FIND_COMPONENTS})
|
||||
find_odb_api(${component})
|
||||
endforeach()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ODB
|
||||
FOUND_VAR ODB_FOUND
|
||||
REQUIRED_VARS ODB_EXECUTABLE ODB_LIBODB_FOUND
|
||||
HANDLE_COMPONENTS)
|
79
cmake/FindSofiaSipUa.cmake
Normal file
79
cmake/FindSofiaSipUa.cmake
Normal file
|
@ -0,0 +1,79 @@
|
|||
############################################################################
|
||||
# FindSofiaSipUa.txt
|
||||
# Copyright (C) 2014 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# - Find the sofia-sip include file and library
|
||||
#
|
||||
# SOFIASIPUA_FOUND - system has sofia-sip
|
||||
# SOFIASIPUA_INCLUDE_DIRS - the sofia-sip include directory
|
||||
# SOFIASIPUA_LIBRARIES - The libraries needed to use sofia-sip
|
||||
# SOFIASIPUA_CPPFLAGS - The cflags needed to use sofia-sip
|
||||
|
||||
|
||||
set(_SOFIASIPUA_ROOT_PATHS
|
||||
${WITH_SOFIASIPUA}
|
||||
${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
find_path(SOFIASIPUA_INCLUDE_DIRS
|
||||
NAMES sofia-sip/sip.h
|
||||
HINTS _SOFIASIPUA_ROOT_PATHS
|
||||
PATH_SUFFIXES include/sofia-sip-1.13 include/sofia-sip-1.12
|
||||
)
|
||||
|
||||
if(SOFIASIPUA_INCLUDE_DIRS)
|
||||
set(HAVE_SOFIASIPUA_SOFIASIPUA_H 1)
|
||||
|
||||
file(STRINGS "${SOFIASIPUA_INCLUDE_DIRS}/sofia-sip/sofia_features.h" SOFIASIPUA_VERSION_STR
|
||||
REGEX "^#define[\t ]+SOFIA_SIP_VERSION[\t ]+\"([0-9a-zA-Z\.])+\"$")
|
||||
|
||||
string(REGEX REPLACE "^.*SOFIA_SIP_VERSION[\t ]+\"([0-9a-zA-Z\.]+)\"$"
|
||||
"\\1" SOFIASIPUA_VERSION "${SOFIASIPUA_VERSION_STR}")
|
||||
endif()
|
||||
|
||||
find_library(SOFIASIPUA_LIBRARIES
|
||||
NAMES sofia-sip-ua
|
||||
HINTS ${_SOFIASIPUA_ROOT_PATHS}
|
||||
PATH_SUFFIXES bin lib
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SOFIASIPUA_LIBRARIES ws2_32 delayimp Winmm Qwave)
|
||||
endif(WIN32)
|
||||
list(REMOVE_DUPLICATES SOFIASIPUA_INCLUDE_DIRS)
|
||||
list(REMOVE_DUPLICATES SOFIASIPUA_LIBRARIES)
|
||||
set(SOFIASIPUA_CPPFLAGS "")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
|
||||
if (SOFIASIPUA_VERSION)
|
||||
find_package_handle_standard_args(SofiaSipUa
|
||||
REQUIRED_VARS SOFIASIPUA_INCLUDE_DIRS SOFIASIPUA_LIBRARIES
|
||||
VERSION_VAR SOFIASIPUA_VERSION
|
||||
)
|
||||
else()
|
||||
find_package_handle_standard_args(SofiaSipUa
|
||||
REQUIRED_VARS SOFIASIPUA_INCLUDE_DIRS SOFIASIPUA_LIBRARIES
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(SOFIASIPUA_INCLUDE_DIRS SOFIASIPUA_LIBRARIES SOFIASIPUA_CPPFLAGS)
|
61
cmake/FindZlib.cmake
Normal file
61
cmake/FindZlib.cmake
Normal file
|
@ -0,0 +1,61 @@
|
|||
############################################################################
|
||||
# FindZlib.cmake
|
||||
# Copyright (C) 2015-2018 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# - Find the zlib include file and library
|
||||
#
|
||||
# ZLIB_FOUND - system has zlib
|
||||
# ZLIB_INCLUDE_DIRS - the zlib include directory
|
||||
# ZLIB_LIBRARIES - The libraries needed to use zlib
|
||||
|
||||
if(ZLIB_HINTS)
|
||||
set(ZLIB_LIBRARIES_HINTS "${ZLIB_HINTS}/lib")
|
||||
endif()
|
||||
|
||||
find_path(ZLIB_INCLUDE_DIRS
|
||||
NAMES zlib.h
|
||||
HINTS "${ZLIB_HINTS}"
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
if(ZLIB_INCLUDE_DIRS)
|
||||
set(HAVE_ZLIB_H 1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_STATIC)
|
||||
find_library(ZLIB_LIBRARIES
|
||||
NAMES zstatic zlibstatic zlibstaticd z
|
||||
HINTS "${ZLIB_LIBRARIES_HINTS}"
|
||||
)
|
||||
else()
|
||||
find_library(ZLIB_LIBRARIES
|
||||
NAMES z zlib zlibd
|
||||
HINTS "${ZLIB_LIBRARIES_HINTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Zlib
|
||||
DEFAULT_MSG
|
||||
ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES HAVE_ZLIB_H
|
||||
)
|
||||
|
||||
mark_as_advanced(ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES HAVE_ZLIB_H)
|
77
cmake/Findjsoncpp.cmake
Normal file
77
cmake/Findjsoncpp.cmake
Normal file
|
@ -0,0 +1,77 @@
|
|||
############################################################################
|
||||
# Findjsoncpp.cmake
|
||||
# Copyright (C) 2010-2022 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if(INTERNAL_JSONCPP)
|
||||
if(NOT TARGET jsoncpp_lib)
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/linphone-sdk/external/jsoncpp" "${PROJECT_BINARY_DIR}/linphone-sdk/external/jsoncpp")
|
||||
endif()
|
||||
find_package_handle_standard_args(jsoncpp DEFAULT_MSG)
|
||||
else()
|
||||
find_package(jsoncpp CONFIG)
|
||||
if(jsoncpp_FOUND)
|
||||
get_target_property(JSONCPP_INCLUDE_DIR jsoncpp_lib INTERFACE_INCLUDE_DIRECTORIES)
|
||||
find_file(JSON_HEADER_FOUND NAMES "json.h" PATHS "${JSONCPP_INCLUDE_DIR}/json/" NO_CACHE)
|
||||
if(NOT JSON_HEADER_FOUND)
|
||||
# CentOS 7-8 & RockyLinux
|
||||
message(STATUS "Invalid jsoncpp include directory detected [${JSONCPP_INCLUDE_DIR}]. Trying '${JSONCPP_INCLUDE_DIR}/jsoncpp'")
|
||||
string(APPEND JSONCPP_INCLUDE_DIR "/jsoncpp")
|
||||
find_file(JSON_HEADER_FOUND NAMES "json.h" PATHS "${JSONCPP_INCLUDE_DIR}/json/" NO_CACHE)
|
||||
if(NOT JSON_HEADER_FOUND)
|
||||
message(FATAL_ERROR "CMake config file for 'jsoncpp' library is invalid. Try -DINTERNAL_JSONCPP=ON")
|
||||
endif()
|
||||
set_target_properties(jsoncpp_lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_INCLUDE_DIR}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Searching for jsoncpp in module mode")
|
||||
find_path(jsoncpp_INCLUDE_DIR "json/json.h" PATH_SUFFIXES "jsoncpp")
|
||||
find_library(jsoncpp_LIBRARIES jsoncpp)
|
||||
|
||||
# Get version number
|
||||
if (jsoncpp_INCLUDE_DIR)
|
||||
set(version_def_line_regex "^[ \\t]*#[ \\t]*define[ \\t]+JSONCPP_VERSION_STRING[ \\t]+\"([0-9]+\\.[0-9]+\\.[0-9]+)\"[ \\t]*$")
|
||||
file(STRINGS "${jsoncpp_INCLUDE_DIR}/json/version.h" version_def_line REGEX "${version_def_line_regex}")
|
||||
if (NOT version_def_line)
|
||||
message(FATAL_ERROR "Cannot find version number of jsoncpp")
|
||||
endif()
|
||||
string(REGEX REPLACE "${version_def_line_regex}" "\\1" version "${version_def_line}")
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(jsoncpp
|
||||
REQUIRED_VARS jsoncpp_INCLUDE_DIR jsoncpp_LIBRARIES
|
||||
VERSION_VAR version
|
||||
)
|
||||
|
||||
mark_as_advanced(jsoncpp_LIBRARIES jsoncpp_INCLUDE_DIR)
|
||||
|
||||
if(jsoncpp_FOUND)
|
||||
add_library(jsoncpp_lib SHARED IMPORTED)
|
||||
set_target_properties(jsoncpp_lib
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${jsoncpp_LIBRARIES}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${jsoncpp_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
39
cmake/FlexisipUtils.cmake
Normal file
39
cmake/FlexisipUtils.cmake
Normal file
|
@ -0,0 +1,39 @@
|
|||
############################################################################
|
||||
# FlexisipUtils.cmake
|
||||
# Copyright (C) 2010-2021 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
# Add the 'ENABLE_CCACHE' option that allows to find the ccache
|
||||
# executable on the system to use it as launcher for the C/C++
|
||||
# compiler.
|
||||
#
|
||||
# Parameter:
|
||||
# * default[in]: default value of ENABLE_CCACHE option. Must be a boolean.
|
||||
macro(add_ccache_option default)
|
||||
option(ENABLE_CCACHE "Use CCache to accelerate the build" ${default})
|
||||
if(ENABLE_CCACHE)
|
||||
find_program(CCACHE_EXECUTABLE "ccache")
|
||||
if(CCACHE_EXECUTABLE)
|
||||
message(STATUS "Using '${CCACHE_EXECUTABLE}' as C/C++ compiler launcher")
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}")
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
185
cmake/LinphoneSDK.cmake
Normal file
185
cmake/LinphoneSDK.cmake
Normal file
|
@ -0,0 +1,185 @@
|
|||
############################################################################
|
||||
# LinphoneSDK.cmake
|
||||
# Copyright (C) 2010-2023 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
############################################################################
|
||||
# Add Linphone SDK project as subproject
|
||||
############################################################################
|
||||
|
||||
function(add_linphonesdk)
|
||||
if(ENABLE_TRANSCODER OR ENABLE_CONFERENCE OR ENABLE_B2BUA)
|
||||
set(BUILD_MEDIASTREAMER2 ON)
|
||||
set(ENABLE_ZRTP ON)
|
||||
else()
|
||||
set(BUILD_MEDIASTREAMER2 OFF)
|
||||
set(ENABLE_ZRTP OFF)
|
||||
endif()
|
||||
|
||||
set(BUILD_SOCI ${SOCI_REQUIRED})
|
||||
if(BUILD_SOCI)
|
||||
set(BUILD_SOCI_BACKENDS "mysql;sqlite3")
|
||||
if(ENABLE_SOCI_POSTGRESQL_BACKEND)
|
||||
string(APPEND BUILD_SOCI_BACKENDS ";postgresql")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_PRESENCE OR ENABLE_MDNS OR ENABLE_CONFERENCE OR ENABLE_UNIT_TESTS)
|
||||
set(BUILD_BELLESIP ON)
|
||||
endif()
|
||||
|
||||
set(BUILD_LIBLINPHONE ${LIBLINPHONE_REQUIRED})
|
||||
|
||||
# # Global SDK config
|
||||
set(ENABLE_DOC OFF)
|
||||
set(ENABLE_PACKAGE_SOURCE OFF)
|
||||
set(ENABLE_STRICT ${ENABLE_STRICT_LINPHONESDK})
|
||||
set(ENABLE_TESTS_COMPONENT ON)
|
||||
set(ENABLE_TOOLS OFF)
|
||||
set(ENABLE_UNIT_TESTS ${ENABLE_LIBLINPHONE_TESTER})
|
||||
set(ENABLE_SANITIZER ${ENABLE_SANITIZERS})
|
||||
|
||||
# Global features activation
|
||||
set(BUILD_GSM OFF)
|
||||
set(BUILD_JSONCPP ${INTERNAL_JSONCPP})
|
||||
set(BUILD_AOM OFF)
|
||||
set(BUILD_DAV1D OFF)
|
||||
set(BUILD_LIBVPX OFF)
|
||||
set(BUILD_LIBXML2 OFF)
|
||||
set(BUILD_MBEDTLS_WITH_FATAL_WARNINGS OFF)
|
||||
set(BUILD_OPUS OFF)
|
||||
set(BUILD_SPEEX OFF)
|
||||
set(BUILD_SQLITE3 OFF)
|
||||
set(BUILD_XERCESC OFF)
|
||||
set(BUILD_ZLIB OFF)
|
||||
set(ENABLE_ADVANCED_IM ON)
|
||||
set(ENABLE_AMRNB OFF)
|
||||
set(ENABLE_AMRWB OFF)
|
||||
set(ENABLE_ASSETS OFF)
|
||||
set(ENABLE_BV16 OFF)
|
||||
set(ENABLE_CODEC2 OFF)
|
||||
set(ENABLE_CSHARP_WRAPPER OFF)
|
||||
set(ENABLE_CXX_WRAPPER ${BUILD_LIBLINPHONE})
|
||||
set(ENABLE_DB_STORAGE ON)
|
||||
set(ENABLE_DECAF ON)
|
||||
set(ENABLE_FFMPEG OFF)
|
||||
set(ENABLE_FLEXIAPI OFF)
|
||||
set(ENABLE_G726 OFF)
|
||||
set(ENABLE_G729 OFF) # Disable for license conformity
|
||||
set(ENABLE_G729B_CNG OFF) # Disable for license conformity
|
||||
set(ENABLE_GSM ON)
|
||||
set(ENABLE_ILBC OFF)
|
||||
set(ENABLE_ISAC OFF)
|
||||
set(ENABLE_JAVA_WRAPPER OFF)
|
||||
set(ENABLE_JAZZY_DOC OFF)
|
||||
set(ENABLE_JPEG OFF)
|
||||
set(ENABLE_LDAP OFF)
|
||||
set(ENABLE_LIBYUV OFF)
|
||||
set(ENABLE_LIME OFF)
|
||||
set(ENABLE_LIME_X3DH ${BUILD_LIBLINPHONE})
|
||||
|
||||
# ENABLE_MBEDTLS must be a cache variable because this option is declared by
|
||||
# libsrtp2 project as cache variable instead of using option() command. That avoid Flexisip
|
||||
# to masquerade this variable by using CMP0077 new behavior.
|
||||
set(ENABLE_MBEDTLS ON CACHE BOOL "Enable MbedTLS support." FORCE)
|
||||
mark_as_advanced(ENABLE_MBEDTLS)
|
||||
|
||||
set(ENABLE_MKV OFF)
|
||||
set(ENABLE_NON_FREE_FEATURES OFF)
|
||||
set(ENABLE_OPENH264 OFF)
|
||||
set(ENABLE_OPUS ON)
|
||||
set(ENABLE_PQCRYPTO OFF)
|
||||
set(ENABLE_QRCODE OFF)
|
||||
set(ENABLE_RELATIVE_PREFIX OFF)
|
||||
set(ENABLE_SILK OFF)
|
||||
set(ENABLE_SPEEX_CODEC ON)
|
||||
set(ENABLE_SPEEX_DSP ON)
|
||||
set(ENABLE_SRTP ON)
|
||||
set(ENABLE_SWIFT_WRAPPER OFF)
|
||||
set(ENABLE_SWIFT_WRAPPER_COMPILATION OFF)
|
||||
set(ENABLE_THEORA OFF)
|
||||
set(ENABLE_TUNNEL OFF)
|
||||
set(ENABLE_VCARD OFF)
|
||||
set(ENABLE_VIDEO ON)
|
||||
set(ENABLE_VPX ${BUILD_MEDIASTREAMER2})
|
||||
set(ENABLE_AV1 OFF)
|
||||
set(ENABLE_WEBRTC_AEC OFF)
|
||||
set(ENABLE_WEBRTC_VAD OFF)
|
||||
|
||||
set(BUILD_LIBSRTP2 ${INTERNAL_LIBSRTP2})
|
||||
set(BUILD_MBEDTLS ${INTERNAL_MBEDTLS})
|
||||
|
||||
# BcToolbox specific config
|
||||
set(ENABLE_DEFAULT_LOG_HANDLER OFF)
|
||||
|
||||
# BZRTP specific config
|
||||
set(ENABLE_ZIDCACHE ${ENABLE_ZRTP})
|
||||
set(ENABLE_EXPORTEDKEY_V1_0_RETROCOMPATIBILITY OFF)
|
||||
set(ENABLE_GOCLEAR ON)
|
||||
set(ENABLE_PQCRYPTO OFF)
|
||||
|
||||
if(BUILD_MEDIASTREAMER2)
|
||||
# Mediastreamer specific config
|
||||
set(ENABLE_FIXED_POINT OFF)
|
||||
set(ENABLE_PCAP OFF)
|
||||
set(ENABLE_SOUND OFF) # Disable all sound card backends.
|
||||
set(ENABLE_V4L OFF) # Disable video capture
|
||||
# Disable video rendering
|
||||
set(ENABLE_GL OFF)
|
||||
set(ENABLE_GLX OFF)
|
||||
set(ENABLE_SDL OFF)
|
||||
set(ENABLE_X11 OFF)
|
||||
set(ENABLE_XV OFF)
|
||||
set(ENABLE_RESAMPLE ON)
|
||||
endif()
|
||||
|
||||
if(BUILD_BELLESIP)
|
||||
# Belle-sip specific config
|
||||
set(ENABLE_RTP_MAP_ALWAYS_IN_SDP OFF)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LIME_X3DH)
|
||||
# Lime specific config
|
||||
set(ENABLE_CURVE25519 YES)
|
||||
set(ENABLE_CURVE448 YES)
|
||||
set(ENABLE_PROFILING NO)
|
||||
set(ENABLE_C_INTERFACE NO)
|
||||
set(ENABLE_JNI NO)
|
||||
endif()
|
||||
|
||||
if(BUILD_LIBLINPHONE)
|
||||
# Liblinphone specific config
|
||||
set(ENABLE_CONSOLE_UI OFF)
|
||||
set(ENABLE_DATE OFF)
|
||||
set(ENABLE_JAVADOC OFF)
|
||||
set(ENABLE_TUTORIALS OFF)
|
||||
set(ENABLE_UPDATE_CHECK OFF)
|
||||
if(APPLE)
|
||||
set(ENABLE_DAEMON OFF)
|
||||
else()
|
||||
set(ENABLE_DAEMON ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LINPHONESDK_BUILD_TYPE "Flexisip")
|
||||
|
||||
add_subdirectory("linphone-sdk")
|
||||
endfunction()
|
||||
add_linphonesdk()
|
167
cmake/UseODB.cmake
Normal file
167
cmake/UseODB.cmake
Normal file
|
@ -0,0 +1,167 @@
|
|||
|
||||
set(ODB_COMPILE_DEBUG FALSE)
|
||||
set(ODB_COMPILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/odb_gen")
|
||||
set(ODB_COMPILE_HEADER_SUFFIX ".h")
|
||||
set(ODB_COMPILE_INLINE_SUFFIX "_inline.h")
|
||||
set(ODB_COMPILE_SOURCE_SUFFIX ".cpp")
|
||||
set(ODB_COMPILE_FILE_SUFFIX "_odb")
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
|
||||
|
||||
function(odb_compile outvar)
|
||||
if(NOT ODB_EXECUTABLE)
|
||||
message(FATAL_ERROR "odb compiler executable not found")
|
||||
endif()
|
||||
|
||||
set(options GENERATE_QUERY GENERATE_SESSION GENERATE_SCHEMA GENERATE_PREPARED)
|
||||
set(oneValueParams SCHEMA_FORMAT SCHEMA_NAME TABLE_PREFIX
|
||||
STANDARD SLOC_LIMIT
|
||||
HEADER_PROLOGUE INLINE_PROLOGUE SOURCE_PROLOGUE
|
||||
HEADER_EPILOGUE INLINE_EPILOGUE SOURCE_EPILOGUE
|
||||
MULTI_DATABASE
|
||||
PROFILE)
|
||||
set(multiValueParams FILES INCLUDE DB)
|
||||
|
||||
cmake_parse_arguments(PARAM "${options}" "${oneValueParams}" "${multiValueParams}" ${ARGN})
|
||||
|
||||
if(PARAM_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "invalid arguments passed to odb_wrap_cpp: ${PARAM_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
|
||||
if(NOT PARAM_FILES)
|
||||
message(FATAL_ERROR: "no input files to odb_compile")
|
||||
endif()
|
||||
|
||||
set(ODB_ARGS)
|
||||
|
||||
if(PARAM_MULTI_DATABASE)
|
||||
list(APPEND ODB_ARGS --multi-database "${PARAM_MULTI_DATABASE}")
|
||||
list(APPEND PARAM_DB common)
|
||||
endif()
|
||||
|
||||
foreach(db ${PARAM_DB})
|
||||
list(APPEND ODB_ARGS -d "${db}")
|
||||
endforeach()
|
||||
|
||||
if(PARAM_GENERATE_QUERY)
|
||||
list(APPEND ODB_ARGS --generate-query)
|
||||
endif()
|
||||
|
||||
if(PARAM_GENERATE_SESSION)
|
||||
list(APPEND ODB_ARGS --generate-session)
|
||||
endif()
|
||||
|
||||
if(PARAM_GENERATE_SCHEMA)
|
||||
list(APPEND ODB_ARGS --generate-schema)
|
||||
endif()
|
||||
|
||||
if(PARAM_GENERATE_PREPARED)
|
||||
list(APPEND ODB_ARGS --generate-prepared)
|
||||
endif()
|
||||
|
||||
if(PARAM_SCHEMA_FORMAT)
|
||||
list(APPEND ODB_ARGS --schema-format "${PARAM_SCHEMA_FORMAT}")
|
||||
endif()
|
||||
|
||||
if(PARAM_SCHEMA_NAME)
|
||||
list(APPEND ODB_ARGS --schema-name "${PARAM_SCHEMA_NAME}")
|
||||
endif()
|
||||
|
||||
if(PARAM_TABLE_PREFIX)
|
||||
list(APPEND ODB_ARGS --table-prefix "${PARAM_TABLE_PREFIX}")
|
||||
endif()
|
||||
|
||||
if(PARAM_STANDARD)
|
||||
list(APPEND ODB_ARGS --std "${PARAM_STANDARD}")
|
||||
endif()
|
||||
|
||||
if(PARAM_SLOC_LIMIT)
|
||||
list(APPEND ODB_ARGS --sloc-limit "${PARAM_SLOC_LIMIT}")
|
||||
endif()
|
||||
|
||||
if(PARAM_HEADER_PROLOGUE)
|
||||
list(APPEND ODB_ARGS --hxx-prologue-file "${PARAM_HEADER_PROLOGUE}")
|
||||
endif()
|
||||
|
||||
if(PARAM_INLINE_PROLOGUE)
|
||||
list(APPEND ODB_ARGS --ixx-prologue-file "${PARAM_INLINE_PROLOGUE}")
|
||||
endif()
|
||||
|
||||
if(PARAM_SOURCE_PROLOGUE)
|
||||
list(APPEND ODB_ARGS --cxx-prologue-file "${PARAM_SOURCE_PROLOGUE}")
|
||||
endif()
|
||||
|
||||
if(PARAM_HEADER_EPILOGUE)
|
||||
list(APPEND ODB_ARGS --hxx-epilogue-file "${PARAM_HEADER_EPILOGUE}")
|
||||
endif()
|
||||
|
||||
if(PARAM_INLINE_EPILOGUE)
|
||||
list(APPEND ODB_ARGS --ixx-epilogue-file "${PARAM_INLINE_EPILOGUE}")
|
||||
endif()
|
||||
|
||||
if(PARAM_SOURCE_EPILOGUE)
|
||||
list(APPEND ODB_ARGS --cxx-epilogue-file "${PARAM_SOURCE_EPILOGUE}")
|
||||
endif()
|
||||
|
||||
if(PARAM_PROFILE)
|
||||
list(APPEND ODB_ARGS --profile "${PARAM_PROFILE}")
|
||||
endif()
|
||||
|
||||
list(APPEND ODB_ARGS --output-dir "${ODB_COMPILE_OUTPUT_DIR}")
|
||||
list(APPEND ODB_ARGS --hxx-suffix "${ODB_COMPILE_HEADER_SUFFIX}")
|
||||
list(APPEND ODB_ARGS --ixx-suffix "${ODB_COMPILE_INLINE_SUFFIX}")
|
||||
list(APPEND ODB_ARGS --cxx-suffix "${ODB_COMPILE_SOURCE_SUFFIX}")
|
||||
|
||||
if(PARAM_MULTI_DATABASE AND NOT "${ODB_COMPILE_FILE_SUFFIX}" MATCHES ".+:.+")
|
||||
set(osuffix "${ODB_COMPILE_FILE_SUFFIX}")
|
||||
set(ODB_COMPILE_FILE_SUFFIX)
|
||||
foreach(db ${PARAM_DB})
|
||||
if("${db}" MATCHES "common")
|
||||
list(APPEND ODB_COMPILE_FILE_SUFFIX "${db}:${osuffix}")
|
||||
else()
|
||||
list(APPEND ODB_COMPILE_FILE_SUFFIX "${db}:${osuffix}_${db}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
foreach(sfx ${ODB_COMPILE_FILE_SUFFIX})
|
||||
list(APPEND ODB_ARGS --odb-file-suffix "${sfx}")
|
||||
endforeach()
|
||||
|
||||
foreach(dir ${PARAM_INCLUDE} ${ODB_INCLUDE_DIRS})
|
||||
list(APPEND ODB_ARGS "-I${dir}")
|
||||
endforeach()
|
||||
|
||||
file(REMOVE_RECURSE "${ODB_COMPILE_OUTPUT_DIR}")
|
||||
file(MAKE_DIRECTORY "${ODB_COMPILE_OUTPUT_DIR}")
|
||||
|
||||
foreach(input ${PARAM_FILES})
|
||||
get_filename_component(fname "${input}" NAME_WE)
|
||||
set(outputs)
|
||||
|
||||
foreach(sfx ${ODB_COMPILE_FILE_SUFFIX})
|
||||
string(REGEX REPLACE ":.*$" "" pfx "${sfx}")
|
||||
string(REGEX REPLACE "^.*:" "" sfx "${sfx}")
|
||||
|
||||
if(NOT "${PARAM_MULTI_DATABASE}" MATCHES "static" OR NOT "${pfx}" MATCHES "common")
|
||||
set(output "${ODB_COMPILE_OUTPUT_DIR}/${fname}${sfx}${ODB_COMPILE_SOURCE_SUFFIX}")
|
||||
list(APPEND ${outvar} "${output}")
|
||||
list(APPEND outputs "${output}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(ODB_COMPILE_DEBUG)
|
||||
set(_msg "${ODB_EXECUTABLE} ${ODB_ARGS} ${input}")
|
||||
string(REPLACE ";" " " _msg "${_msg}")
|
||||
message(STATUS "${_msg}")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${outputs}
|
||||
COMMAND ${ODB_EXECUTABLE} ${ODB_ARGS} "${input}"
|
||||
DEPENDS "${input}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
VERBATIM)
|
||||
endforeach()
|
||||
|
||||
set(${outvar} ${${outvar}} PARENT_SCOPE)
|
||||
endfunction()
|
74
cmake/flexisip-config.h.in
Normal file
74
cmake/flexisip-config.h.in
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#cmakedefine CONFIG_DIR "${CONFIG_DIR}"
|
||||
#cmakedefine INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
|
||||
#cmakedefine ENABLE_SNMP 1
|
||||
#cmakedefine ENABLE_LIBODB_MYSQL 1
|
||||
#cmakedefine ENABLE_TRANSCODER 1
|
||||
#cmakedefine ENABLE_PRESENCE 1
|
||||
#cmakedefine ENABLE_CONFERENCE 1
|
||||
#cmakedefine ENABLE_B2BUA 1
|
||||
#cmakedefine ENABLE_ODBC 1
|
||||
#cmakedefine ENABLE_REDIS 1
|
||||
#cmakedefine ENABLE_SOCI 1
|
||||
#cmakedefine ENABLE_FLEXIAPI 1
|
||||
#cmakedefine ENABLE_MDNS 1
|
||||
#cmakedefine ENABLE_UNIT_TESTS 1
|
||||
#cmakedefine ENABLE_UNIT_TESTS_NGHTTP2ASIO 1
|
||||
|
||||
#cmakedefine HAVE_DATEHANDLER 1
|
||||
#cmakedefine HAVE_ARC4RANDOM 1
|
||||
#cmakedefine HAVE_SYS_PRCTL_H 1
|
||||
|
||||
/* Whether the liblinphone library has been linked. */
|
||||
#cmakedefine HAVE_LIBLINPHONE 1
|
||||
|
||||
/* Whether the liblinphone++ library has been linked. */
|
||||
#cmakedefine HAVE_LIBLINPHONECXX 1
|
||||
|
||||
#cmakedefine MEDIARELAY_SPECIFIC_FEATURES_ENABLED 1
|
||||
#cmakedefine MONOTONIC_CLOCK_REGISTRATIONS 1
|
||||
|
||||
// Anything that exits successfully without fuss
|
||||
#cmakedefine DUMMY_EXEC "${DUMMY_EXEC}"
|
||||
|
||||
#define SNMP_COMPANY_OID 10000
|
||||
|
||||
/* oRTP ABI version */
|
||||
#define ORTP_ABI_VERSION 9
|
||||
|
||||
/* oRTP rtp_session_set_reuseaddr availabled */
|
||||
#define ORTP_HAS_REUSEADDR 1
|
||||
|
||||
/* Default lib directory */
|
||||
#define DEFAULT_LIB_DIR "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/lib/flexisip"
|
||||
|
||||
/* Default log directory */
|
||||
#define DEFAULT_LOG_DIR "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/flexisip"
|
||||
|
||||
/* Default b2bua data dir */
|
||||
#define DEFAULT_B2BUA_DATA_DIR "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/flexisip/b2b"
|
||||
|
||||
/* Default directory for Flexisip's plugins */
|
||||
#define DEFAULT_PLUGINS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/flexisip/plugins"
|
||||
|
||||
#define BELR_GRAMMARS_DIR "${BELR_GRAMMARS_DIR}"
|
||||
|
||||
#define FIREBASE_GET_ACCESS_TOKEN_SCRIPT_PATH "${CMAKE_INSTALL_FULL_DATADIR}/flexisip/firebase_v1_get_access_token.py"
|
257
doc/xw.py
Executable file
257
doc/xw.py
Executable file
|
@ -0,0 +1,257 @@
|
|||
#!/bin/python
|
||||
|
||||
|
||||
import sys
|
||||
if sys.version_info.major < 3:
|
||||
print('ERROR: current Python version is {0}.{1}.{2} whereas Python 3 is required.'.format(
|
||||
sys.version_info[0], sys.version_info[1], sys.version_info[2]
|
||||
))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import urllib.request
|
||||
|
||||
|
||||
class Version:
|
||||
def __init__(self, major=0, minor=0, patch=0, branch=None, ncommit=0, _hash=None, fromStr=None):
|
||||
if fromStr is not None:
|
||||
m = re.match('^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-alpha|-beta|-pre)?((-[0-9]+)(-g[0-9a-f]+))?$', fromStr)
|
||||
if m is None:
|
||||
raise ValueError("'{0}' isn't a valid git describe string".format(fromStr))
|
||||
major = m.group(1)
|
||||
minor = m.group(2)
|
||||
patch = m.group(3)
|
||||
if m.group(4) is not None:
|
||||
branch = m.group(4)[1:]
|
||||
if m.group(5) is not None:
|
||||
ncommit = int(m.group(6)[1:])
|
||||
_hash = m.group(7)[2:]
|
||||
|
||||
if ncommit > 0 and _hash is None:
|
||||
raise ValueError('missing hash')
|
||||
if ncommit == 0 and _hash is not None:
|
||||
raise ValueError('missing or null commit number')
|
||||
|
||||
self.major = major
|
||||
self.minor = minor
|
||||
self.patch = patch
|
||||
self.branch = branch
|
||||
self.ncommit = ncommit
|
||||
self.hash = _hash
|
||||
|
||||
@property
|
||||
def short_version(self):
|
||||
return '{0}.{1}.{2}'.format(self.major, self.minor, self.patch)
|
||||
|
||||
@property
|
||||
def git_version(self):
|
||||
res = self.short_version
|
||||
if self.branch is not None:
|
||||
res += '-{0}'.format(self.branch)
|
||||
if self.ncommit > 0:
|
||||
res += '-{0}-g{1}'.format(self.ncommit, self.hash)
|
||||
return res
|
||||
|
||||
|
||||
class FlexisipProxy:
|
||||
def __init__(self, binaryPath):
|
||||
self.path = binaryPath
|
||||
self._version = None
|
||||
|
||||
@property
|
||||
def section_list(self):
|
||||
p = subprocess.Popen([self.path, '--list-sections'], stdout=subprocess.PIPE , stderr=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
return str(out, encoding='utf-8').rstrip('\n').split('\n')
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
if self._version is None:
|
||||
_version = self._get_version()
|
||||
return _version
|
||||
|
||||
def dump_section_doc(self, moduleName):
|
||||
p = subprocess.Popen([self.path, '--dump-format', 'xwiki', '--show-experimental', '--dump-default', moduleName], stdout=subprocess.PIPE , stderr=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
out = str(out, encoding='utf-8')
|
||||
# replace all the -- in the doc with {{{--}}} to escape xwiki autoformatting -- into striken
|
||||
return re.sub("--", "{{{--}}}", out)
|
||||
|
||||
def _get_version(self):
|
||||
p = subprocess.Popen([self.path, '-v'], stdout=subprocess.PIPE , stderr=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
out = str(out, encoding='utf-8')
|
||||
m = re.search('version: ([.a-z0-9-]+)', out)
|
||||
if m is None:
|
||||
raise RuntimeError("unexpected output of 'flexisip -v': [{0}]".format(out))
|
||||
version = m.group(1)
|
||||
try:
|
||||
return Version(fromStr=version)
|
||||
except ValueError:
|
||||
raise RuntimeError("invalid version string in output of 'flexisip -v' [{0}]".format(version))
|
||||
|
||||
|
||||
class XWikiProxy:
|
||||
class Credential:
|
||||
def __init__(self, user, password):
|
||||
self.user = user
|
||||
self.password = password
|
||||
|
||||
def to_base64(self):
|
||||
return base64.b64encode(bytes('{0}:{1}'.format(self.user, self.password), encoding='utf-8'))
|
||||
|
||||
def __init__(self, host, wikiname, credentials=None, cafile=None):
|
||||
m = re.fullmatch('(?:(http[s]?)\\://)?(\\S+)', host)
|
||||
if m is None:
|
||||
raise ValueError('invalid host [{0}]'.format(host))
|
||||
|
||||
self.scheme = m.group(1) if m.group(1) is not None else 'http'
|
||||
self.host = m.group(2)
|
||||
self.wikiname = wikiname
|
||||
self.credentials = credentials
|
||||
self.cafile = cafile
|
||||
|
||||
def update_page(self, path, content):
|
||||
uri = self._forge_page_uri(path)
|
||||
request = self._forge_http_request(uri, 'PUT', content)
|
||||
response = urllib.request.urlopen(request, cafile=self.cafile)
|
||||
if response.status not in (201, 202):
|
||||
raise RuntimeError('page creation or modification has failed' if response.status == 304 \
|
||||
else 'unexpected status code ({0})'.format(response.status))
|
||||
|
||||
def _forge_page_uri(self, path):
|
||||
uri = self._forge_root_uri()
|
||||
|
||||
scopepath = os.path.dirname(path)
|
||||
scopepath = scopepath.split('/')
|
||||
if scopepath[0] == '':
|
||||
del scopepath[0]
|
||||
for scopename in scopepath:
|
||||
uri += ('/spaces/' + self._escape(scopename))
|
||||
|
||||
pagename = os.path.basename(path)
|
||||
uri += ('/pages/' + self._escape(pagename))
|
||||
return uri
|
||||
|
||||
def _escape(self, string):
|
||||
return string.translate({0x20 : '%20'})
|
||||
|
||||
def _forge_root_uri(self):
|
||||
return self.scheme + '://' + self.host + XWikiProxy._apipath + '/wikis/' + self.wikiname
|
||||
|
||||
_apipath = '/xwiki/rest'
|
||||
|
||||
def _forge_http_request(self, uri, method, body):
|
||||
headers = { 'Content-Type': 'text/plain' }
|
||||
if self.credentials is not None:
|
||||
headers['Authorization'] = ('Basic ' + str(self.credentials.to_base64(), encoding='ascii'))
|
||||
return urllib.request.Request(uri, data=bytes(body, encoding='utf-8'), headers=headers, method=method)
|
||||
|
||||
|
||||
class DocWriter:
|
||||
def __init__(self, wikiProxy, fProxy):
|
||||
self.proxy = wikiProxy
|
||||
self.fProxy = fProxy
|
||||
self.documentRoot = '/Flexisip/A. Configuration Reference Guide'
|
||||
|
||||
def write_and_push(self):
|
||||
fProxy = FlexisipProxy(args.flexisip_binary)
|
||||
|
||||
childrenMacro = '{{children/}}'
|
||||
wiki.update_page(os.path.join(self.documentRoot, 'WebHome'), childrenMacro)
|
||||
wiki.update_page(os.path.join(self._get_version_page_path(), 'WebHome'), childrenMacro)
|
||||
wiki.update_page(os.path.join(self._get_version_page_path(), 'module/WebHome'), childrenMacro)
|
||||
|
||||
for section in fProxy.section_list:
|
||||
out = fProxy.dump_section_doc(section)
|
||||
|
||||
#add commit version on top of the file
|
||||
message = "// Documentation based on repostory git version commit {0} //\n\n".format(fProxy.version.git_version)
|
||||
out = message + out
|
||||
|
||||
path = self._section_name_to_page_path(section)
|
||||
|
||||
print("Updating page '{0}'".format(path))
|
||||
wiki.update_page(path, out)
|
||||
|
||||
def _section_name_to_page_path(self, module_name):
|
||||
return os.path.join(self._get_version_page_path(), *tuple(module_name.split('::')))
|
||||
|
||||
def _get_version_page_path(self):
|
||||
if fProxy.version.branch == 'alpha':
|
||||
version = 'master'
|
||||
elif fProxy.version.branch is None or fProxy.version.branch == 'beta':
|
||||
version = fProxy.version.short_version
|
||||
else:
|
||||
raise RuntimeError("Reference documentation isn't authorized to be pushed for this version of Flexisip [{0}]".format(fProxy.version.git_version))
|
||||
return os.path.join(self.documentRoot, version)
|
||||
|
||||
|
||||
class Settings:
|
||||
def __init__(self):
|
||||
self.section_name = 'main'
|
||||
self.host = ''
|
||||
self.wikiname = ''
|
||||
self.user = ''
|
||||
self.password = ''
|
||||
|
||||
def load(self, filename):
|
||||
import configparser
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_file)
|
||||
self.host = config.get(self.section_name, 'host', fallback=self.host)
|
||||
self.wikiname = config.get(self.section_name, 'wiki', fallback=self.wikiname)
|
||||
self.user = config.get(self.section_name, 'username')
|
||||
self.password = config.get(self.section_name, 'password')
|
||||
|
||||
def dump_example(self):
|
||||
return """[{section}]
|
||||
host=example.com
|
||||
wiki=public
|
||||
username=titi
|
||||
password=toto""".format(self.section_name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# parse cli arguments
|
||||
parser = argparse.ArgumentParser(description='Send the Flexisip documentation to the Wiki. All options passed override the config file.')
|
||||
parser.add_argument('-H', '--host' , help='the host to which we should send the documentation', default='wiki.linphone.org:8080')
|
||||
parser.add_argument('-w', '--wiki' , help='name of the wiki', default='public', dest='wikiname')
|
||||
parser.add_argument('-u', '--user' , help='the user to authenticate to the server', dest='config_user')
|
||||
parser.add_argument('-p', '--password' , help='the password to authenticate to the server', dest='config_password')
|
||||
parser.add_argument('--cafile' , help='file containing a set of trusted certificates', default=None)
|
||||
parser.add_argument('--flexisip-binary', help='location of the Flexisip executable to run', default='../OUTPUT/bin/flexisip')
|
||||
args = parser.parse_args()
|
||||
|
||||
# read from a configuration file for user/pass/host. This allows for out-of-cli specification of these parameters.
|
||||
settings = Settings()
|
||||
config_file = os.path.expanduser('~/.flexiwiki.x.cfg')
|
||||
if os.access(config_file, os.R_OK):
|
||||
settings.load(config_file)
|
||||
|
||||
# require a password for REST
|
||||
if args.config_password is not None:
|
||||
settings.password = args.config_password
|
||||
if args.config_user is not None:
|
||||
settings.user = args.config_user
|
||||
if args.host is not None:
|
||||
settings.host = args.host
|
||||
if args.wikiname is not None:
|
||||
settings.wikiname = args.wikiname
|
||||
|
||||
if settings.password == '':
|
||||
print("Please define a password using " + config_file + " or using the --password option")
|
||||
print("Example of " + config_file + ":")
|
||||
print(settings.dump_example())
|
||||
sys.exit(1)
|
||||
|
||||
credentials = XWikiProxy.Credential(settings.user, settings.password)
|
||||
wiki = XWikiProxy(settings.host, settings.wikiname, credentials=credentials, cafile=args.cafile)
|
||||
fProxy = FlexisipProxy(args.flexisip_binary)
|
||||
docWriter = DocWriter(wiki, fProxy)
|
||||
docWriter.write_and_push()
|
6
docker/Belledonne.repo
Normal file
6
docker/Belledonne.repo
Normal file
|
@ -0,0 +1,6 @@
|
|||
[Belledonne]
|
||||
name=Belledonne
|
||||
baseurl=https://linphone.org/snapshots/centos7
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
|
37
docker/Dockerfile
Normal file
37
docker/Dockerfile
Normal file
|
@ -0,0 +1,37 @@
|
|||
FROM centos:7
|
||||
MAINTAINER Jehan Monnier <jehan.monnier@linphone.org>
|
||||
|
||||
# Prepare the Belledonne's repository
|
||||
COPY docker/Belledonne.repo /etc/yum.repos.d/Belledonne.repo
|
||||
RUN yum -y install epel-release yum-downloadonly gdb
|
||||
RUN yum update -y
|
||||
|
||||
# Download rpm to be able to skip systemd's scripts
|
||||
RUN yum install -y --downloadonly --downloaddir=/opt bc-flexisip bc-flexisip-debuginfo bc-flexisip-jwe-auth-plugin
|
||||
RUN mv /opt/bc-flexisip*.rpm /tmp
|
||||
RUN rpm -i /opt/*.rpm
|
||||
RUN rpm -i --noscripts /tmp/bc-flexisip*.rpm
|
||||
#RUN echo '/tmp/core' > /proc/sys/kernel/core_pattern
|
||||
|
||||
RUN rm /opt/*.rpm
|
||||
|
||||
# Add it to the default path
|
||||
ENV PATH=$PATH:/opt/belledonne-communications/bin
|
||||
|
||||
WORKDIR /opt/belledonne-communications
|
||||
|
||||
# Generate a default configuration
|
||||
RUN flexisip --dump-default all > /etc/flexisip/flexisip.conf
|
||||
|
||||
VOLUME /etc/flexisip
|
||||
COPY docker/flexisip-entrypoint.sh /
|
||||
COPY docker/backtrace.gdb /
|
||||
RUN chmod a+x /flexisip-entrypoint.sh
|
||||
|
||||
# Script to wait db before launch flexisip [Licence Apache2]
|
||||
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
|
||||
RUN chmod +x /wait
|
||||
RUN yum clean all
|
||||
|
||||
ENTRYPOINT ["/flexisip-entrypoint.sh"]
|
||||
CMD flexisip
|
37
docker/Makefile
Normal file
37
docker/Makefile
Normal file
|
@ -0,0 +1,37 @@
|
|||
BASE_NAME=gitlab.linphone.org:4567/bc/public/flexisip
|
||||
$(eval GIT_DESCRIBE = $(shell sh -c "git describe"))
|
||||
DOCKER_TAG=$(BASE_NAME):$(GIT_DESCRIBE)
|
||||
DOCKER_FILE=flex-from-src
|
||||
|
||||
# We cannot use dockerfile's COPY outside build context
|
||||
# we use then flexisip directory as context for flex-from-src instead of docker directory
|
||||
|
||||
ifeq ($(DOCKER_FILE), flex-from-src)
|
||||
CONTEXT=..
|
||||
else
|
||||
CONTEXT=.
|
||||
endif
|
||||
|
||||
flexisip-build:
|
||||
docker build -f $(DOCKER_FILE) --pull --no-cache -t $(DOCKER_TAG) --rm $(CONTEXT)
|
||||
|
||||
flexisip-push:
|
||||
docker push $(DOCKER_TAG)
|
||||
|
||||
flexisip-clean:
|
||||
docker image rm $(DOCKER_TAG)
|
||||
|
||||
flexisip-deb-before:
|
||||
$(eval DOCKER_FILE = flex-from-deb)
|
||||
# forcing context to .
|
||||
# at the moment of the condition above being executed, $DOCKER_FILE doesn't have the right value
|
||||
$(eval CONTEXT = .)
|
||||
$(eval DOCKER_TAG = $(DOCKER_TAG)-deb)
|
||||
|
||||
flexisip-deb-build: flexisip-deb-before flexisip-build
|
||||
|
||||
flexisip-deb-push: flexisip-deb-before flexisip-push
|
||||
|
||||
flexisip-deb-clean: flexisip-deb-before flexisip-clean
|
||||
|
||||
.PHONY: flexisip-build
|
3
docker/backtrace.gdb
Normal file
3
docker/backtrace.gdb
Normal file
|
@ -0,0 +1,3 @@
|
|||
set debug-file-directory /opt/belledonne-communications/lib
|
||||
thread apply all bt full
|
||||
quit
|
103
docker/bc-dev-archlinux
Normal file
103
docker/bc-dev-archlinux
Normal file
|
@ -0,0 +1,103 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-archlinux:20250127_update_clang
|
||||
###############################################################################
|
||||
|
||||
FROM archlinux:base
|
||||
|
||||
LABEL org.opencontainers.image.authors="Belledonne Communications <flexisip@belledonne-communications.com>"
|
||||
|
||||
|
||||
# Configure locale
|
||||
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
|
||||
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
|
||||
|
||||
ENV SHELL=/bin/bash
|
||||
|
||||
# Update the system
|
||||
RUN pacman --noconfirm --noprogressbar --sync --refresh --sysupgrade \
|
||||
# Install development tools
|
||||
&& pacman --noconfirm --noprogressbar --sync \
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
doxygen \
|
||||
gcc \
|
||||
git \
|
||||
make \
|
||||
nasm \
|
||||
ninja \
|
||||
python-pip \
|
||||
python-pystache \
|
||||
python-six \
|
||||
sudo \
|
||||
locate \
|
||||
yasm \
|
||||
# Install Flexisip dependencies
|
||||
gsm \
|
||||
hiredis \
|
||||
jansson \
|
||||
jsoncpp \
|
||||
libsrtp \
|
||||
libxml2 \
|
||||
mariadb \
|
||||
mbedtls \
|
||||
net-snmp \
|
||||
openssl \
|
||||
opus \
|
||||
postgresql \
|
||||
speex \
|
||||
speexdsp \
|
||||
sqlite \
|
||||
xerces-c \
|
||||
# Dependencies of the B2BUA (and video tests)
|
||||
libvpx \
|
||||
# Test dependencies
|
||||
boost \
|
||||
redis \
|
||||
# Clean package cache
|
||||
&& pacman --noconfirm -Scc
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -m -s /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
ENTRYPOINT /bin/bash
|
||||
CMD "--login"
|
||||
|
||||
RUN sudo pacman --noconfirm --noprogressbar --sync \
|
||||
# Build-time dependencies of AUR packages
|
||||
fakeroot \
|
||||
debugedit \
|
||||
# Install AUR packages
|
||||
&& aurinstall() { \
|
||||
# https://wiki.archlinux.org/title/AUR_helpers
|
||||
local AURL="https://aur.archlinux.org/cgit/aur.git/snapshot/${1}.tar.gz"; \
|
||||
local WDIR="$(mktemp --directory)"; \
|
||||
cd "${WDIR}"; \
|
||||
curl --remote-name --fail --silent "${AURL}"; \
|
||||
tar --extract --file "${1}.tar.gz"; \
|
||||
cd "${WDIR}/${1}"; \
|
||||
makepkg --noconfirm --syncdeps --install --clean; \
|
||||
rm -rf "${WDIR}"; \
|
||||
} \
|
||||
# OpenID Connect dependency
|
||||
&& aurinstall cpp-jwt \
|
||||
&& sudo pacman --noconfirm --remove --nosave --recursive \
|
||||
fakeroot \
|
||||
debugedit \
|
||||
# Clean package cache
|
||||
&& sudo pacman --noconfirm -Scc
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
||||
|
||||
# Example build commands
|
||||
#
|
||||
# export CC=gcc
|
||||
# export CXX=g++
|
||||
# export BUILD_DIR_NAME="build.archlinux"
|
||||
# cmake -S . -B ./$BUILD_DIR_NAME -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="$PWD/$BUILD_DIR_NAME/install" -DENABLE_UNIT_TESTS=ON -DENABLE_UNIT_TESTS_NGHTTP2ASIO=OFF
|
||||
# cmake --build . --target install
|
98
docker/bc-dev-debian11
Normal file
98
docker/bc-dev-debian11
Normal file
|
@ -0,0 +1,98 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-debian11:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM debian:bullseye
|
||||
|
||||
MAINTAINER Anthony Gauchy <anthony.gauchy@belledonne-communications.com>
|
||||
|
||||
# Update
|
||||
RUN apt-get -y update \
|
||||
# Install common tools
|
||||
&& apt-get -y install sudo \
|
||||
vim \
|
||||
wget \
|
||||
file \
|
||||
# Install development tools
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
doxygen \
|
||||
g++ \
|
||||
gdb \
|
||||
git \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pip \
|
||||
yasm \
|
||||
# Install all dependencies needed for Flexisip
|
||||
libssl-dev \
|
||||
libboost-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libhiredis-dev \
|
||||
libjansson-dev \
|
||||
libjsoncpp-dev \
|
||||
libsqlite3-dev \
|
||||
libpq-dev \
|
||||
libmariadb-dev \
|
||||
libmariadb-dev-compat \
|
||||
libnghttp2-dev \
|
||||
libsnmp-dev \
|
||||
libxerces-c-dev \
|
||||
libsrtp2-dev \
|
||||
libgsm1-dev \
|
||||
libopus-dev \
|
||||
libmbedtls-dev \
|
||||
libspeex-dev \
|
||||
libspeexdsp-dev \
|
||||
libxml2-dev \
|
||||
redis-server \
|
||||
# Dependencies of the B2BUA
|
||||
libvpx-dev \
|
||||
# Dependencies of the tester
|
||||
mariadb-server \
|
||||
# Dependencies of clang test coverage
|
||||
llvm \
|
||||
# Clean
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get -y clean
|
||||
|
||||
# Install CMake 3.22.6
|
||||
COPY cmake_install.sh .
|
||||
RUN ./cmake_install.sh 3.22.6 \
|
||||
&& rm cmake_install.sh \
|
||||
&& apt-get -y remove cmake
|
||||
|
||||
# Install libnghttp2_asio
|
||||
RUN wget https://github.com/nghttp2/nghttp2/releases/download/v1.43.0/nghttp2-1.43.0.tar.bz2 && \
|
||||
tar xf nghttp2-1.43.0.tar.bz2 && \
|
||||
cd nghttp2-1.43.0 && \
|
||||
./configure --prefix=/usr/local --disable-examples --disable-python-bindings --enable-lib-only --enable-asio-lib && \
|
||||
make && \
|
||||
sudo make -C src install && \
|
||||
cd - && \
|
||||
rm -rf nghttp2-1.43.0.tar.bz2 nghttp2-1.43.0
|
||||
|
||||
# Dependency of clang test coverage (converts lcov format to cobertura so Gitlab can display code coverage for files in diff view)
|
||||
RUN pip install lcov_cobertura
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch for 'bc' user
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# Install python3 modules.
|
||||
# This must be done as 'bc' user because some python modules are installed into /usr/local/lib when pip is invoked
|
||||
# as root, and rpmbuild prevent python from seaching its modules in this prefix. Using 'bc' user make the python
|
||||
# modules to be installed into /home/bc/.local/bin.
|
||||
RUN python3 -m pip install --user pystache six
|
||||
ENV PATH=$PATH:/home/bc/.local/bin
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
98
docker/bc-dev-debian12
Normal file
98
docker/bc-dev-debian12
Normal file
|
@ -0,0 +1,98 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-debian12:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM debian:12
|
||||
|
||||
MAINTAINER Thibault Lemaire <thibault.lemaire@belledonne-communications.com>
|
||||
|
||||
# Update
|
||||
RUN apt-get -y update \
|
||||
&& apt-get -y install \
|
||||
# Install common tools
|
||||
sudo \
|
||||
vim \
|
||||
wget \
|
||||
file \
|
||||
# Install development tools
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
doxygen \
|
||||
g++ \
|
||||
gdb \
|
||||
git \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pystache \
|
||||
python3-six \
|
||||
yasm \
|
||||
# Install all dependencies needed for Flexisip
|
||||
libssl-dev \
|
||||
libboost-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libhiredis-dev \
|
||||
libjansson-dev \
|
||||
libjsoncpp-dev \
|
||||
libnghttp2-dev \
|
||||
libsqlite3-dev \
|
||||
libpq-dev \
|
||||
libmariadb-dev \
|
||||
libmariadb-dev-compat \
|
||||
libsnmp-dev \
|
||||
libxerces-c-dev \
|
||||
libsrtp2-dev \
|
||||
libgsm1-dev \
|
||||
libopus-dev \
|
||||
libmbedtls-dev \
|
||||
libspeex-dev \
|
||||
libspeexdsp-dev \
|
||||
libxml2-dev \
|
||||
redis-server \
|
||||
# Dependencies of the B2BUA
|
||||
libvpx-dev \
|
||||
# Dependencies of the tester
|
||||
mariadb-server \
|
||||
# Dependencies of CPack (to build the .deb)
|
||||
dpkg-dev \
|
||||
# Clean up
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get -y clean
|
||||
|
||||
# Install libnghttp2_asio
|
||||
# Downloading the gz source and not bz2 to avoid installing bzip2.
|
||||
# nghttp2-asio has been moved out of nghttp2 from v1.52.0 onward.
|
||||
RUN wget https://github.com/nghttp2/nghttp2/releases/download/v1.51.0/nghttp2-1.51.0.tar.gz && \
|
||||
tar xf nghttp2-1.51.0.tar.gz && \
|
||||
cd nghttp2-1.51.0 && \
|
||||
./configure --prefix=/usr/local --disable-examples --disable-python-bindings --enable-lib-only --enable-asio-lib && \
|
||||
make -j4 && \
|
||||
sudo make -C src install && \
|
||||
cd - && \
|
||||
rm -rf nghttp2-1.51.0.tar.gz nghttp2-1.51.0
|
||||
|
||||
# Configure user 'bc'
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch to user 'bc'
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
||||
|
||||
|
||||
# Example build commands
|
||||
#
|
||||
# cd flexisip/
|
||||
# export CC=gcc
|
||||
# export CXX=g++
|
||||
# export BUILD_DIR_NAME="build.debian12"
|
||||
# cmake -S . -B ./$BUILD_DIR_NAME -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="$PWD/$BUILD_DIR_NAME/install" -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON -DENABLE_UNIT_TESTS=ON
|
||||
# cd $BUILD_DIR_NAME
|
||||
# cmake --build . --target install
|
||||
# LSAN_OPTIONS="suppressions=../sanitizer_ignore.txt" bin/flexisip_tester --resource-dir "../tester/"
|
51
docker/bc-dev-minimal
Normal file
51
docker/bc-dev-minimal
Normal file
|
@ -0,0 +1,51 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-minimal:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM debian:12
|
||||
|
||||
MAINTAINER Thibault Lemaire <thibault.lemaire@belledonne-communications.com>
|
||||
|
||||
# Update
|
||||
RUN apt-get -y update \
|
||||
&& apt-get -y install \
|
||||
# Install build deps
|
||||
ccache \
|
||||
cmake \
|
||||
g++ \
|
||||
git \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pystache \
|
||||
python3-six \
|
||||
yasm \
|
||||
# Install all dependencies needed for Flexisip
|
||||
libssl-dev \
|
||||
libnghttp2-dev \
|
||||
# Clean up
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get -y clean
|
||||
|
||||
# Configure user 'bc'
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch to user 'bc'
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
||||
|
||||
|
||||
# Example build commands
|
||||
#
|
||||
# cd flexisip/
|
||||
# export CC=gcc
|
||||
# export CXX=g++
|
||||
# export BUILD_DIR_NAME="build.minimal"
|
||||
# cmake -S . -B ./$BUILD_DIR_NAME -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="$PWD/$BUILD_DIR_NAME/install" -DCMAKE_PREFIX_PATH=/usr/local -DENABLE_PRESENCE=OFF -DENABLE_REDIS=OFF -DENABLE_SNMP=OFF -DENABLE_SOCI=OFF -DENABLE_TRANSCODER=OFF -DENABLE_MDNS=OFF -DENABLE_EXTERNAL_AUTH_PLUGIN=OFF -DENABLE_JWE_AUTH_PLUGIN=OFF -DENABLE_CONFERENCE=OFF -DENABLE_SOCI_POSTGRESQL_BACKEND=OFF -DENABLE_B2BUA=OFF -DENABLE_UNIT_TESTS=OFF
|
||||
# cd $BUILD_DIR_NAME
|
||||
# cmake --build . --target install
|
99
docker/bc-dev-rocky8
Normal file
99
docker/bc-dev-rocky8
Normal file
|
@ -0,0 +1,99 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-rocky8:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM rockylinux:8
|
||||
|
||||
MAINTAINER Anthony Gauchy <anthony.gauchy@belledonne-communications.com>
|
||||
|
||||
# Install common general tools
|
||||
RUN dnf install -y sudo vim wget
|
||||
|
||||
# Configure additional repositories
|
||||
RUN dnf install -y epel-release && \
|
||||
sudo dnf install -y dnf-plugins-core && \
|
||||
sudo dnf config-manager -y --set-enabled powertools
|
||||
|
||||
# Update
|
||||
RUN sudo dnf makecache --refresh && dnf -y update
|
||||
|
||||
# Install development tools
|
||||
RUN sudo dnf -y install \
|
||||
bzip2 \
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
c-ares-devel \
|
||||
doxygen \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
gdb \
|
||||
git \
|
||||
libasan \
|
||||
libev-devel \
|
||||
libubsan \
|
||||
libuv-devel \
|
||||
llvm \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pip \
|
||||
rpm-build \
|
||||
yasm \
|
||||
zlib-devel \
|
||||
# Install all dependencies needed for Flexisip
|
||||
openssl-devel \
|
||||
boost-devel \
|
||||
hiredis-devel \
|
||||
jansson-devel \
|
||||
libsqlite3x-devel \
|
||||
libpq-devel \
|
||||
mariadb-devel \
|
||||
nghttp2 \
|
||||
libnghttp2-devel \
|
||||
net-snmp-devel \
|
||||
xerces-c-devel \
|
||||
gsm-devel \
|
||||
opus-devel \
|
||||
mbedtls-devel \
|
||||
speex-devel \
|
||||
speexdsp-devel \
|
||||
libxml2-devel \
|
||||
redis \
|
||||
# Dependencies of the B2BUA
|
||||
libvpx-devel \
|
||||
jsoncpp-devel \
|
||||
# Dependencies of the tester
|
||||
mariadb-server \
|
||||
&& dnf -y clean all
|
||||
|
||||
# Install CMake 3.22.6
|
||||
COPY cmake_install.sh .
|
||||
RUN ./cmake_install.sh 3.22.6 \
|
||||
&& rm cmake_install.sh \
|
||||
&& dnf -y remove cmake
|
||||
|
||||
# Install libnghttp2_asio 1.39.2
|
||||
COPY libnghttp2_asio_install.sh .
|
||||
RUN ./libnghttp2_asio_install.sh 1.39.2 && rm libnghttp2_asio_install.sh
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch to 'bc' user
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# Install python3 modules.
|
||||
# This must be done as user 'bc' because python modules are installed in /usr/local/lib when pip is invoked
|
||||
# as root, and rpmbuild prevents python from searching its modules in this prefix. Installing with user 'bc' puts
|
||||
# the modules in /home/bc/.local/bin.
|
||||
RUN python3 -m pip install --user pystache six
|
||||
ENV PATH=$PATH:/home/bc/.local/bin
|
||||
|
||||
ENV PS1='\[\e[34m\]\u@bc-dev-rocky8>\[\e[0m\] '
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
112
docker/bc-dev-rocky9
Normal file
112
docker/bc-dev-rocky9
Normal file
|
@ -0,0 +1,112 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-rocky9:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM rockylinux:9
|
||||
|
||||
MAINTAINER Thibault Lemaire <Thibault.lemaire@belledonne-communications.com>
|
||||
|
||||
# Install common general tools
|
||||
RUN dnf install -y sudo vim wget
|
||||
|
||||
# Configure additional repositories
|
||||
RUN dnf install -y \
|
||||
epel-release \
|
||||
dnf-plugins-core \
|
||||
# Code Ready Builder
|
||||
&& dnf config-manager -y --set-enabled crb
|
||||
|
||||
# Update
|
||||
RUN dnf makecache --refresh \
|
||||
&& dnf -y update \
|
||||
# Install development tools
|
||||
&& dnf -y install \
|
||||
bzip2 \
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
c-ares-devel \
|
||||
doxygen \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
gdb \
|
||||
git \
|
||||
libasan \
|
||||
libev-devel \
|
||||
libubsan \
|
||||
libuv-devel \
|
||||
llvm \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pip \
|
||||
rpm-build \
|
||||
yasm \
|
||||
zlib-devel \
|
||||
# Install all dependencies needed for Flexisip
|
||||
openssl-devel \
|
||||
boost-devel \
|
||||
hiredis-devel \
|
||||
jansson-devel \
|
||||
libsqlite3x-devel \
|
||||
libpq-devel \
|
||||
mariadb-devel \
|
||||
nghttp2 \
|
||||
libnghttp2-devel \
|
||||
net-snmp-devel \
|
||||
xerces-c-devel \
|
||||
gsm-devel \
|
||||
opus-devel \
|
||||
mbedtls-devel \
|
||||
speex-devel \
|
||||
speexdsp-devel \
|
||||
libxml2-devel \
|
||||
redis \
|
||||
# Dependencies of the B2BUA
|
||||
libvpx-devel \
|
||||
jsoncpp-devel \
|
||||
# Dependencies of the tester
|
||||
mariadb-server \
|
||||
&& dnf -y clean all
|
||||
|
||||
# Install CMake 3.22.6
|
||||
COPY cmake_install.sh .
|
||||
RUN ./cmake_install.sh 3.22.6 \
|
||||
&& rm cmake_install.sh \
|
||||
&& dnf -y remove cmake
|
||||
|
||||
# Install libnghttp2_asio 1.39.2
|
||||
COPY libnghttp2_asio_install.sh .
|
||||
RUN ./libnghttp2_asio_install.sh 1.39.2
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch to 'bc' user
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# Install python3 modules.
|
||||
# This must be done as user 'bc' because python modules are installed in /usr/local/lib when pip is invoked
|
||||
# as root, and rpmbuild prevents python from searching its modules in this prefix. Installing with user 'bc' puts
|
||||
# the modules in /home/bc/.local/bin.
|
||||
RUN python3 -m pip install --user pystache six
|
||||
ENV PATH=$PATH:/home/bc/.local/bin
|
||||
|
||||
ENV PS1='\[\e[34m\]\u@bc-dev-rocky9>\[\e[0m\] '
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
||||
|
||||
|
||||
# Example build commands
|
||||
#
|
||||
# export CC=gcc
|
||||
# export CXX=g++
|
||||
# export BUILD_DIR_NAME="build.rocky9"
|
||||
# cd flexisip/
|
||||
# cmake -S . -B ./$BUILD_DIR_NAME -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="$PWD/$BUILD_DIR_NAME/install" -DENABLE_UNIT_TESTS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON
|
||||
# cd $BUILD_DIR_NAME
|
||||
# cmake --build . --target install
|
82
docker/bc-dev-ubuntu-22-04
Normal file
82
docker/bc-dev-ubuntu-22-04
Normal file
|
@ -0,0 +1,82 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-ubuntu-22-04:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM ubuntu:22.04
|
||||
|
||||
MAINTAINER Anthony Gauchy <anthony.gauchy@belledonne-communications.com>
|
||||
|
||||
# Update
|
||||
RUN apt-get -y update \
|
||||
# Install common tools
|
||||
&& apt-get -y install sudo \
|
||||
vim \
|
||||
wget \
|
||||
file \
|
||||
# Install development tools
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
doxygen \
|
||||
elfutils \
|
||||
g++ \
|
||||
gdb \
|
||||
git \
|
||||
llvm \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pip \
|
||||
yasm \
|
||||
# Install all dependencies needed for Flexisip
|
||||
libssl-dev \
|
||||
libboost-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libhiredis-dev \
|
||||
libjansson-dev \
|
||||
libjsoncpp-dev \
|
||||
libsqlite3-dev \
|
||||
libpq-dev \
|
||||
libmariadb-dev \
|
||||
libmariadb-dev-compat \
|
||||
mariadb-server \
|
||||
libnghttp2-dev \
|
||||
libsnmp-dev \
|
||||
libxerces-c-dev \
|
||||
libsrtp2-dev \
|
||||
libgsm1-dev \
|
||||
libopus-dev \
|
||||
libmbedtls-dev \
|
||||
libspeex-dev \
|
||||
libspeexdsp-dev \
|
||||
libxml2-dev \
|
||||
redis-server \
|
||||
# Dependencies of the B2BUA
|
||||
libvpx-dev \
|
||||
# Clean
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get -y clean
|
||||
|
||||
# Install libnghttp2_asio 1.43.0
|
||||
COPY libnghttp2_asio_install.sh .
|
||||
RUN ./libnghttp2_asio_install.sh 1.43.0 && rm libnghttp2_asio_install.sh
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch for 'bc' user
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# Install python3 modules.
|
||||
# This must be done as 'bc' user because some python modules are installed into /usr/local/lib when pip is invoked
|
||||
# as root, and rpmbuild prevent python from seaching its modules in this prefix. Using 'bc' user make the python
|
||||
# modules to be installed into /home/bc/.local/bin.
|
||||
RUN python3 -m pip install --user pystache six
|
||||
ENV PATH=$PATH:/home/bc/.local/bin
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
77
docker/bc-dev-ubuntu-24-04
Normal file
77
docker/bc-dev-ubuntu-24-04
Normal file
|
@ -0,0 +1,77 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-ubuntu-24-04:20240911_remove_protobuf
|
||||
###############################################################################
|
||||
|
||||
FROM ubuntu:24.04
|
||||
RUN userdel -r ubuntu
|
||||
|
||||
MAINTAINER Anthony Gauchy <anthony.gauchy@belledonne-communications.com>
|
||||
|
||||
# Update
|
||||
RUN apt-get -y update \
|
||||
# Install common tools
|
||||
&& apt-get -y install sudo \
|
||||
vim \
|
||||
wget \
|
||||
file \
|
||||
# Install development tools
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
doxygen \
|
||||
elfutils \
|
||||
g++ \
|
||||
gdb \
|
||||
git \
|
||||
llvm \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pystache \
|
||||
python3-six \
|
||||
yasm \
|
||||
# Install all dependencies needed for Flexisip
|
||||
libssl-dev \
|
||||
libboost-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libhiredis-dev \
|
||||
libjansson-dev \
|
||||
libjsoncpp-dev \
|
||||
libsqlite3-dev \
|
||||
libpq-dev \
|
||||
libmariadb-dev \
|
||||
libmariadb-dev-compat \
|
||||
mariadb-server \
|
||||
libnghttp2-dev \
|
||||
libsnmp-dev \
|
||||
libxerces-c-dev \
|
||||
libsrtp2-dev \
|
||||
libgsm1-dev \
|
||||
libopus-dev \
|
||||
libmbedtls-dev \
|
||||
libspeex-dev \
|
||||
libspeexdsp-dev \
|
||||
libxml2-dev \
|
||||
redis-server \
|
||||
# Dependencies of the B2BUA
|
||||
libvpx-dev \
|
||||
# Clean
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get -y clean
|
||||
|
||||
# Install libnghttp2_asio 1.51.0
|
||||
COPY libnghttp2_asio_install.sh .
|
||||
RUN ./libnghttp2_asio_install.sh 1.51.0 && rm libnghttp2_asio_install.sh
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Switch for 'bc' user
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# CVE-2022-24765, from git 2.35.2 onward
|
||||
RUN git config --global --add safe.directory *
|
30
docker/build-and-push-ci-image.sh
Executable file
30
docker/build-and-push-ci-image.sh
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (C) 2010-2023 Belledonne Communications SARL
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Small helper script to build and push a Docker image used for CI.
|
||||
# Should be called from within the docker/ folder, and takes only one argument: the Dockerfile to build.
|
||||
# You should update the tag in the Dockerfile before running this script.
|
||||
# Set {BUILD,RUN,PUSH} env vars to {en,dis}able the corresponding steps
|
||||
#
|
||||
# Example usage:
|
||||
# BUILD=false RUN=true ./build-and-push-ci-image.sh bc-dev-ubuntu-22-04
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
DOCKERFILE=$1
|
||||
BUILD=${BUILD:-true}
|
||||
RUN=${RUN:-false}
|
||||
PUSH=${PUSH:-false}
|
||||
|
||||
IMAGE_TAG=$(grep --only-matching --regexp="gitlab.linphone.org.*" $DOCKERFILE | head -1)
|
||||
|
||||
if $BUILD; then
|
||||
docker build --pull --network=host -t $IMAGE_TAG -f $DOCKERFILE .
|
||||
fi
|
||||
if $RUN; then
|
||||
docker run --rm -it -v $(pwd)/..:/home/bc/flexisip $IMAGE_TAG /bin/bash
|
||||
fi
|
||||
if $PUSH; then
|
||||
docker push $IMAGE_TAG
|
||||
fi
|
32
docker/cmake_install.sh
Executable file
32
docker/cmake_install.sh
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
script_name="$(basename $0)"
|
||||
|
||||
if [ $# -ne 1 ]
|
||||
then
|
||||
echo "usage: $script_name <cmake_version>" 1>&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
version="$1"
|
||||
archive="cmake-${version}.tar.gz"
|
||||
url="https://github.com/Kitware/CMake/releases/download/v${version}/${archive}"
|
||||
workdir=$(realpath "$PWD/.tmp-$(date '+%Y%m%d-%H%M%S')")
|
||||
srcdir="${workdir}/cmake-${version}"
|
||||
bindir="${workdir}/build"
|
||||
|
||||
mkdir -p $bindir
|
||||
pushd $workdir
|
||||
|
||||
wget $url \
|
||||
&& tar xf $archive \
|
||||
|| exit 1
|
||||
|
||||
cd $bindir \
|
||||
&& cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local $srcdir \
|
||||
&& cmake --build . \
|
||||
&& sudo cmake --build . --target install \
|
||||
|| exit 1
|
||||
|
||||
popd
|
||||
rm -rf $workdir
|
32
docker/flex-from-deb
Normal file
32
docker/flex-from-deb
Normal file
|
@ -0,0 +1,32 @@
|
|||
FROM debian:9
|
||||
MAINTAINER Jehan Monnier <jehan.monnier@linphone.org>
|
||||
|
||||
# Prepare dependencies
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y xsdcxx gdb libmariadbclient18
|
||||
|
||||
# Get flexisip package
|
||||
COPY DEBS/*.deb DEBS/*.ddeb deb-packages/
|
||||
RUN apt-get install -y /deb-packages/*
|
||||
RUN rm -rf /deb-packages
|
||||
|
||||
# Add it to the default path
|
||||
ENV PATH=$PATH:/opt/belledonne-communications/bin
|
||||
|
||||
WORKDIR /opt/belledonne-communications
|
||||
|
||||
# Generate a default configuration
|
||||
RUN flexisip --dump-default all > /etc/flexisip/flexisip.conf
|
||||
|
||||
VOLUME /etc/opt/belledonne-communications/flexisip
|
||||
VOLUME /var/opt/belledonne-communications/log/flexisip
|
||||
COPY flexisip-entrypoint.sh /
|
||||
COPY backtrace.gdb /
|
||||
RUN chmod a+x /flexisip-entrypoint.sh
|
||||
|
||||
# Script to wait db before launch flexisip [Licence Apache2]
|
||||
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
|
||||
RUN chmod +x /wait
|
||||
|
||||
ENTRYPOINT ["/flexisip-entrypoint.sh"]
|
||||
CMD flexisip
|
50
docker/flex-from-src
Normal file
50
docker/flex-from-src
Normal file
|
@ -0,0 +1,50 @@
|
|||
FROM gitlab.linphone.org:4567/bc/public/flexisip/bc-dev-debian10:20220708_add_jsoncpp
|
||||
MAINTAINER Jehan Monnier <jehan.monnier@linphone.org>
|
||||
|
||||
ARG sanitizer=OFF
|
||||
ARG build_type=Debug
|
||||
|
||||
# Some Python modules are available as 'bc' user only.
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
RUN sudo apt-get install -y iptables
|
||||
|
||||
# Get source code
|
||||
COPY --chown=bc:bc . flexisip/
|
||||
|
||||
# Configure & build
|
||||
RUN cd flexisip \
|
||||
&& rm -rf work && mkdir work \
|
||||
&& cmake -S . -B work -G Ninja -DCMAKE_BUILD_TYPE=${build_type} -DENABLE_SANITIZERS=${sanitizer} -DCMAKE_INSTALL_PREFIX=/opt/belledonne-communications -DSYSCONF_INSTALL_DIR=/etc \
|
||||
&& cmake --build work \
|
||||
&& sudo cmake --build work --target install
|
||||
|
||||
# Cleanup
|
||||
RUN rm -rf flexisip
|
||||
|
||||
# Switch to 'root' user
|
||||
USER root
|
||||
WORKDIR /root
|
||||
|
||||
# Add Flexisip bindir to the default path
|
||||
ENV PATH=/opt/belledonne-communications/bin:$PATH
|
||||
|
||||
# Create volumes for Flexisip configuration and logs
|
||||
RUN mkdir -p /var/opt/belledonne-communications/flexisip /etc/flexisip /home/cores
|
||||
VOLUME /etc/flexisip
|
||||
VOLUME /var/opt/belledonne-communications/log/flexisip
|
||||
|
||||
COPY docker/flexisip-entrypoint.sh /
|
||||
COPY docker/backtrace.gdb /
|
||||
RUN chmod a+x /flexisip-entrypoint.sh
|
||||
|
||||
# Script to wait db before launch flexisip [Licence Apache2]
|
||||
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
|
||||
RUN chmod +x /wait
|
||||
|
||||
# Generate a default configuration
|
||||
RUN flexisip --dump-default all > /etc/flexisip/flexisip.conf
|
||||
|
||||
ENTRYPOINT ["/flexisip-entrypoint.sh"]
|
||||
CMD flexisip
|
30
docker/flexisip-entrypoint.sh
Normal file
30
docker/flexisip-entrypoint.sh
Normal file
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
ulimit -c unlimited*
|
||||
set -- flexisip "$@"
|
||||
|
||||
# Wait for needed container startup
|
||||
/wait || exit $?
|
||||
|
||||
echo "Flexisip docker params : $*"
|
||||
|
||||
if [[ $@ == *"--server"* ]]; then
|
||||
echo "--server param found, starting only one Flexisip instance"
|
||||
"$@" &
|
||||
else
|
||||
echo "Server param not found, starting 3 Flexisip instances (proxy, presence, conference)"
|
||||
( "$@" --server proxy 2>&1| tee /var/opt/belledonne-communications/log/flexisip/flexisip_proxy_stdout.log ) &
|
||||
( "$@" --server presence 2>&1| tee /var/opt/belledonne-communications/log/flexisip/flexisip_presence_stdout.log ) &
|
||||
( "$@" --server conference 2>&1| tee /var/opt/belledonne-communications/log/flexisip/flexisip_conference_stdout.log ) &
|
||||
fi
|
||||
|
||||
wait -n
|
||||
|
||||
echo "At least one server crashed, stopping every sub process that is still alive"
|
||||
pkill -P $$
|
||||
|
||||
# coredump management, used in unit tests
|
||||
# we execute gdb on each coredump, with the options given in backtrace.gdb file
|
||||
# we search in /root because it's the workdir set in Dockerfile and because by default our coredumps are generated by default in the working directory
|
||||
if [ -n "$(find /root -type f -name "core*")" ]; then
|
||||
find /root -type f -name "core*" | xargs -L1 gdb flexisip -x /backtrace.gdb;
|
||||
fi
|
22
docker/libnghttp2_asio_install.sh
Executable file
22
docker/libnghttp2_asio_install.sh
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
script_name="$(basename $0)"
|
||||
|
||||
if [ $# -ne 1 ]
|
||||
then
|
||||
echo "usage: $script_name <libnghttp2_asio_version>" 1>&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
version="$1"
|
||||
srcdir=nghttp2-${version}
|
||||
srcpkg=${srcdir}.tar.gz
|
||||
bindir=build_libnghttp2_asio
|
||||
|
||||
wget https://github.com/nghttp2/nghttp2/releases/download/v${version}/${srcpkg} && \
|
||||
tar -xf ${srcpkg} && \
|
||||
|
||||
mkdir ${bindir} && cmake -S ${srcdir} -B ${bindir} -GNinja -DENABLE_ASIO_LIB=ON && \
|
||||
cmake --build ${bindir} --target install && \
|
||||
|
||||
rm -rf ${srcpkg} ${srcdir} ${bindir}
|
82
docker/rpmmacros
Normal file
82
docker/rpmmacros
Normal file
|
@ -0,0 +1,82 @@
|
|||
#
|
||||
# Macros for cmake
|
||||
#
|
||||
%_cmake_lib_suffix64 -DLIB_SUFFIX=64
|
||||
%_cmake_skip_rpath -DCMAKE_SKIP_RPATH:BOOL=ON
|
||||
%_cmake_version 3.2.3
|
||||
%__cmake cmake
|
||||
|
||||
# - Set default compile flags
|
||||
# - CMAKE_*_FLAGS_RELEASE are added *after* the *FLAGS environment variables
|
||||
# and default to -O3 -DNDEBUG. Strip the -O3 so we can override with *FLAGS
|
||||
# - Turn on verbose makefiles so we can see and verify compile flags
|
||||
# - Set default install prefixes and library install directories
|
||||
# - Turn on shared libraries by default
|
||||
%cmake \
|
||||
CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS ; \
|
||||
CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS ; \
|
||||
FFLAGS="${FFLAGS:-%optflags%{?_fmoddir: -I%_fmoddir}}" ; export FFLAGS ; \
|
||||
FCFLAGS="${FCFLAGS:-%optflags%{?_fmoddir: -I%_fmoddir}}" ; export FCFLAGS ; \
|
||||
%{?__global_ldflags:LDFLAGS="${LDFLAGS:-%__global_ldflags}" ; export LDFLAGS ;} \
|
||||
%__cmake \\\
|
||||
-DCMAKE_C_FLAGS_RELEASE:STRING="-DNDEBUG" \\\
|
||||
-DCMAKE_CXX_FLAGS_RELEASE:STRING="-DNDEBUG" \\\
|
||||
-DCMAKE_Fortran_FLAGS_RELEASE:STRING="-DNDEBUG" \\\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \\\
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} \\\
|
||||
-DINCLUDE_INSTALL_DIR:PATH=%{_includedir} \\\
|
||||
-DLIB_INSTALL_DIR:PATH=%{_libdir} \\\
|
||||
-DSYSCONF_INSTALL_DIR:PATH=%{_sysconfdir} \\\
|
||||
-DSHARE_INSTALL_PREFIX:PATH=%{_datadir} \\\
|
||||
%if "%{?_lib}" == "lib64" \
|
||||
%{?_cmake_lib_suffix64} \\\
|
||||
%endif \
|
||||
-DBUILD_SHARED_LIBS:BOOL=ON
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Macros for systemd
|
||||
#
|
||||
|
||||
%_unitdir /lib/systemd/system
|
||||
|
||||
|
||||
%systemd_requires \
|
||||
Requires(post): systemd \
|
||||
Requires(preun): systemd \
|
||||
Requires(postun): systemd \
|
||||
%{nil}
|
||||
|
||||
|
||||
%systemd_post() \
|
||||
if [ $1 -eq 1 ] ; then \
|
||||
# Initial installation \
|
||||
systemctl preset %{?*} >/dev/null 2>&1 || : \
|
||||
fi \
|
||||
%{nil}
|
||||
|
||||
|
||||
%systemd_preun() \
|
||||
if [ $1 -eq 0 ] ; then \
|
||||
# Package removal, not upgrade \
|
||||
systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \
|
||||
systemctl stop %{?*} > /dev/null 2>&1 || : \
|
||||
fi \
|
||||
%{nil}
|
||||
|
||||
|
||||
%systemd_postun() \
|
||||
systemctl daemon-reload >/dev/null 2>&1 || : \
|
||||
%{nil}
|
||||
|
||||
|
||||
%systemd_postun_with_restart() \
|
||||
systemctl daemon-reload >/dev/null 2>&1 || : \
|
||||
if [ $1 -ge 1 ] ; then \
|
||||
# Package upgrade, not uninstall \
|
||||
systemctl try-restart %{?*} >/dev/null 2>&1 || : \
|
||||
fi \
|
||||
%{nil}
|
||||
|
||||
|
25
flake.lock
generated
Normal file
25
flake.lock
generated
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1687886075,
|
||||
"narHash": "sha256-PeayJDDDy+uw1Ats4moZnRdL1OFuZm1Tj+KiHlD67+o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a565059a348422af5af9026b5174dc5c0dcefdae",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
51
flake.nix
Normal file
51
flake.nix
Normal file
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
description = "A very basic flake";
|
||||
|
||||
outputs = { self, nixpkgs }: {
|
||||
|
||||
devShells.x86_64-linux.default = import ./shell.nix {
|
||||
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||
};
|
||||
devShells.x86_64-linux.embedded-like = with nixpkgs.legacyPackages.x86_64-linux;
|
||||
/* CC=gcc CXX=g++ BUILD_DIR_NAME="build" cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -S . -B ./$BUILD_DIR_NAME -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="$PWD/$BUILD_DIR_NAME/install"
|
||||
-DENABLE_PRESENCE=ON
|
||||
-DENABLE_REDIS=OFF
|
||||
-DENABLE_SNMP=OFF
|
||||
-DENABLE_SOCI=ON
|
||||
-DENABLE_TRANSCODER=ON
|
||||
-DENABLE_MDNS=OFF
|
||||
-DENABLE_EXTERNAL_AUTH_PLUGIN=OFF
|
||||
-DENABLE_JWE_AUTH_PLUGIN=OFF
|
||||
-DINTERNAL_LIBSRTP2=ON
|
||||
-DINTERNAL_JSONCPP=OFF
|
||||
-DENABLE_CONFERENCE=OFF
|
||||
-DENABLE_SOCI_POSTGRESQL_BACKEND=OFF
|
||||
-DENABLE_B2BUA=OFF
|
||||
-DENABLE_UNIT_TESTS=OFF
|
||||
-DENABLE_STRICT_LINPHONESDK=OFF
|
||||
*/
|
||||
mkShell
|
||||
{
|
||||
buildInputs =
|
||||
[
|
||||
cmake
|
||||
git
|
||||
openssl
|
||||
python3
|
||||
perl
|
||||
xercesc
|
||||
nghttp2
|
||||
sqlite
|
||||
speex
|
||||
libmysqlclient
|
||||
msgpack
|
||||
ninja # Optional. You can use "Unix makefiles" instead
|
||||
];
|
||||
};
|
||||
|
||||
packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
|
||||
|
||||
defaultPackage.x86_64-linux = self.packages.x86_64-linux.hello;
|
||||
|
||||
};
|
||||
}
|
122
flexisip_tester_script
Executable file
122
flexisip_tester_script
Executable file
|
@ -0,0 +1,122 @@
|
|||
#!/bin/bash
|
||||
#Script to mimic Gitlab-CI configuration of flexisip-flexisip_tester
|
||||
#execute it with sh -x [script] to see variables values and command launched
|
||||
|
||||
FLEXISIP_LOCATION=~/flexisip
|
||||
|
||||
#GCI script variables
|
||||
REBUILD_FLEXISIP_IMAGE_FROM_RPM=false
|
||||
REBUILD_FLEXISIP_AUXILIARIES=true
|
||||
REBUILD_SDK=false
|
||||
SDK_VERSION=4.3
|
||||
SDK_BRANCH=release/$SDK_VERSION
|
||||
PARALLEL_TEST_MODE=false
|
||||
DOCKER_BUILD_OPTIONS="--no-cache --force-rm -t gitlab.linphone.org:4567/bc/public/flexisip/flexisip:latest -f docker/flex-from-src --build-arg=njobs=12"
|
||||
liblinphone_tester="gitlab.linphone.org:4567/bc/public/linphone-sdk/liblinphone_tester:$SDK_VERSION"
|
||||
sourcedir=$FLEXISIP_LOCATION/linphone-sdk-docker
|
||||
workspace=$FLEXISIP_LOCATION/liblinphone_tester_workspace
|
||||
#docker compose network is default one (it is docker_default ???)
|
||||
docker_run_options="--volume=$FLEXISIP_LOCATION/liblinphone_tester_workspace:/home/bc/linphone-sdk-build/linphone-sdk/desktop/work --network=docker_default --device=/dev/snd --user 1000:29"
|
||||
COMPOSE_PROJECT_NAME=$RANDOM
|
||||
|
||||
#new variables for flexisip_tester
|
||||
|
||||
export FLEXISIP_DOCKER_IMAGE="gitlab.linphone.org:4567/bc/public/flexisip/flexisip"
|
||||
export FLEXISIP_DOCKER_TAG="latest"
|
||||
|
||||
#new variables for liblinphone_tester in docker-compose
|
||||
export LIBLINPHONE_DOCKER_IMAGE="gitlab.linphone.org:4567/bc/public/linphone-sdk/liblinphone_tester"
|
||||
export LIBLINPHONE_DOCKER_TAG=$SDK_VERSION
|
||||
|
||||
if [ -z $workspace ]; then
|
||||
echo "Error, $workspace should be set. Aborting to avoid unwanted rm"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p $workspace
|
||||
|
||||
sudo rm -rf $workspace
|
||||
|
||||
mkdir -p $workspace/{bin,ext,lime-server-apache}
|
||||
|
||||
ls $workspace
|
||||
#workaround for logs writing
|
||||
sudo chown apache:apache $workspace
|
||||
sudo chmod -R 777 $workspace
|
||||
|
||||
if [ "$REBUILD_FLEXISIP_IMAGE_FROM_RPM" = "true" ]; then
|
||||
docker build $DOCKER_BUILD_OPTIONS .
|
||||
fi
|
||||
|
||||
#--no-cache --force-rm
|
||||
if [ "$REBUILD_SDK" = "true" ]; then
|
||||
docker build --no-cache --force-rm -t gitlab.linphone.org:4567/bc/public/linphone-sdk/liblinphone_tester:$SDK_VERSION --build-arg="branch=$SDK_BRANCH" --build-arg="njobs=8" -f "$sourcedir/docker-files/liblinphone-tester" $sourcedir/docker-files/
|
||||
fi
|
||||
|
||||
#Handle multiple runs
|
||||
docker_compose_options=''
|
||||
|
||||
#Overriding docker-compose.yaml values with docker-compose-standalone.yaml in the ways specified with docker docs (either OR or AND, depending on key)
|
||||
for name in 'docker-compose.yaml' 'docker-compose-standalone.yaml'; do
|
||||
docker_compose_options="$docker_compose_options -f $FLEXISIP_LOCATION/flexisip-tester/docker/$name"
|
||||
done
|
||||
|
||||
#liblinphone_tester_options='--dns-hosts none --log-file liblinphone_tester.log --xml --verbose --show-account-manager-logs'
|
||||
liblinphone_tester_options="--suite Register --test \"Simple register\" --dns-hosts none --log-file liblinphone_tester.log --xml --verbose --show-account-manager-logs"
|
||||
|
||||
if [ "$PARALLEL_TEST_MODE" = "true" ]; then
|
||||
liblinphone_tester_options="$liblinphone_tester_options --parallel"
|
||||
fi
|
||||
|
||||
export FLEXISIP_LOGS="$workspace"
|
||||
|
||||
cd $workspace
|
||||
|
||||
docker-compose $docker_compose_options down
|
||||
|
||||
if [ "$REBUILD_FLEXISIP_AUXILIARIES" = "true" ]; then
|
||||
docker-compose $docker_compose_options build
|
||||
fi
|
||||
|
||||
# --exit-code-from liblinphone_tester
|
||||
docker-compose $docker_compose_options up --exit-code-from liblinphone_tester |& tee logs_all | grep 'liblinphone_tester_1' || EXIT=$?
|
||||
|
||||
grep 'file-transfer-server_1' logs_all > file-transfer-server.log
|
||||
|
||||
grep 'lime-server_1' logs_all > lime-server_stdout.log
|
||||
|
||||
grep 'dbserver_1' logs_all > dbserver_stdout.log
|
||||
|
||||
grep 'account-manager_1' logs_all > account-manager_stdout.log
|
||||
|
||||
grep 'http-proxy_1' logs_all > http-proxy_stdout.log
|
||||
|
||||
grep 'redis-server_1' logs_all > redis-server_stdout.log
|
||||
|
||||
#docker-compose $docker_compose_options exec liblinphone_tester bash
|
||||
|
||||
#sleep 60
|
||||
|
||||
|
||||
|
||||
#docker run $(echo $docker_run_options) $liblinphone_tester $liblinphone_tester_options || EXIT=$? && echo 'Tests have failed'
|
||||
|
||||
docker-compose $docker_compose_options stop
|
||||
|
||||
#after script (coredump management)
|
||||
|
||||
|
||||
# we specify commands to launch for each coredump of liblinphone_tester
|
||||
echo "set debug-file-directory ../lib64" | tee gdb_options
|
||||
echo "thread apply all bt" | tee -a gdb_options
|
||||
|
||||
# searching for core files and if there are some, launch gdb on all of it
|
||||
# xargs -L1 means that the command in argument will be executed for each
|
||||
# line (core dump) found in find output
|
||||
# The docker syntax is error proning : to override the entrypoint with
|
||||
# args, we enter the entrypoint first, then the name of the image, then the
|
||||
# args to the entrypoint command.
|
||||
# "true ||" is used here to continue the script even if the find fails
|
||||
if [[ -n $(find . -type f -name "core*") ]]; then find . -type f -name "core*" | xargs -L1 docker run $(echo $docker_run_options) --entrypoint gdb $liblinphone_tester ../bin/liblinphone_tester -x gdb_options; fi || true
|
||||
|
||||
echo $EXIT
|
41
include/CMakeLists.txt
Normal file
41
include/CMakeLists.txt
Normal file
|
@ -0,0 +1,41 @@
|
|||
############################################################################
|
||||
# CMakeLists.txt
|
||||
# Copyright (C) 2019 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
find_package(Git)
|
||||
|
||||
set(gitversion_script "${CMAKE_CURRENT_SOURCE_DIR}/gitversion.cmake")
|
||||
set(workdir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(outputdir "${CMAKE_CURRENT_BINARY_DIR}/flexisip")
|
||||
set(flexisip_version_h "${outputdir}/flexisip-version.h")
|
||||
|
||||
add_custom_target(flexisip-git-version ALL
|
||||
COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DFLEXISIP_VERSION=${FLEXISIP_VERSION}
|
||||
-DWORK_DIR=${workdir} -DOUTPUT_DIR=${outputdir} -P "${gitversion_script}"
|
||||
BYPRODUCTS "${flexisip_version_h}"
|
||||
)
|
||||
|
||||
install(DIRECTORY flexisip DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES "${flexisip_version_h}" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/flexisip")
|
||||
|
||||
if(HAS_GCC_BUG_105562)
|
||||
set_source_files_properties(flexisip/expressionparser-impl.cc PROPERTIES COMPILE_OPTIONS "-Wno-error=maybe-uninitialized")
|
||||
endif()
|
77
include/flexisip/auth/flexisip-auth-module-base.hh
Normal file
77
include/flexisip/auth/flexisip-auth-module-base.hh
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <sofia-sip/auth_digest.h>
|
||||
#include <sofia-sip/auth_module.h>
|
||||
#include <sofia-sip/msg_types.h>
|
||||
#include <sofia-sip/su_wait.h>
|
||||
|
||||
#include "flexisip/auth/flexisip-auth-status.hh"
|
||||
#include "flexisip/auth/nonce-store.hh"
|
||||
#include "flexisip/sofia-wrapper/auth-module.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
/**
|
||||
* @brief Base class for all authentication modules used by Flexisip.
|
||||
*
|
||||
* This implementation of AuthModule allows to do HTTP-like authentication
|
||||
* of SIP requests as described in RFC 3261 §22.
|
||||
*/
|
||||
class FlexisipAuthModuleBase : public AuthModule {
|
||||
public:
|
||||
/**
|
||||
* @brief Instantiate a new authentication module without QOP authentication feature.
|
||||
* @param[in] root Event loop which the module will be working on.
|
||||
* @param[in] domain The domain name which the module is in charge of.
|
||||
* @param[in] nonceExpire Validity period for a nonce in seconds.
|
||||
* @param[in] qopAuth Setting true allows clients to use the same nonce for successive authentication.
|
||||
*/
|
||||
FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, int nonceExpire, bool qopAuth);
|
||||
~FlexisipAuthModuleBase() override = default;
|
||||
|
||||
NonceStore &nonceStore() {return mNonceStore;}
|
||||
|
||||
protected:
|
||||
void onCheck(AuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) override;
|
||||
void onChallenge(AuthStatus &as, auth_challenger_t const *ach) override;
|
||||
void onCancel(AuthStatus &as) override;
|
||||
|
||||
/**
|
||||
* This method is called each time the module want to authenticate an Authorization header.
|
||||
* The result of the authentication must be store in 'status' attribute of 'as' parameter as
|
||||
* described in documentation of auth_mod_verify() function.
|
||||
*
|
||||
* @param[in,out] as The context on the authentication. It is also used to return the result.
|
||||
* @param[in] credentials The authorization header to validate.
|
||||
*/
|
||||
virtual void checkAuthHeader(FlexisipAuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) = 0;
|
||||
|
||||
void notify(FlexisipAuthStatus &as);
|
||||
void onError(FlexisipAuthStatus &as);
|
||||
|
||||
NonceStore mNonceStore;
|
||||
bool mQOPAuth = false;
|
||||
};
|
||||
|
||||
}
|
79
include/flexisip/auth/flexisip-auth-status.hh
Normal file
79
include/flexisip/auth/flexisip-auth-status.hh
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "flexisip/event.hh"
|
||||
#include "flexisip/sofia-wrapper/auth-status.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
/**
|
||||
* Specialization of AuthStatus dedicated to be used
|
||||
* with FlexisipAuthModule class.
|
||||
*/
|
||||
class FlexisipAuthStatus : public AuthStatus {
|
||||
public:
|
||||
FlexisipAuthStatus(const std::shared_ptr<RequestSipEvent>& ev) : AuthStatus(), mEvent(ev) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that has been used while construction.
|
||||
*/
|
||||
const std::shared_ptr<RequestSipEvent> &event() const {return mEvent;}
|
||||
|
||||
/**
|
||||
* This property is to be set by the user of FlexisipAuthModule
|
||||
* before calling verify(). If true, the module will not return 403
|
||||
* status code on authentication denied but will submit a new challenge.
|
||||
*/
|
||||
bool no403() const {return mNo403;}
|
||||
void no403(bool no403) {mNo403 = no403;}
|
||||
|
||||
/**
|
||||
* This property is set by FlexisipAuthModule and can
|
||||
* be read on each time while the authentication is running.
|
||||
* A 'true' value means that the module has already tried to fetch
|
||||
* the password from database and has succeeded.
|
||||
*/
|
||||
bool passwordFound() const {return mPasswordFound;}
|
||||
void passwordFound(bool val) {mPasswordFound = val;}
|
||||
|
||||
/**
|
||||
* List of digest algorithms to use for authentication. If there
|
||||
* are several algorithms, FlexisipAuthModule will generate
|
||||
* one challenge per algorithm when the Authorization header is missing
|
||||
* from the request.
|
||||
*
|
||||
* This property must be set before calling verify() and must
|
||||
* contain one element at least.
|
||||
*/
|
||||
std::list<std::string> &usedAlgo() {return mAlgoUsed;}
|
||||
|
||||
private:
|
||||
std::shared_ptr<RequestSipEvent> mEvent;
|
||||
std::list<std::string> mAlgoUsed;
|
||||
bool mNo403 = false;
|
||||
bool mPasswordFound = false;
|
||||
};
|
||||
|
||||
}
|
53
include/flexisip/auth/nonce-store.hh
Normal file
53
include/flexisip/auth/nonce-store.hh
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
* Copyright (C) 2018 Belledonne Communications SARL, All rights reserved.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include <sofia-sip/msg_types.h>
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class NonceStore {
|
||||
public:
|
||||
void setNonceExpires(int value) {mNonceExpires = value;}
|
||||
int getNc(const std::string &nonce);
|
||||
void insert(const msg_auth_t *response);
|
||||
void insert(const std::string &nonce);
|
||||
void updateNc(const std::string &nonce, int newnc);
|
||||
void erase(const std::string &nonce);
|
||||
void cleanExpired();
|
||||
|
||||
private:
|
||||
struct NonceCount {
|
||||
NonceCount(int c, time_t ex) : nc(c), expires(ex) {
|
||||
}
|
||||
int nc;
|
||||
std::time_t expires;
|
||||
};
|
||||
|
||||
std::map<std::string, NonceCount> mNc;
|
||||
std::mutex mMutex;
|
||||
int mNonceExpires = 3600;
|
||||
};
|
||||
|
||||
}
|
119
include/flexisip/common.hh
Normal file
119
include/flexisip/common.hh
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "flexisip/logmanager.hh"
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (a) > (b) ? (a) : (b)
|
||||
#endif
|
||||
|
||||
time_t getCurrentTime();
|
||||
time_t getTimeOffset(time_t current_time);
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex(bool reentrant = false);
|
||||
void lock();
|
||||
void unlock();
|
||||
~Mutex();
|
||||
|
||||
private:
|
||||
const bool mReentrant;
|
||||
pthread_t mThread;
|
||||
int mCount;
|
||||
pthread_mutex_t mMutex;
|
||||
pthread_mutex_t mInternalMutex;
|
||||
};
|
||||
|
||||
template <typename _type>
|
||||
class delete_functor {
|
||||
public:
|
||||
void operator()(_type* obj) {
|
||||
delete obj;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _first, typename _last>
|
||||
class map_delete_functor {
|
||||
public:
|
||||
void operator()(std::pair<_first, _last> obj) {
|
||||
delete obj.second;
|
||||
}
|
||||
};
|
||||
|
||||
#define RESTART_EXIT_CODE 5
|
||||
|
||||
// Helper to get ip from host in a portable binary format.
|
||||
// It has comparison functions, which makes it suitable to use in std::set or std::map, for fast search.
|
||||
class BinaryIp {
|
||||
public:
|
||||
/* Adds a hostname in the form of BinaryIp into a generic STL container.
|
||||
If numericOnly is set to true, then no DNS lookup will be made. As a result fully qualified domain names will be
|
||||
ignored.*/
|
||||
template <typename _containerT>
|
||||
static _containerT& emplace(_containerT& container, const std::string& hostname, bool numericOnly = false) {
|
||||
struct addrinfo* ai = resolve(hostname, numericOnly);
|
||||
struct addrinfo* ai_it;
|
||||
for (ai_it = ai; ai_it != nullptr; ai_it = ai_it->ai_next) {
|
||||
container.emplace(ai_it);
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
return container;
|
||||
}
|
||||
/* Builds a BinaryIp from a struct addrinfo containing an AF_INET6 address only !.
|
||||
* Do not use directly, use static emplace() method to build BinarIps.*/
|
||||
BinaryIp(const struct addrinfo* ai);
|
||||
BinaryIp(const char* ip);
|
||||
|
||||
bool operator==(const BinaryIp& ip2) const {
|
||||
return memcmp(&mAddr, &ip2.mAddr, sizeof mAddr) == 0;
|
||||
}
|
||||
bool operator<(const BinaryIp& ip2) const {
|
||||
return memcmp(&mAddr, &ip2.mAddr, sizeof mAddr) < 0;
|
||||
}
|
||||
bool operator<=(const BinaryIp& ip2) const {
|
||||
return memcmp(&mAddr, &ip2.mAddr, sizeof mAddr) <= 0;
|
||||
}
|
||||
bool operator>(const BinaryIp& ip2) const {
|
||||
return memcmp(&mAddr, &ip2.mAddr, sizeof mAddr) > 0;
|
||||
}
|
||||
bool operator>=(const BinaryIp& ip2) const {
|
||||
return memcmp(&mAddr, &ip2.mAddr, sizeof mAddr) >= 0;
|
||||
}
|
||||
// turn hummanely readable IP. This function is not optimized for speed.
|
||||
std::string asString() const;
|
||||
|
||||
private:
|
||||
static struct addrinfo* resolve(const std::string& hostname, bool numericOnly);
|
||||
struct in6_addr mAddr;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const flexisip::BinaryIp& ip);
|
||||
} // namespace flexisip
|
827
include/flexisip/configmanager.hh
Normal file
827
include/flexisip/configmanager.hh
Normal file
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <cxxabi.h>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <typeinfo>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
// WARNING: keep flexisip-config.h included before any other
|
||||
// Flexisip includes.
|
||||
// WARNING2: keep flexisip-config.h included before 'net-snmp'
|
||||
// header section because ENABLE_SNMP is defined in this header.
|
||||
#if defined(HAVE_CONFIG_H) && !defined(FLEXISIP_INCLUDED)
|
||||
#include "flexisip-config.h"
|
||||
#define FLEXISIP_INCLUDED
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SNMP
|
||||
// SNMP headers are sensitive to the inclusion order.
|
||||
// clang-format off
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
// clang-format on
|
||||
#else
|
||||
typedef unsigned long oid;
|
||||
#endif /* ENABLE_SNMP */
|
||||
|
||||
#include "flexisip/common.hh"
|
||||
#include "flexisip/flexisip-exception.hh"
|
||||
#include "flexisip/global.hh"
|
||||
#include "flexisip/sip-boolean-expressions.hh"
|
||||
|
||||
typedef struct sip_s sip_t;
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class LpConfig;
|
||||
|
||||
enum class ConfigState { Check, Changed, Reset, Committed };
|
||||
class ConfigValue;
|
||||
|
||||
class ConfigValueListener {
|
||||
public:
|
||||
ConfigValueListener() = default;
|
||||
virtual ~ConfigValueListener() = default;
|
||||
virtual bool doOnConfigStateChanged(const ConfigValue& conf, ConfigState state) = 0;
|
||||
|
||||
private:
|
||||
// FLEXISIP_DISABLE_COPY(ConfigValueListener);
|
||||
};
|
||||
|
||||
enum GenericValueType {
|
||||
Boolean,
|
||||
Integer,
|
||||
IntegerRange,
|
||||
Counter64,
|
||||
String,
|
||||
ByteSize,
|
||||
StringList,
|
||||
Struct,
|
||||
BooleanExpr,
|
||||
Notification,
|
||||
RuntimeError,
|
||||
DurationMS,
|
||||
DurationS,
|
||||
DurationMIN
|
||||
};
|
||||
|
||||
/* Allows to have a string for each GenericValueType */
|
||||
static const std::map<GenericValueType, std::string> GenericValueTypeNameMap = {
|
||||
#define TypeToName(X) \
|
||||
{ X, #X }
|
||||
TypeToName(Boolean), TypeToName(Integer), TypeToName(IntegerRange), TypeToName(Counter64),
|
||||
TypeToName(String), TypeToName(ByteSize), TypeToName(StringList), TypeToName(Struct),
|
||||
TypeToName(BooleanExpr), TypeToName(Notification), TypeToName(RuntimeError), TypeToName(DurationMS),
|
||||
TypeToName(DurationS), TypeToName(DurationMIN)
|
||||
#undef TypeToName
|
||||
};
|
||||
|
||||
struct ConfigItemDescriptor {
|
||||
GenericValueType type;
|
||||
const char* name;
|
||||
const char* help;
|
||||
const char* default_value;
|
||||
};
|
||||
static const ConfigItemDescriptor config_item_end = {Boolean, NULL, NULL, NULL};
|
||||
|
||||
struct StatItemDescriptor {
|
||||
GenericValueType type;
|
||||
const char* name;
|
||||
const char* help;
|
||||
};
|
||||
static const StatItemDescriptor stat_item_end = {Boolean, NULL, NULL};
|
||||
|
||||
class Oid {
|
||||
friend class GenericEntry;
|
||||
friend class StatCounter64;
|
||||
friend class ConfigValue;
|
||||
friend class GenericStruct;
|
||||
friend class RootConfigStruct;
|
||||
friend class NotificationEntry;
|
||||
|
||||
protected:
|
||||
Oid(Oid& parent, oid leaf);
|
||||
Oid(std::vector<oid> path);
|
||||
Oid(std::vector<oid> path, oid leaf);
|
||||
std::vector<oid>& getValue() {
|
||||
return mOidPath;
|
||||
}
|
||||
virtual ~Oid() = default;
|
||||
|
||||
private:
|
||||
std::vector<oid> mOidPath;
|
||||
|
||||
public:
|
||||
std::string getValueAsString() const {
|
||||
std::ostringstream oss(std::ostringstream::out);
|
||||
for (oid i = 0; i < mOidPath.size(); ++i) {
|
||||
if (i != 0) oss << ".";
|
||||
oss << mOidPath[i];
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
oid getLeaf() {
|
||||
return mOidPath[mOidPath.size() - 1];
|
||||
}
|
||||
static oid oidFromHashedString(const std::string& str);
|
||||
};
|
||||
|
||||
class GenericEntry {
|
||||
public:
|
||||
class DeprecationInfo {
|
||||
public:
|
||||
DeprecationInfo() = default;
|
||||
DeprecationInfo(const std::string& date, const std::string& version, const std::string& text = "") {
|
||||
setAsDeprecated(date, version, text);
|
||||
}
|
||||
|
||||
bool isDeprecated() const {
|
||||
return !mDate.empty();
|
||||
}
|
||||
void setAsDeprecated(const std::string& date, const std::string& version, const std::string& text = "");
|
||||
|
||||
const std::string& getDate() const {
|
||||
return mDate;
|
||||
}
|
||||
const std::string& getVersion() const {
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
const std::string& getText() const {
|
||||
return mText;
|
||||
}
|
||||
void setText(const std::string& text) {
|
||||
mText = text;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mDate;
|
||||
std::string mVersion;
|
||||
std::string mText;
|
||||
};
|
||||
|
||||
static std::string sanitize(const std::string& str);
|
||||
|
||||
const std::string& getName() const {
|
||||
return mName;
|
||||
}
|
||||
std::string getCompleteName() const;
|
||||
std::string getPrettyName() const;
|
||||
|
||||
GenericValueType getType() const {
|
||||
return mType;
|
||||
}
|
||||
|
||||
const std::string& getTypeName() const {
|
||||
if (GenericValueTypeNameMap.count(mType) == 1) return GenericValueTypeNameMap.at(mType);
|
||||
else return GenericValueTypeNameMap.at(Integer);
|
||||
}
|
||||
|
||||
const std::string& getHelp() const {
|
||||
return mHelp;
|
||||
}
|
||||
GenericEntry* getParent() const {
|
||||
return mParent;
|
||||
}
|
||||
virtual ~GenericEntry() {
|
||||
if (mOid) delete mOid;
|
||||
}
|
||||
virtual void setParent(GenericEntry* parent);
|
||||
/*
|
||||
* @returns entry oid built from parent & object oid index
|
||||
*/
|
||||
Oid& getOid() {
|
||||
return *mOid;
|
||||
}
|
||||
std::string getOidAsString() const {
|
||||
return mOid->getValueAsString();
|
||||
}
|
||||
void setErrorMessage(const std::string& msg) {
|
||||
mErrorMessage = msg;
|
||||
}
|
||||
const std::string& getErrorMessage() const {
|
||||
return mErrorMessage;
|
||||
}
|
||||
|
||||
void setReadOnly(bool ro) {
|
||||
mReadOnly = ro;
|
||||
}
|
||||
bool isExportable() const {
|
||||
return mExportToConfigFile;
|
||||
}
|
||||
void setExportable(bool val) {
|
||||
mExportToConfigFile = val;
|
||||
}
|
||||
#ifdef ENABLE_SNMP
|
||||
static int sHandleSnmpRequest(netsnmp_mib_handler* handler,
|
||||
netsnmp_handler_registration* reginfo,
|
||||
netsnmp_agent_request_info* reqinfo,
|
||||
netsnmp_request_info* requests);
|
||||
virtual int handleSnmpRequest(netsnmp_mib_handler*,
|
||||
netsnmp_handler_registration*,
|
||||
netsnmp_agent_request_info*,
|
||||
netsnmp_request_info*) {
|
||||
return -1;
|
||||
};
|
||||
#endif
|
||||
virtual void mibFragment(std::ostream& ostr, std::string spacing) const = 0;
|
||||
void setConfigListener(ConfigValueListener* listener) {
|
||||
mConfigListener = listener;
|
||||
}
|
||||
ConfigValueListener* getConfigListener() const {
|
||||
return mConfigListener;
|
||||
}
|
||||
bool onConfigStateChanged(const ConfigValue& conf, ConfigState state);
|
||||
|
||||
void setDeprecated(const DeprecationInfo& info) {
|
||||
mDeprecationInfo = info;
|
||||
}
|
||||
void setDeprecated(const std::string& aDate, const std::string& aVersion, const std::string& aText = "") {
|
||||
mDeprecationInfo.setAsDeprecated(aDate, aVersion, aText);
|
||||
}
|
||||
bool isDeprecated() const {
|
||||
return mDeprecationInfo.isDeprecated();
|
||||
}
|
||||
const DeprecationInfo& getDeprecationInfo() const {
|
||||
return mDeprecationInfo;
|
||||
}
|
||||
DeprecationInfo& getDeprecationInfo() {
|
||||
return mDeprecationInfo;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void doMibFragment(std::ostream& ostr,
|
||||
const std::string& def,
|
||||
const std::string& access,
|
||||
const std::string& syntax,
|
||||
const std::string& spacing) const;
|
||||
GenericEntry(const std::string& name, GenericValueType type, const std::string& help, oid oid_index = 0);
|
||||
static std::string escapeDoubleQuotes(const std::string& str);
|
||||
|
||||
Oid* mOid = nullptr;
|
||||
const std::string mName;
|
||||
bool mReadOnly = false;
|
||||
bool mExportToConfigFile = true;
|
||||
DeprecationInfo mDeprecationInfo;
|
||||
std::string mErrorMessage;
|
||||
|
||||
private:
|
||||
std::string mHelp;
|
||||
GenericValueType mType;
|
||||
GenericEntry* mParent = nullptr;
|
||||
ConfigValueListener* mConfigListener = nullptr;
|
||||
oid mOidLeaf = 0;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& ostr, const GenericEntry& entry) {
|
||||
return ostr << entry.getName();
|
||||
}
|
||||
|
||||
class ConfigValue;
|
||||
class StatCounter64;
|
||||
struct StatPair;
|
||||
class GenericStruct : public GenericEntry {
|
||||
public:
|
||||
GenericStruct(const std::string& name, const std::string& help, oid oid_index);
|
||||
|
||||
template <typename T>
|
||||
T* addChild(std::unique_ptr<T>&& newEntry) {
|
||||
auto newEntryPointer = newEntry.get();
|
||||
newEntryPointer->setParent(this);
|
||||
for (auto& entry : mEntries) {
|
||||
if (entry->getName() == newEntry->getName()) {
|
||||
throw std::runtime_error(std::string("Duplicate entry key: ") + entry->getName());
|
||||
}
|
||||
}
|
||||
mEntries.push_back(std::move(newEntry));
|
||||
return newEntryPointer;
|
||||
}
|
||||
|
||||
StatCounter64* createStat(const std::string& name, const std::string& help);
|
||||
void createStatPair(const std::string& name, const std::string& help);
|
||||
StatCounter64* getStat(const std::string& name);
|
||||
std::pair<StatCounter64*, StatCounter64*> getStatPair(const std::string& name);
|
||||
std::unique_ptr<StatPair> getStatPairPtr(const std::string& name);
|
||||
|
||||
void addChildrenValues(ConfigItemDescriptor* items);
|
||||
void addChildrenValues(ConfigItemDescriptor* items, bool hashed);
|
||||
void deprecateChild(const std::string& name, const DeprecationInfo& info);
|
||||
const std::list<std::unique_ptr<GenericEntry>>& getChildren() const;
|
||||
template <typename _retType, typename StrT>
|
||||
_retType* get(StrT&& name) const;
|
||||
template <typename _retType>
|
||||
_retType* getDeep(const std::string& name, bool strict) const;
|
||||
|
||||
template <typename Str>
|
||||
GenericEntry* find(Str&& name) const {
|
||||
auto it = find_if(mEntries.cbegin(), mEntries.cend(), [&name](const auto& e) { return e->getName() == name; });
|
||||
return it != mEntries.cend() ? it->get() : nullptr;
|
||||
}
|
||||
|
||||
GenericEntry* findApproximate(const std::string& name) const;
|
||||
void mibFragment(std::ostream& ost, std::string spacing) const override;
|
||||
void setParent(GenericEntry* parent) override;
|
||||
|
||||
private:
|
||||
std::list<std::unique_ptr<GenericEntry>> mEntries;
|
||||
};
|
||||
|
||||
class RootConfigStruct : public GenericStruct {
|
||||
public:
|
||||
RootConfigStruct(const std::string& name,
|
||||
const std::string& help,
|
||||
std::vector<oid> oid_root_prefix,
|
||||
const std::string& configFile);
|
||||
~RootConfigStruct() override;
|
||||
|
||||
const std::string& getConfigFile() const {
|
||||
return mConfigFile;
|
||||
}
|
||||
void setCommittedChange(bool committedChange) {
|
||||
mCommittedChange = committedChange;
|
||||
}
|
||||
bool hasCommittedChange() const {
|
||||
return mCommittedChange;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string& mConfigFile; // keep a const ref to ConfigManager file
|
||||
bool mCommittedChange{true};
|
||||
};
|
||||
|
||||
class StatCounter64 : public GenericEntry {
|
||||
public:
|
||||
StatCounter64(const std::string& name, const std::string& help, oid oid_index);
|
||||
#ifdef ENABLE_SNMP
|
||||
int handleSnmpRequest(netsnmp_mib_handler*,
|
||||
netsnmp_handler_registration*,
|
||||
netsnmp_agent_request_info*,
|
||||
netsnmp_request_info*) override;
|
||||
#endif
|
||||
void mibFragment(std::ostream& ost, std::string spacing) const override;
|
||||
void setParent(GenericEntry* parent) override;
|
||||
uint64_t read() {
|
||||
return mValue;
|
||||
}
|
||||
void set(uint64_t val) {
|
||||
mValue = val;
|
||||
}
|
||||
void operator++() {
|
||||
++mValue;
|
||||
}
|
||||
void operator++(int) {
|
||||
mValue++;
|
||||
}
|
||||
void operator--() {
|
||||
--mValue;
|
||||
}
|
||||
void operator--(int) {
|
||||
mValue--;
|
||||
}
|
||||
inline void incr() {
|
||||
mValue++;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t mValue;
|
||||
};
|
||||
|
||||
struct StatPair {
|
||||
StatCounter64* const start;
|
||||
StatCounter64* const finish;
|
||||
StatPair(StatCounter64* istart, StatCounter64* ifinish) : start(istart), finish(ifinish) {
|
||||
}
|
||||
|
||||
inline void incrStart() {
|
||||
start->incr();
|
||||
}
|
||||
inline void incrFinish() {
|
||||
finish->incr();
|
||||
}
|
||||
};
|
||||
|
||||
class StatFinishListener {
|
||||
std::unordered_set<StatCounter64*> mStatList;
|
||||
|
||||
public:
|
||||
void addStatCounter(StatCounter64* stat) {
|
||||
mStatList.insert(stat);
|
||||
}
|
||||
~StatFinishListener() {
|
||||
for (auto it = mStatList.begin(); it != mStatList.end(); ++it) {
|
||||
StatCounter64& s = **it;
|
||||
++s;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ConfigValue : public GenericEntry {
|
||||
public:
|
||||
ConfigValue(const std::string& name,
|
||||
GenericValueType vt,
|
||||
const std::string& help,
|
||||
const std::string& default_value,
|
||||
oid oid_index);
|
||||
|
||||
/* Set the value and mark it as 'not default' */
|
||||
void set(const std::string& value);
|
||||
virtual const std::string& get() const;
|
||||
|
||||
/* Restore the default value and mark the value as 'default'. */
|
||||
void restoreDefault();
|
||||
|
||||
/*
|
||||
* Set the default value i.e. the value which will be restored by reset(). If the value is
|
||||
* marked as 'default', it will be automatically updated to the new default value.
|
||||
*/
|
||||
void setDefault(const std::string& value);
|
||||
const std::string& getDefault() const;
|
||||
|
||||
virtual std::string_view getDefaultUnit() const;
|
||||
|
||||
void setFallback(const ConfigValue& fallbackValue);
|
||||
|
||||
/* Check whether the value is mark as 'default' */
|
||||
bool isDefault() const {
|
||||
return mIsDefault;
|
||||
}
|
||||
|
||||
void setNextValue(const std::string& value);
|
||||
const std::string& getNextValue() const {
|
||||
return mNextValue;
|
||||
}
|
||||
|
||||
void setNotifPayload(bool b) {
|
||||
mNotifPayload = b;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SNMP
|
||||
int handleSnmpRequest(netsnmp_mib_handler*,
|
||||
netsnmp_handler_registration*,
|
||||
netsnmp_agent_request_info*,
|
||||
netsnmp_request_info*) override;
|
||||
#endif
|
||||
|
||||
void doConfigMibFragment(std::ostream& ostr, const std::string& syntax, const std::string& spacing) const {
|
||||
doMibFragment(ostr, "", "", syntax, spacing);
|
||||
}
|
||||
|
||||
void setParent(GenericEntry* parent) override;
|
||||
void mibFragment(std::ostream& ost, std::string spacing) const override;
|
||||
void doMibFragment(std::ostream& ostr,
|
||||
const std::string& def,
|
||||
const std::string& access,
|
||||
const std::string& syntax,
|
||||
const std::string& spacing) const override;
|
||||
|
||||
protected:
|
||||
bool invokeConfigStateChanged(ConfigState state);
|
||||
void checkType(const std::string& value, bool isDefault);
|
||||
|
||||
std::string mValue;
|
||||
std::string mNextValue;
|
||||
std::string mDefaultValue;
|
||||
const ConfigValue* mFallback = nullptr;
|
||||
bool mIsDefault = true;
|
||||
bool mNotifPayload = false;
|
||||
};
|
||||
|
||||
class ConfigBoolean : public ConfigValue {
|
||||
public:
|
||||
static bool parse(const std::string& value);
|
||||
ConfigBoolean(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index);
|
||||
bool read() const;
|
||||
bool readNext() const;
|
||||
void write(bool value);
|
||||
#ifdef ENABLE_SNMP
|
||||
int handleSnmpRequest(netsnmp_mib_handler*,
|
||||
netsnmp_handler_registration*,
|
||||
netsnmp_agent_request_info*,
|
||||
netsnmp_request_info*) override;
|
||||
#endif
|
||||
void mibFragment(std::ostream& ost, std::string spacing) const override;
|
||||
};
|
||||
|
||||
class ConfigInt : public ConfigValue {
|
||||
public:
|
||||
#ifdef ENABLE_SNMP
|
||||
int handleSnmpRequest(netsnmp_mib_handler*,
|
||||
netsnmp_handler_registration*,
|
||||
netsnmp_agent_request_info*,
|
||||
netsnmp_request_info*) override;
|
||||
#endif
|
||||
ConfigInt(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index);
|
||||
void mibFragment(std::ostream& ost, std::string spacing) const override;
|
||||
int read() const;
|
||||
int readNext() const;
|
||||
void write(int value);
|
||||
};
|
||||
|
||||
class ConfigIntRange : public ConfigValue {
|
||||
public:
|
||||
ConfigIntRange(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index);
|
||||
int readMin();
|
||||
int readMax();
|
||||
int readNextMin();
|
||||
int readNextMax();
|
||||
void write(int min, int max);
|
||||
|
||||
private:
|
||||
void parse(const std::string& value);
|
||||
int mMin{};
|
||||
int mMax{};
|
||||
};
|
||||
|
||||
template <typename DurationType>
|
||||
struct DurationInfo {};
|
||||
|
||||
template <>
|
||||
struct DurationInfo<std::chrono::milliseconds> {
|
||||
static constexpr GenericValueType kValueType = DurationMS;
|
||||
static constexpr const char* kUnit = "millisecond";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DurationInfo<std::chrono::seconds> {
|
||||
static constexpr GenericValueType kValueType = DurationS;
|
||||
static constexpr const char* kUnit = "second";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DurationInfo<std::chrono::minutes> {
|
||||
static constexpr GenericValueType kValueType = DurationMIN;
|
||||
static constexpr const char* kUnit = "minute";
|
||||
};
|
||||
|
||||
template <typename DurationType>
|
||||
class ConfigDuration : public ConfigValue {
|
||||
public:
|
||||
ConfigDuration(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index)
|
||||
: ConfigValue(name, DurationInfo<DurationType>::kValueType, help, default_value, oid_index) {
|
||||
}
|
||||
|
||||
std::string_view getDefaultUnit() const override {
|
||||
return DurationInfo<DurationType>::kUnit;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds read() const {
|
||||
using namespace std::chrono_literals;
|
||||
static const std::map<std::string, std::chrono::milliseconds> kMapping = {
|
||||
{"ms", 1ms},
|
||||
{"s", 1000ms},
|
||||
{"min", 60000ms},
|
||||
{"h", 3600 * 1000ms},
|
||||
{"d", 24 * 3600 * 1000ms},
|
||||
{"m", static_cast<long>(30.436875 * 24 * 3600) * 1000ms},
|
||||
{"y", static_cast<long>(365.2425 * 24 * 3600) * 1000ms}};
|
||||
|
||||
const auto [value, unit] = parse();
|
||||
auto unitIterator = kMapping.find(unit);
|
||||
|
||||
// If not found, it may be intentional (use default unit) or for backward compatibility.
|
||||
if (unitIterator == kMapping.end()) {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(DurationType{value});
|
||||
}
|
||||
|
||||
if (unit == "ms" and getDefaultUnit() == "second") {
|
||||
throw std::runtime_error("(" + getCompleteName() + ") duration precision (\"" + unit +
|
||||
R"(") is too high, "second" is maximum precision for this parameter)");
|
||||
}
|
||||
if ((unit == "ms" or unit == "s") and getDefaultUnit() == "minute") {
|
||||
throw std::runtime_error("(" + getCompleteName() + ") duration precision (\"" + unit +
|
||||
R"(") is too high, "minute" is maximum precision for this parameter)");
|
||||
}
|
||||
|
||||
return unitIterator->second * value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::pair<long, std::string> parse() const {
|
||||
std::smatch matchResult{};
|
||||
if (!std::regex_match(get(), matchResult, std::regex("([0-9]+)(|ms|s|min|h|d|m|y)"))) {
|
||||
throw std::runtime_error(
|
||||
"(" + getCompleteName() + ") duration value is ill-formed (parameter = \"" + get() +
|
||||
"\"). Please use the following syntax: <value>[ms|s|min|h|d|m|y] (example: 250ms).");
|
||||
}
|
||||
|
||||
return {std::stol(matchResult[1]), matchResult[2]};
|
||||
}
|
||||
};
|
||||
|
||||
class ConfigRuntimeError : public ConfigValue {
|
||||
mutable std::string mErrorStr;
|
||||
|
||||
public:
|
||||
ConfigRuntimeError(const std::string& name, const std::string& help, oid oid_index);
|
||||
std::string generateErrors() const;
|
||||
#ifdef ENABLE_SNMP
|
||||
int handleSnmpRequest(netsnmp_mib_handler*,
|
||||
netsnmp_handler_registration*,
|
||||
netsnmp_agent_request_info*,
|
||||
netsnmp_request_info*) override;
|
||||
#endif
|
||||
void writeErrors(const GenericEntry* entry, std::ostringstream& oss) const;
|
||||
};
|
||||
|
||||
class ConfigString : public ConfigValue {
|
||||
public:
|
||||
ConfigString(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index);
|
||||
~ConfigString();
|
||||
const std::string& read() const;
|
||||
};
|
||||
|
||||
class ConfigByteSize : public ConfigValue {
|
||||
public:
|
||||
using ValueType = std::uint64_t;
|
||||
|
||||
ConfigByteSize(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index);
|
||||
ValueType read() const;
|
||||
};
|
||||
|
||||
class ConfigStringList : public ConfigValue {
|
||||
public:
|
||||
ConfigStringList(const std::string& name, const std::string& help, const std::string& default_value, oid oid_index);
|
||||
std::list<std::string> read() const;
|
||||
bool contains(const std::string& ref) const;
|
||||
static std::list<std::string> parse(const std::string& in);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class ConfigBooleanExpression : public ConfigValue {
|
||||
public:
|
||||
ConfigBooleanExpression(const std::string& name,
|
||||
const std::string& help,
|
||||
const std::string& default_value,
|
||||
oid oid_index);
|
||||
std::shared_ptr<SipBooleanExpression> read() const;
|
||||
};
|
||||
|
||||
template <typename _retType, typename StrT>
|
||||
_retType* GenericStruct::get(StrT&& name) const {
|
||||
GenericEntry* e = find(name);
|
||||
if (e == NULL) {
|
||||
std::ostringstream err{};
|
||||
err << "No ConfigEntry with name [" << name << "] in struct [" << getName() << "]";
|
||||
LOGA("%s", err.str().c_str());
|
||||
}
|
||||
_retType* ret = dynamic_cast<_retType*>(e);
|
||||
if (ret == NULL) {
|
||||
int status;
|
||||
std::string type_name = abi::__cxa_demangle(typeid(_retType).name(), 0, 0, &status);
|
||||
std::ostringstream err{};
|
||||
err << "Config entry [" << name << "] in struct [" << e->getParent()->getName()
|
||||
<< "] does not have the expected type '" << type_name << "'.";
|
||||
LOGA("%s", err.str().c_str());
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
template <typename _retType>
|
||||
_retType* GenericStruct::getDeep(const std::string& name, bool strict) const {
|
||||
size_t len = name.length();
|
||||
size_t next, prev = 0;
|
||||
const GenericStruct *next_node, *prev_node = this;
|
||||
while (std::string::npos != (next = name.find('/', prev))) {
|
||||
std::string next_node_name = name.substr(prev, next - prev);
|
||||
GenericEntry* e = find(next_node_name.c_str());
|
||||
if (!e) {
|
||||
if (!strict) return NULL;
|
||||
LOGE("No ConfigEntry with name [%s] in struct [%s]", name.c_str(), prev_node->getName().c_str());
|
||||
for (auto it = prev_node->mEntries.begin(); it != prev_node->mEntries.end(); ++it) {
|
||||
LOGE("-> %s", (*it)->getName().c_str());
|
||||
}
|
||||
LOGF("end");
|
||||
return NULL;
|
||||
}
|
||||
next_node = dynamic_cast<GenericStruct*>(e);
|
||||
if (!next_node) {
|
||||
LOGA("Config entry [%s] in struct [%s] does not have the expected type", e->getName().c_str(),
|
||||
e->getParent()->getName().c_str());
|
||||
return NULL;
|
||||
}
|
||||
prev_node = next_node;
|
||||
prev = next + 1;
|
||||
}
|
||||
|
||||
std::string leaf(name.substr(prev, len - prev));
|
||||
return prev_node->get<_retType>(leaf.c_str());
|
||||
};
|
||||
|
||||
class FileConfigReader {
|
||||
public:
|
||||
FileConfigReader(GenericStruct* root);
|
||||
int read(const std::string& filename);
|
||||
int reload();
|
||||
void checkUnread();
|
||||
~FileConfigReader();
|
||||
|
||||
private:
|
||||
int read2(GenericEntry* entry, int level);
|
||||
GenericStruct* mRoot;
|
||||
std::unique_ptr<flexisip::LpConfig> mCfg;
|
||||
std::string mFilename;
|
||||
bool mHaveUnreads;
|
||||
};
|
||||
|
||||
class NotificationEntry : public GenericEntry {
|
||||
Oid& getStringOid();
|
||||
bool mInitialized;
|
||||
std::queue<std::tuple<const GenericEntry*, std::string>> mPendingTraps;
|
||||
|
||||
public:
|
||||
NotificationEntry(const std::string& name, const std::string& help, oid oid_index);
|
||||
virtual void mibFragment(std::ostream& ost, std::string spacing) const;
|
||||
void send(const std::string& msg);
|
||||
void send(const GenericEntry* source, const std::string& msg);
|
||||
void setInitialized(bool status);
|
||||
};
|
||||
|
||||
class ConfigManager : protected ConfigValueListener {
|
||||
friend class ConfigArea;
|
||||
|
||||
public:
|
||||
// Statically register add section functions
|
||||
static std::vector<std::function<void(GenericStruct&)>>& defaultInit();
|
||||
ConfigManager();
|
||||
|
||||
int load(const std::string& configFile);
|
||||
const GenericStruct* getRoot() const;
|
||||
GenericStruct* getRoot();
|
||||
const std::string& getConfigFile() const {
|
||||
return mConfigFile;
|
||||
}
|
||||
|
||||
void setOverrideMap(const std::map<std::string, std::string>& overrides) {
|
||||
mOverrides = overrides;
|
||||
}
|
||||
void setOverrideMap(std::map<std::string, std::string>&& overrides) {
|
||||
mOverrides = std::move(overrides);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>& getOverrideMap() {
|
||||
return mOverrides;
|
||||
}
|
||||
|
||||
const GenericStruct* getGlobal() const;
|
||||
StatCounter64& findStat(const std::string& key);
|
||||
void addStat(const std::string& key, StatCounter64& stat);
|
||||
NotificationEntry* getSnmpNotifier() {
|
||||
return mNotifier;
|
||||
}
|
||||
void sendTrap(const GenericEntry* source, const std::string& msg) {
|
||||
mNotifier->send(source, msg);
|
||||
}
|
||||
void sendTrap(const std::string& msg) {
|
||||
mNotifier->send(&mConfigRoot, msg);
|
||||
}
|
||||
void applyOverrides(bool strict);
|
||||
|
||||
bool mNeedRestart = false;
|
||||
bool mDirtyConfig = false;
|
||||
|
||||
private:
|
||||
bool doIsValidNextConfig(const ConfigValue& cv);
|
||||
bool doOnConfigStateChanged(const ConfigValue& conf, ConfigState state) override;
|
||||
std::string mConfigFile;
|
||||
RootConfigStruct mConfigRoot;
|
||||
FileConfigReader mReader;
|
||||
std::map<std::string, std::string> mOverrides;
|
||||
std::map<std::string, StatCounter64*> mStatMap;
|
||||
std::unordered_set<std::string> mStatOids;
|
||||
NotificationEntry* mNotifier = nullptr;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
79
include/flexisip/dos/module-dos.hh
Normal file
79
include/flexisip/dos/module-dos.hh
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flexisip/module.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class ThreadPool;
|
||||
class BanExecutor;
|
||||
|
||||
struct DosContext {
|
||||
uint64_t recv_msg_count_since_last_check = 0;
|
||||
double last_check_recv_msg_check_time = 0;
|
||||
double packet_count_rate = 0;
|
||||
};
|
||||
|
||||
class ModuleDoSProtection : public Module {
|
||||
friend std::shared_ptr<Module> ModuleInfo<ModuleDoSProtection>::create(Agent*);
|
||||
|
||||
public:
|
||||
~ModuleDoSProtection() override = default;
|
||||
|
||||
#ifdef ENABLE_UNIT_TESTS
|
||||
void clearWhiteList() {
|
||||
mWhiteList.clear();
|
||||
}
|
||||
|
||||
void setBanExecutor(const std::shared_ptr<BanExecutor>& executor);
|
||||
#endif
|
||||
|
||||
private:
|
||||
explicit ModuleDoSProtection(Agent* ag, ModuleInfoBase* moduleInfo);
|
||||
|
||||
void onLoad(const GenericStruct* mc) override;
|
||||
void onUnload() override;
|
||||
void onRequest(std::shared_ptr<RequestSipEvent>& ev) override;
|
||||
void onResponse(std::shared_ptr<ResponseSipEvent>&) override{};
|
||||
void onIdle() override;
|
||||
|
||||
bool isValidNextConfig(const ConfigValue& value) override;
|
||||
|
||||
bool isIpWhiteListed(const char* ip);
|
||||
|
||||
void registerUnbanTimer(const std::string& ip, const std::string& port, const std::string& protocol);
|
||||
void unbanIP(const std::string& ip, const std::string& port, const std::string& protocol);
|
||||
|
||||
static ModuleInfo<ModuleDoSProtection> sInfo;
|
||||
int mTimePeriod;
|
||||
int mPacketRateLimit;
|
||||
int mBanTime;
|
||||
bool mExecutorConfigChecked = false;
|
||||
std::set<BinaryIp> mWhiteList;
|
||||
std::unordered_map<std::string, DosContext> mDosContexts;
|
||||
std::unordered_map<std::string, DosContext>::iterator mDOSHashtableIterator;
|
||||
std::unique_ptr<ThreadPool> mThreadPool;
|
||||
std::shared_ptr<BanExecutor> mBanExecutor;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
225
include/flexisip/event.hh
Normal file
225
include/flexisip/event.hh
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <regex.h>
|
||||
#include <string>
|
||||
|
||||
#include <sofia-sip/msg.h>
|
||||
#include <sofia-sip/nta.h>
|
||||
#include <sofia-sip/sip.h>
|
||||
#include <sofia-sip/tport.h>
|
||||
|
||||
#include "flexisip/sofia-wrapper/msg-sip.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class Agent;
|
||||
class Module;
|
||||
class IncomingAgent;
|
||||
class OutgoingAgent;
|
||||
class IncomingTransaction;
|
||||
class OutgoingTransaction;
|
||||
class EventLog;
|
||||
class EventLogWriteDispatcher;
|
||||
class SocketAddress;
|
||||
|
||||
using MsgSip = sofiasip::MsgSip;
|
||||
|
||||
class SipEvent : public std::enable_shared_from_this<SipEvent> {
|
||||
friend class Agent;
|
||||
|
||||
public:
|
||||
SipEvent(const std::shared_ptr<IncomingAgent>& inAgent,
|
||||
const std::shared_ptr<MsgSip>& msgSip,
|
||||
tport_t* tport = NULL);
|
||||
SipEvent(const std::shared_ptr<OutgoingAgent>& outAgent,
|
||||
const std::shared_ptr<MsgSip>& msgSip,
|
||||
tport_t* tport = NULL);
|
||||
SipEvent(const SipEvent& sipEvent);
|
||||
|
||||
inline const std::shared_ptr<MsgSip>& getMsgSip() const {
|
||||
return mMsgSip;
|
||||
}
|
||||
|
||||
inline su_home_t* getHome() const {
|
||||
return mMsgSip->getHome();
|
||||
}
|
||||
inline sip_t* getSip() const {
|
||||
return mMsgSip->getSip();
|
||||
}
|
||||
|
||||
inline void setMsgSip(std::shared_ptr<MsgSip> msgSip) {
|
||||
mMsgSip = msgSip;
|
||||
}
|
||||
|
||||
virtual void terminateProcessing();
|
||||
|
||||
virtual void suspendProcessing();
|
||||
|
||||
virtual void restartProcessing();
|
||||
|
||||
inline bool isSuspended() const {
|
||||
return mState == State::SUSPENDED;
|
||||
}
|
||||
|
||||
inline bool isTerminated() const {
|
||||
return mState == State::TERMINATED;
|
||||
}
|
||||
|
||||
std::shared_ptr<IncomingAgent> getIncomingAgent() const;
|
||||
|
||||
std::shared_ptr<OutgoingAgent> getOutgoingAgent() const;
|
||||
|
||||
virtual inline void setIncomingAgent(const std::shared_ptr<IncomingAgent>& agent) {
|
||||
mIncomingAgent = agent;
|
||||
}
|
||||
|
||||
virtual inline void setOutgoingAgent(const std::shared_ptr<OutgoingAgent>& agent) {
|
||||
mOutgoingAgent = agent;
|
||||
}
|
||||
|
||||
virtual void send(const std::shared_ptr<MsgSip>& msg,
|
||||
url_string_t const* u = NULL,
|
||||
tag_type_t tag = 0,
|
||||
tag_value_t value = 0,
|
||||
...) = 0;
|
||||
|
||||
virtual ~SipEvent();
|
||||
|
||||
const std::weak_ptr<Module>& getCurrentModule() {
|
||||
return mCurrModule;
|
||||
}
|
||||
|
||||
template <typename _eventLogT>
|
||||
std::shared_ptr<_eventLogT> getEventLog() {
|
||||
return std::dynamic_pointer_cast<_eventLogT>(mEventLog);
|
||||
}
|
||||
void setEventLog(const std::shared_ptr<EventLog>& log);
|
||||
void flushLog(); /*to be used exceptionally when an event log needs to be flushed immediately, for example because
|
||||
you need to submit a new one.*/
|
||||
// Write given EventLog immediately
|
||||
void writeLog(const std::shared_ptr<const EventLogWriteDispatcher>&);
|
||||
std::shared_ptr<IncomingTransaction> getIncomingTransaction();
|
||||
std::shared_ptr<OutgoingTransaction> getOutgoingTransaction();
|
||||
|
||||
const std::shared_ptr<tport_t>& getIncomingTport() const;
|
||||
std::shared_ptr<SocketAddress> getMsgAddress() const;
|
||||
|
||||
protected:
|
||||
enum class State {
|
||||
STARTED,
|
||||
SUSPENDED,
|
||||
TERMINATED,
|
||||
};
|
||||
|
||||
static std::string stateStr(State s) {
|
||||
switch (s) {
|
||||
case State::STARTED:
|
||||
return "STARTED";
|
||||
case State::SUSPENDED:
|
||||
return "SUSPENDED";
|
||||
case State::TERMINATED:
|
||||
return "TERMINATED";
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
std::weak_ptr<Module> mCurrModule;
|
||||
std::shared_ptr<MsgSip> mMsgSip;
|
||||
std::shared_ptr<EventLog> mEventLog;
|
||||
std::weak_ptr<Agent> mAgent;
|
||||
State mState;
|
||||
|
||||
private:
|
||||
std::shared_ptr<tport_t> mIncomingTport;
|
||||
std::weak_ptr<IncomingAgent> mIncomingAgent;
|
||||
std::weak_ptr<OutgoingAgent> mOutgoingAgent;
|
||||
};
|
||||
|
||||
class RequestSipEvent : public SipEvent {
|
||||
public:
|
||||
RequestSipEvent(std::shared_ptr<IncomingAgent> incomingAgent,
|
||||
const std::shared_ptr<MsgSip>& msgSip,
|
||||
tport_t* tport = NULL);
|
||||
RequestSipEvent(const std::shared_ptr<RequestSipEvent>& sipEvent);
|
||||
|
||||
// Sip event extends enable_shared_from_this and constructor should be private.
|
||||
static std::shared_ptr<RequestSipEvent> makeRestored(std::shared_ptr<IncomingAgent> incomingAgent,
|
||||
const std::shared_ptr<MsgSip>& msgSip,
|
||||
const std::weak_ptr<Module>& currModule);
|
||||
|
||||
void suspendProcessing() override;
|
||||
void terminateProcessing() override;
|
||||
std::shared_ptr<IncomingTransaction> createIncomingTransaction();
|
||||
std::shared_ptr<OutgoingTransaction> createOutgoingTransaction();
|
||||
|
||||
void send(const std::shared_ptr<MsgSip>& msg,
|
||||
url_string_t const* u = NULL,
|
||||
tag_type_t tag = 0,
|
||||
tag_value_t value = 0,
|
||||
...) override;
|
||||
|
||||
void reply(int status, char const* phrase, tag_type_t tag, tag_value_t value, ...);
|
||||
|
||||
void setIncomingAgent(const std::shared_ptr<IncomingAgent>& agent) override;
|
||||
|
||||
~RequestSipEvent();
|
||||
|
||||
/** Find if incoming tport TLS client certificate contains a given entry */
|
||||
bool findIncomingSubject(const char* searched) const;
|
||||
const char* findIncomingSubject(const std::list<std::string>& in) const;
|
||||
bool matchIncomingSubject(regex_t* regex);
|
||||
void unlinkTransactions();
|
||||
bool mRecordRouteAdded;
|
||||
|
||||
private:
|
||||
void checkContentLength(const url_t* url);
|
||||
void linkTransactions();
|
||||
std::shared_ptr<OutgoingTransaction> mOutgoingTransactionOwner;
|
||||
};
|
||||
|
||||
class ResponseSipEvent : public SipEvent {
|
||||
public:
|
||||
ResponseSipEvent(std::shared_ptr<OutgoingAgent> outgoingAgent,
|
||||
const std::shared_ptr<MsgSip>& msgSip,
|
||||
tport_t* tport = NULL);
|
||||
ResponseSipEvent(const std::shared_ptr<ResponseSipEvent>& sipEvent);
|
||||
|
||||
virtual void send(const std::shared_ptr<MsgSip>& msg,
|
||||
url_string_t const* u = NULL,
|
||||
tag_type_t tag = 0,
|
||||
tag_value_t value = 0,
|
||||
...);
|
||||
|
||||
virtual void setOutgoingAgent(const std::shared_ptr<OutgoingAgent>& agent);
|
||||
|
||||
~ResponseSipEvent();
|
||||
|
||||
private:
|
||||
void checkContentLength(const std::shared_ptr<MsgSip>& msg, const sip_via_t* via);
|
||||
bool mPopVia; // set to true if the response comes from an outgoing transaction.
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
513
include/flexisip/expressionparser-impl.cc
Normal file
513
include/flexisip/expressionparser-impl.cc
Normal file
|
@ -0,0 +1,513 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation file for the BooleanExpression and BooleanExpressionBuilder templates.
|
||||
* This file must be included from the compilation unit where the template is instanciated.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
#include "flexisip/expressionparser.hh"
|
||||
#include "flexisip/logmanager.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
template <typename _valuesT>
|
||||
class ConstantBooleanExpression : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
ConstantBooleanExpression(bool ret) : mRet(ret){};
|
||||
virtual bool eval([[maybe_unused]] const _valuesT& args) override {
|
||||
return mRet;
|
||||
}
|
||||
bool mRet;
|
||||
};
|
||||
|
||||
template <typename _valuesT>
|
||||
class LogicalAnd : public BooleanExpression<_valuesT> {
|
||||
private:
|
||||
using Expr = BooleanExpression<_valuesT>;
|
||||
shared_ptr<Expr> mExp1, mExp2;
|
||||
public:
|
||||
LogicalAnd(const shared_ptr<Expr> &exp1, const shared_ptr<Expr> &exp2) : mExp1(exp1), mExp2(exp2) {};
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
return mExp1->eval(args) && mExp2->eval(args);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _valuesT>
|
||||
class LogicalOr : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Expr = BooleanExpression<_valuesT>;
|
||||
LogicalOr(const shared_ptr<Expr> &exp1, const shared_ptr<Expr> &exp2) : mExp1(exp1), mExp2(exp2) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
return mExp1->eval(args) || mExp2->eval(args);
|
||||
}
|
||||
private:
|
||||
shared_ptr<Expr> mExp1, mExp2;
|
||||
};
|
||||
|
||||
template <typename _valuesT>
|
||||
class LogicalNot : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Expr = BooleanExpression<_valuesT>;
|
||||
LogicalNot(const shared_ptr<Expr> &exp) : mExp(exp) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
return !mExp->eval(args);
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<Expr> mExp;
|
||||
};
|
||||
|
||||
template <typename _valuesT>
|
||||
class EqualsOp : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
EqualsOp(const shared_ptr<Var> &var1, const shared_ptr<Var> &var2) : mVar1(var1), mVar2(var2) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
return mVar1->get(args) == mVar2->get(args);
|
||||
}
|
||||
private:
|
||||
shared_ptr<Var> mVar1, mVar2;
|
||||
};
|
||||
|
||||
template <typename _valuesT>
|
||||
class UnEqualsOp : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
UnEqualsOp(const shared_ptr<Var> &var1, const shared_ptr<Var> &var2) : mVar1(var1), mVar2(var2) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
return mVar1->get(args) != mVar2->get(args);
|
||||
}
|
||||
private:
|
||||
shared_ptr<Var> mVar1, mVar2;
|
||||
};
|
||||
|
||||
/*
|
||||
* This operator evaluates whether a variable is purely numeric or not.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class NumericOp : public BooleanExpression<_valuesT>{
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
NumericOp(const shared_ptr<Var> &var) : mVar(var) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
string var = mVar->get(args);
|
||||
bool res = true;
|
||||
for (auto it = var.begin(); it != var.end(); ++it) {
|
||||
if (!isdigit(*it)) {
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
private:
|
||||
shared_ptr<Var> mVar;
|
||||
};
|
||||
|
||||
/*
|
||||
* This operator returns true if the variable is defined in the context of provided _valuesT.
|
||||
* It directly uses the defined() method of variable to do this.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class DefinedOp : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
DefinedOp(const shared_ptr<Var> &var) : mVar(var) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) {
|
||||
return mVar->defined(args);
|
||||
}
|
||||
private:
|
||||
shared_ptr<Var> mVar;
|
||||
};
|
||||
|
||||
template <typename _valuesT> class RegexpOp : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
|
||||
RegexpOp(const shared_ptr<Var>& input, const shared_ptr<Constant<_valuesT>>& pattern)
|
||||
: mInput(input), mRegex(pattern->get(), std::regex::ECMAScript | std::regex::nosubs) {
|
||||
}
|
||||
|
||||
virtual bool eval(const _valuesT& args) {
|
||||
if (regex_match(mInput->get(args), mRegex)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<Var> mInput;
|
||||
std::regex mRegex;
|
||||
};
|
||||
|
||||
template <typename _valuesT>
|
||||
class ContainsOp : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
ContainsOp(const shared_ptr<Var> &var1, const shared_ptr<Var> &var2) : mVar1(var1), mVar2(var2) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
string var1 = mVar1->get(args);
|
||||
string var2 = mVar2->get(args);
|
||||
return var1.find(var2) != string::npos;
|
||||
}
|
||||
private:
|
||||
shared_ptr<Var> mVar1, mVar2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Evaluates whether a variable has its value equal to an element of a list of other variables.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class InOp : public BooleanExpression<_valuesT> {
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
InOp(const shared_ptr<Var> &var1, const shared_ptr<Var> &var2) : mVar1(var1), mVar2(var2) {
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) {
|
||||
bool res = false;
|
||||
list<string> values = mVar2->getAsList(args);
|
||||
string varValue = mVar1->get(args);
|
||||
|
||||
for (auto it = values.begin(); it != values.end(); ++it) {
|
||||
if (varValue == *it) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
private:
|
||||
shared_ptr<Var> mVar1, mVar2;
|
||||
};
|
||||
|
||||
template< typename _valuesT>
|
||||
size_t BooleanExpressionBuilder<_valuesT>::findFirstNonWord(const string &expr, size_t offset) {
|
||||
size_t i;
|
||||
for (i = offset; i < expr.size(); ++i) {
|
||||
char c = expr[i];
|
||||
if (c != '-' && c != '_' && c != '.' && !isalnum(c))
|
||||
return i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
shared_ptr<Variable<_valuesT>> BooleanExpressionBuilder<_valuesT>::buildVariable(const string &expr, size_t *newpos) {
|
||||
shared_ptr<Var> ret = dynamic_pointer_cast<Var>(buildElement(expr,newpos));
|
||||
if (ret == nullptr){
|
||||
throw invalid_argument("Expected variable at " + expr.substr(*newpos, string::npos));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
shared_ptr<Constant<_valuesT>> BooleanExpressionBuilder<_valuesT>::buildConstant(const string &expr, size_t *newpos) {
|
||||
shared_ptr<Constant<_valuesT>> ret = dynamic_pointer_cast<Constant<_valuesT>>(buildElement(expr,newpos));
|
||||
if (ret == nullptr){
|
||||
throw invalid_argument("Expected constant at " + expr.substr(*newpos, string::npos));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
std::shared_ptr<ExpressionElement> BooleanExpressionBuilder<_valuesT>::buildElement(const std::string &expr, size_t *newpos){
|
||||
while (expr[*newpos] == ' ' || expr[*newpos] == '\t'){
|
||||
*newpos += 1;
|
||||
}
|
||||
if (expr[*newpos] == '\'') {
|
||||
size_t end = expr.find_first_of('\'', *newpos + 1);
|
||||
if (end == string::npos) throw invalid_argument("Missing quote around " + expr);
|
||||
size_t len = end - *newpos - 1;
|
||||
auto cons = expr.substr(*newpos + 1, len);
|
||||
*newpos += len + 2; // remove the two '
|
||||
return make_shared<Constant<_valuesT>>(cons);
|
||||
}else{
|
||||
// Can be a variable or a named operator
|
||||
size_t eow = findFirstNonWord(expr, *newpos);
|
||||
if (eow <= *newpos && expr.size() > eow) {
|
||||
throw invalid_argument("no variable recognized in X" + expr.substr(*newpos, string::npos) + "XX");
|
||||
}
|
||||
size_t len = eow - *newpos;
|
||||
auto word = expr.substr(*newpos, len);
|
||||
*newpos += len;
|
||||
auto varIt = mRules.variables.find(word);
|
||||
auto opIt = mRules.operators.find(word);
|
||||
if (varIt != mRules.variables.end()){
|
||||
return make_shared<Variable<_valuesT>>((*varIt).second);
|
||||
}else if (opIt != mRules.operators.end()){
|
||||
return make_shared<NamedOperator<_valuesT>>((*opIt).second);
|
||||
}else{
|
||||
throw invalid_argument("Element '" + word + "' is not a variable nor operator name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
size_t BooleanExpressionBuilder<_valuesT>::findMatchingClosingParenthesis(const string &expr, size_t offset) {
|
||||
size_t i;
|
||||
int match = 1;
|
||||
for (i = offset; i < expr.size(); ++i) {
|
||||
if (expr[i] == '(')
|
||||
++match;
|
||||
else if (expr[i] == ')')
|
||||
--match;
|
||||
if (match == 0)
|
||||
return i;
|
||||
}
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
bool BooleanExpressionBuilder<_valuesT>::isKeyword(const string &expr, size_t *newpos, const string &keyword) {
|
||||
size_t pos = *newpos;
|
||||
size_t keyLen = keyword.size();
|
||||
size_t availableLen = expr.size() - pos;
|
||||
if (availableLen < keyLen)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < keyLen; ++i) {
|
||||
if (expr[pos + i] != keyword[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
if (availableLen > keyLen && isalnum(expr[pos + keyLen]))
|
||||
return false;
|
||||
|
||||
*newpos += keyLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
void BooleanExpressionBuilder<_valuesT>::checkRulesOverlap(){
|
||||
for(const string & builtin : sBuiltinOperators){
|
||||
if (mRules.variables.find(builtin) != mRules.variables.end()){
|
||||
LOGF("BooleanExpressionBuilder: variable name '%s' conflicts with builtin operator name.", builtin.c_str());
|
||||
}
|
||||
if (mRules.operators.find(builtin) != mRules.operators.end()){
|
||||
LOGF("BooleanExpressionBuilder: variable name '%s' conflicts with builtin operator name.", builtin.c_str());
|
||||
}
|
||||
}
|
||||
for (auto p : mRules.operators){
|
||||
if (mRules.variables.find(p.first) != mRules.variables.end()){
|
||||
LOGF("BooleanExpressionBuilder: variable name '%s' conflicts with operator name.", p.first.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
BooleanExpressionBuilder<_valuesT>::BooleanExpressionBuilder(const ExpressionRules<_valuesT> &rules) : mRules(rules){
|
||||
checkRulesOverlap();
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
std::shared_ptr<BooleanExpression<_valuesT>> BooleanExpressionBuilder<_valuesT>::parse(const std::string &expression){
|
||||
if (expression.empty())
|
||||
return make_shared<ConstantBooleanExpression<_valuesT>>(true); /* By arbitrary decision, we evaluate void to true.*/
|
||||
size_t pos = 0;
|
||||
return parseExpression(expression, &pos);
|
||||
}
|
||||
|
||||
template< typename _valuesT>
|
||||
const std::list<std::string> BooleanExpressionBuilder<_valuesT>::sBuiltinOperators = {
|
||||
"&&", "||", "!", "==", "!=", "contains", "in", "notin", "nin", "defined", "regexp", "regex", "numeric",
|
||||
"true", "false"
|
||||
};
|
||||
|
||||
template< typename _valuesT>
|
||||
shared_ptr<BooleanExpression<_valuesT>> BooleanExpressionBuilder<_valuesT>::parseExpression(const string &expr, size_t *newpos, bool immediateNeighbour) {
|
||||
size_t i;
|
||||
shared_ptr<Expr> cur_exp;
|
||||
shared_ptr<Var> cur_var;
|
||||
|
||||
for (i = 0; i < expr.size();) {
|
||||
size_t j = 0;
|
||||
size_t prev_i = i;
|
||||
switch (expr[i]) {
|
||||
case '(': {
|
||||
size_t end = findMatchingClosingParenthesis(expr, i + 1);
|
||||
if (end != string::npos) {
|
||||
cur_exp = parseExpression(expr.substr(i + 1, end - i - 1), &j);
|
||||
i = end + 1;
|
||||
} else {
|
||||
throw invalid_argument("Missing parenthesis around " + expr);
|
||||
}
|
||||
} break;
|
||||
case '&':
|
||||
if (expr[i + 1] == '&') {
|
||||
if (!cur_exp) {
|
||||
throw new logic_error("&& operator expects first operand.");
|
||||
}
|
||||
i += 2;
|
||||
cur_exp = make_shared<LogicalAnd<_valuesT>>(cur_exp, parseExpression(expr.substr(i), &j));
|
||||
i += j;
|
||||
} else {
|
||||
throw new logic_error("Bad operator '&'");
|
||||
}
|
||||
break;
|
||||
case '|':
|
||||
if (expr[i + 1] == '|') {
|
||||
if (!cur_exp) {
|
||||
throw new logic_error("|| operator expects first operand.");
|
||||
}
|
||||
i += 2;
|
||||
cur_exp = make_shared<LogicalOr<_valuesT>>(cur_exp, parseExpression(expr.substr(i), &j));
|
||||
i += j;
|
||||
} else {
|
||||
throw invalid_argument("Bad operator '|'");
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
if (expr[i + 1] == '=') {
|
||||
if (!cur_var) {
|
||||
throw invalid_argument("!= operator expects first variable or const operand.");
|
||||
}
|
||||
i += 2;
|
||||
cur_exp = make_shared<UnEqualsOp<_valuesT>>(cur_var, buildVariable(expr.substr(i), &j));
|
||||
} else {
|
||||
if (cur_exp) {
|
||||
throw invalid_argument("Parsing error around '!'");
|
||||
}
|
||||
i++;
|
||||
cur_exp = make_shared<LogicalNot<_valuesT>>(parseExpression(expr.substr(i), &j, true));
|
||||
}
|
||||
i += j;
|
||||
break;
|
||||
case '=':
|
||||
if (expr[i + 1] == '=') {
|
||||
if (!cur_var) {
|
||||
throw invalid_argument("== operator expects first variable or const operand.");
|
||||
}
|
||||
i += 2;
|
||||
cur_exp = make_shared<EqualsOp<_valuesT>>(cur_var, buildVariable(expr.substr(i), &j));
|
||||
i += j;
|
||||
} else {
|
||||
throw invalid_argument("Bad operator =");
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
i++;
|
||||
break;
|
||||
case 'c':
|
||||
if (isKeyword(expr.substr(i), &j, "contains")) {
|
||||
i += j;
|
||||
j = 0;
|
||||
if (cur_var == nullptr) throw invalid_argument("'contains' operator has no left-hand operand.");
|
||||
auto rightVar = buildVariable(expr.substr(i), &j);
|
||||
cur_exp = make_shared<ContainsOp<_valuesT>>(cur_var, rightVar);
|
||||
i += j;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
if (isKeyword(expr.substr(i), &j, "defined")) {
|
||||
i += j;
|
||||
j = 0;
|
||||
auto rightVar = buildVariable(expr.substr(i), &j);
|
||||
cur_exp = make_shared<DefinedOp<_valuesT>>(rightVar);
|
||||
i += j;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (isKeyword(expr.substr(i), &j, "regexp") || isKeyword(expr.substr(i), &j, "regex")) {
|
||||
i += j;
|
||||
j = 0;
|
||||
auto pattern = buildConstant(expr.substr(i), &j);
|
||||
cur_exp = make_shared<RegexpOp<_valuesT>>(cur_var, pattern);
|
||||
i += j;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
if (isKeyword(expr.substr(i), &j, "in")) {
|
||||
i += j;
|
||||
j = 0;
|
||||
auto rightVar = buildVariable(expr.substr(i), &j);
|
||||
cur_exp = make_shared<InOp<_valuesT>>(cur_var, rightVar);
|
||||
i += j;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (isKeyword(expr.substr(i), &j, "numeric")) {
|
||||
if (cur_exp || cur_var) {
|
||||
throw invalid_argument("Parsing error around 'numeric'");
|
||||
}
|
||||
i += j;
|
||||
j = 0;
|
||||
auto var = buildVariable(expr.substr(i), &j);
|
||||
cur_exp = make_shared<NumericOp<_valuesT>>(var);
|
||||
i += j;
|
||||
j = 0;
|
||||
} else if (isKeyword(expr.substr(i), &j, "nin") || isKeyword(expr.substr(i), &j, "notin")) {
|
||||
i += j;
|
||||
j = 0;
|
||||
auto rightVar = buildVariable(expr.substr(i), &j);
|
||||
auto in = make_shared<InOp<_valuesT>>(cur_var, rightVar);
|
||||
cur_exp = make_shared<LogicalNot<_valuesT>>(in);
|
||||
i += j;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (isKeyword(expr.substr(i), &j, "true")) {
|
||||
i += j;
|
||||
cur_exp = make_shared<ConstantBooleanExpression<_valuesT>>(true);
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (isKeyword(expr.substr(i), &j, "false")) {
|
||||
i += j;
|
||||
cur_exp = make_shared<ConstantBooleanExpression<_valuesT>>(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (prev_i == i){ /*nothing was handled*/
|
||||
shared_ptr<ExpressionElement> element = buildElement(expr.substr(i), &j);
|
||||
i += j;
|
||||
if (dynamic_pointer_cast<Var>(element)){
|
||||
cur_var = dynamic_pointer_cast<Var>(element);
|
||||
}else if (dynamic_pointer_cast<NamedOperator<_valuesT>>(element)){
|
||||
cur_exp = dynamic_pointer_cast<NamedOperator<_valuesT>>(element);
|
||||
}
|
||||
}
|
||||
if (immediateNeighbour && cur_exp) break;
|
||||
}
|
||||
*newpos += i;
|
||||
if (!cur_exp){
|
||||
throw invalid_argument("Meaning-less expression, possibly without operator.");
|
||||
}
|
||||
return cur_exp;
|
||||
};
|
||||
|
||||
// rajouter is_request, is_response
|
||||
|
||||
|
||||
} //end of namespace
|
177
include/flexisip/expressionparser.hh
Normal file
177
include/flexisip/expressionparser.hh
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2015 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
|
||||
class ExpressionElement{
|
||||
public:
|
||||
virtual ~ExpressionElement() = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Variable represents a text field which is evaluated at run-time using the _valuesT argument.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class Variable : public ExpressionElement{
|
||||
public:
|
||||
Variable(const std::function< std::string (const _valuesT &)> &func) : mFunc(func){
|
||||
}
|
||||
~Variable() = default;
|
||||
virtual std::string get(const _valuesT &args){
|
||||
return mFunc(args);
|
||||
}
|
||||
virtual bool defined(const _valuesT &args){
|
||||
if (get(args).empty()) return false;
|
||||
return true;
|
||||
}
|
||||
virtual std::list<std::string> getAsList(const _valuesT &args) {
|
||||
std::list<std::string> valueList;
|
||||
std::string s = get(args);
|
||||
|
||||
size_t pos1 = 0;
|
||||
size_t pos2 = 0;
|
||||
for (pos2 = 0; pos2 < s.size(); ++pos2) {
|
||||
if (s[pos2] != ' ') {
|
||||
if (s[pos1] == ' ')
|
||||
pos1 = pos2;
|
||||
continue;
|
||||
}
|
||||
if (s[pos2] == ' ' && s[pos1] == ' ') {
|
||||
pos1 = pos2;
|
||||
continue;
|
||||
}
|
||||
valueList.push_back(s.substr(pos1, pos2 - pos1));
|
||||
pos1 = pos2;
|
||||
}
|
||||
|
||||
if (pos1 != pos2)
|
||||
valueList.push_back(s.substr(pos1, pos2 - pos1));
|
||||
|
||||
return valueList;
|
||||
}
|
||||
private:
|
||||
std::function< std::string (const _valuesT &)> mFunc;
|
||||
protected:
|
||||
Variable() = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Constant can be seen as a special kind of variable that always evaluates to the same thing, regardless of _valuesT argument contains.
|
||||
* They are enclosed by single quotes in the boolean expression.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class Constant : public Variable<_valuesT>{
|
||||
std::string mVal;
|
||||
public:
|
||||
Constant(const std::string &val) : Variable<_valuesT>(), mVal(val) {
|
||||
}
|
||||
virtual std::string get([[maybe_unused]] const _valuesT &arg) override{
|
||||
return mVal;
|
||||
}
|
||||
std::string get()const{
|
||||
return mVal;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Base class for our boolean expression.
|
||||
* It contains the factory method to create BooleanExpression from an input string,
|
||||
* and the eval() method to evaluates the BooleanExpression to true or false according
|
||||
* to supplied _valuesT arguments.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class BooleanExpression {
|
||||
public:
|
||||
virtual ~BooleanExpression() = default;
|
||||
virtual bool eval(const _valuesT &args) = 0;
|
||||
protected:
|
||||
BooleanExpression() = default;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A named operator is a function that evaluates on the values provided to return
|
||||
* true or false.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class NamedOperator : public BooleanExpression<_valuesT>, public ExpressionElement{
|
||||
public:
|
||||
NamedOperator(const std::function< bool (const _valuesT &)> func) : mFunc(func){
|
||||
}
|
||||
virtual bool eval(const _valuesT &args) override{
|
||||
return mFunc(args);
|
||||
}
|
||||
private:
|
||||
std::function< bool (const _valuesT &)> mFunc;
|
||||
};
|
||||
|
||||
/*
|
||||
* The ExpressionRules consist of two maps suitable to be initialized with builtin initializers.
|
||||
* The variables map provides mapping between a variable name and function to be called to get the
|
||||
* variable's value in the _valuesT argument.
|
||||
* The operators map provides the mapping between operator names and the function that evaluates them.
|
||||
*/
|
||||
|
||||
template <typename _valuesT>
|
||||
struct ExpressionRules{
|
||||
public:
|
||||
std::map<std::string, std::function< std::string (const _valuesT &)>> variables; // the map of variables with their function to evaluate
|
||||
std::map<std::string, std::function< bool (const _valuesT &)>> operators; // the named operators, with their function to evaluate.
|
||||
};
|
||||
|
||||
/*
|
||||
* The BooleanExpressionBuilder creates BooleanExpression by parsing an input string.
|
||||
* The BooleanExpression is constructed according to the rules provided in the constructor,
|
||||
* which gave the map of allowed variables and named operators.
|
||||
*/
|
||||
template <typename _valuesT>
|
||||
class BooleanExpressionBuilder{
|
||||
public:
|
||||
using Var = Variable<_valuesT>;
|
||||
using Const = Constant<_valuesT>;
|
||||
using Expr = BooleanExpression<_valuesT>;
|
||||
BooleanExpressionBuilder(const ExpressionRules<_valuesT> &rules);
|
||||
std::shared_ptr<BooleanExpression<_valuesT>> parse(const std::string &expression);
|
||||
private:
|
||||
void checkRulesOverlap();
|
||||
size_t findFirstNonWord(const std::string &expr, size_t offset);
|
||||
size_t findMatchingClosingParenthesis(const std::string &expr, size_t offset);
|
||||
bool isKeyword(const std::string &expr, size_t *newpos, const std::string &keyword);
|
||||
std::shared_ptr<Var> buildVariable(const std::string &expr, size_t *newpos);
|
||||
std::shared_ptr<Const> buildConstant(const std::string &expr, size_t *newpos);
|
||||
std::shared_ptr<ExpressionElement> buildElement(const std::string &expr, size_t *newpos);
|
||||
std::shared_ptr<Expr> parseExpression(const std::string &expr, size_t *newpos, bool immediateNeighbour = false);
|
||||
const ExpressionRules<_valuesT> mRules;
|
||||
static const std::list<std::string> sBuiltinOperators;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
143
include/flexisip/flexisip-exception.hh
Normal file
143
include/flexisip/flexisip-exception.hh
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "sofia-sip/sip_status.h"
|
||||
|
||||
#include <bctoolbox/exception.hh>
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
/**
|
||||
* @brief This exception inherits \ref BctoolboxException.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class FlexisipException : public BctbxException {
|
||||
public:
|
||||
FlexisipException() = default;
|
||||
explicit FlexisipException(const std::string& message) : BctbxException(message) {
|
||||
}
|
||||
explicit FlexisipException(const char* message) : BctbxException(message) {
|
||||
}
|
||||
~FlexisipException() throw() override = default;
|
||||
FlexisipException(const FlexisipException& other) = default;
|
||||
|
||||
template <typename T2>
|
||||
FlexisipException& operator<<(const T2& val) {
|
||||
BctbxException::operator<<(val);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#define FLEXISIP_EXCEPTION FlexisipException() << " " << __FILE__ << ":" << __LINE__ << " "
|
||||
|
||||
/**
|
||||
* @brief Sip response class.
|
||||
*
|
||||
*/
|
||||
class SipStatus {
|
||||
public:
|
||||
SipStatus(int code, std::string_view phrase) : mCode(code), mReason(phrase) {
|
||||
}
|
||||
int getCode() const {
|
||||
return mCode;
|
||||
}
|
||||
const char* getReason() const {
|
||||
return mReason.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
int mCode;
|
||||
std::string mReason;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This exception reports all sip errors.
|
||||
*
|
||||
*/
|
||||
class GenericSipException : public std::runtime_error {
|
||||
public:
|
||||
GenericSipException(int statusCode, std::string_view statusPhrase)
|
||||
: GenericSipException(statusCode, statusPhrase, "") {
|
||||
}
|
||||
GenericSipException(int statusCode, std::string_view statusPhrase, std::string_view additionalMsg)
|
||||
: std::runtime_error(statusPhrase.data()), mSipStatus(statusCode, statusPhrase), mMsg(statusPhrase) {
|
||||
if (!additionalMsg.empty()) mMsg += std::string(": ") + additionalMsg.data();
|
||||
}
|
||||
virtual ~GenericSipException() = default;
|
||||
void addLocation(const char* file, int line) {
|
||||
mMsg = std::string("Exception in ") + file + ":" + std::to_string(line) + " " + mMsg;
|
||||
}
|
||||
virtual const SipStatus& getSipStatus() const noexcept {
|
||||
return mSipStatus;
|
||||
};
|
||||
virtual const char* what() const noexcept override {
|
||||
return mMsg.data();
|
||||
};
|
||||
|
||||
private:
|
||||
const SipStatus mSipStatus;
|
||||
std::string mMsg;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This exception inherits \ref GenericSipException and reports client errors on request.
|
||||
*
|
||||
*/
|
||||
class InvalidRequestError : public GenericSipException {
|
||||
public:
|
||||
InvalidRequestError() : InvalidRequestError("") {
|
||||
}
|
||||
InvalidRequestError(std::string_view additionalMsg) : GenericSipException(SIP_400_BAD_REQUEST, additionalMsg) {
|
||||
}
|
||||
InvalidRequestError(std::string_view reasonSuffix, std::string_view additionalMsg)
|
||||
: GenericSipException(400, std::string(sip_status_phrase(400)) + " - " + reasonSuffix.data(), additionalMsg) {
|
||||
}
|
||||
virtual ~InvalidRequestError() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This exception inherits \ref GenericSipException and reports server errors.
|
||||
*
|
||||
*/
|
||||
class InternalError : public GenericSipException {
|
||||
public:
|
||||
InternalError() : InternalError("") {
|
||||
}
|
||||
InternalError(std::string_view additionalMsg) : GenericSipException(SIP_500_INTERNAL_SERVER_ERROR, additionalMsg) {
|
||||
}
|
||||
InternalError(std::string_view reasonSuffix, std::string_view additionalMsg)
|
||||
: GenericSipException(500, std::string(sip_status_phrase(500)) + " - " + reasonSuffix.data(), additionalMsg) {
|
||||
}
|
||||
virtual ~InternalError() = default;
|
||||
};
|
||||
|
||||
#define THROW_LINE(myException, ...) \
|
||||
do { \
|
||||
auto e = myException(__VA_ARGS__); \
|
||||
e.addLocation(__FILE__, __LINE__); \
|
||||
throw e; \
|
||||
} while (false)
|
||||
|
||||
} // namespace flexisip
|
151
include/flexisip/fork-context/fork-context.hh
Normal file
151
include/flexisip/fork-context/fork-context.hh
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "flexisip/pushnotification/pushnotification-context-observer.hh"
|
||||
#include "flexisip/sofia-wrapper/msg-sip.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
enum class FinalStatusMode;
|
||||
class BranchInfo;
|
||||
class IncomingTransaction;
|
||||
class OutgoingTransaction;
|
||||
class RequestSipEvent;
|
||||
class ResponseSipEvent;
|
||||
class SipUri;
|
||||
|
||||
struct ExtendedContact;
|
||||
|
||||
struct ForkContextConfig {
|
||||
int mDeliveryTimeout = 0; /* in seconds, used for "late" forking*/
|
||||
std::chrono::seconds mUrgentTimeout{5}; /*timeout for sending buffered urgent or retryable responses (like 415).*/
|
||||
std::chrono::seconds mPushResponseTimeout{0}; /*timeout for receiving response to push */
|
||||
int mCurrentBranchesTimeout = 0; /*timeout for receiving response on current branches*/
|
||||
bool mForkLate = false;
|
||||
bool mSaveForkMessageEnabled = false;
|
||||
bool mTreatAllErrorsAsUrgent = false; /*treat all SIP response code as urgent replies in the fork mechanism.*/
|
||||
bool mForkNoGlobalDecline = false;
|
||||
bool mTreatDeclineAsUrgent =
|
||||
false; /*treat 603 declined as a urgent response, only useful is mForkNoGlobalDecline==true*/
|
||||
bool mPermitSelfGeneratedProvisionalResponse = true; /* Self explicit. Ex: 110 Push sent, 180 Ringing*/
|
||||
};
|
||||
|
||||
class ForkContext : public PushNotificationContextObserver {
|
||||
public:
|
||||
virtual ~ForkContext() = default;
|
||||
|
||||
// Obtain the ForkContext that manages a transaction.
|
||||
static std::shared_ptr<ForkContext> getFork(const std::shared_ptr<IncomingTransaction>& tr);
|
||||
static std::shared_ptr<ForkContext> getFork(const std::shared_ptr<OutgoingTransaction>& tr);
|
||||
// Set the ForkContext managed by an incoming transaction.
|
||||
static void setFork(const std::shared_ptr<IncomingTransaction>& tr, const std::shared_ptr<ForkContext>& fork);
|
||||
|
||||
// Called by the router module to notify a cancellation.
|
||||
static void processCancel(const std::shared_ptr<RequestSipEvent>& ev);
|
||||
// called by the router module to notify the arrival of a response.
|
||||
static bool processResponse(const std::shared_ptr<ResponseSipEvent>& ev);
|
||||
|
||||
bool isEqual(const std::shared_ptr<ForkContext>& other) const {
|
||||
return getPtrForEquality() == other->getPtrForEquality();
|
||||
}
|
||||
|
||||
// Called by the Router module to create a new branch.
|
||||
virtual std::shared_ptr<BranchInfo> addBranch(const std::shared_ptr<RequestSipEvent>& ev,
|
||||
const std::shared_ptr<ExtendedContact>& contact) = 0;
|
||||
virtual bool allCurrentBranchesAnswered(FinalStatusMode finalStatusMode) const = 0;
|
||||
// Request if the fork has other branches with lower priorities to try
|
||||
virtual bool hasNextBranches() const = 0;
|
||||
/**
|
||||
* Called when a fatal internal error is thrown in Flexisip. Send a custom response and cancel all branches if
|
||||
* necessary.
|
||||
* @param status The status of the custom response to send.
|
||||
* @param phrase The content of the custom response to send.
|
||||
*/
|
||||
virtual void processInternalError(int status, const char* phrase) = 0;
|
||||
// Start the processing of the highest priority branches that are not completed yet
|
||||
virtual void start() = 0;
|
||||
|
||||
virtual void addKey(const std::string& key) = 0;
|
||||
virtual const std::vector<std::string>& getKeys() const = 0;
|
||||
|
||||
/**
|
||||
* Informs the forked call context that a new register from a potential destination of the fork just arrived.
|
||||
* If the fork context is interested in handling this new destination he can call
|
||||
* ForkContextListener::onDispatchNeeded, call ForkContextListener::onUselessRegisterNotification otherwise.
|
||||
*
|
||||
* Typical case for refusing it is when another transaction already exists or existed for this contact.
|
||||
*/
|
||||
virtual void
|
||||
onNewRegister(const SipUri& dest, const std::string& uid, const std::shared_ptr<ExtendedContact>& newContact) = 0;
|
||||
// Notifies the cancellation of the fork process.
|
||||
virtual void onCancel(const std::shared_ptr<RequestSipEvent>& ev) = 0;
|
||||
// Notifies the arrival of a new response on a given branch
|
||||
virtual void onResponse(const std::shared_ptr<BranchInfo>& br, const std::shared_ptr<ResponseSipEvent>& event) = 0;
|
||||
virtual const std::shared_ptr<RequestSipEvent>& getEvent() = 0;
|
||||
virtual const std::shared_ptr<ForkContextConfig>& getConfig() const = 0;
|
||||
virtual bool isFinished() const = 0;
|
||||
/**
|
||||
* Check if the fork context should be considered as finished. A final answer is sent if needed.
|
||||
* If a final answer is sent and correspond to a branch, this branch is returned.
|
||||
*/
|
||||
virtual std::shared_ptr<BranchInfo> checkFinished() = 0;
|
||||
virtual sofiasip::MsgSipPriority getMsgPriority() const = 0;
|
||||
virtual const ForkContext* getPtrForEquality() const = 0;
|
||||
|
||||
protected:
|
||||
// Protected methods
|
||||
std::string errorLogPrefix() const;
|
||||
std::string logPrefix() const;
|
||||
virtual const char* getClassName() const = 0;
|
||||
};
|
||||
|
||||
enum class DispatchStatus {
|
||||
DispatchNeeded,
|
||||
DispatchNotNeeded,
|
||||
PendingTransaction,
|
||||
};
|
||||
|
||||
class ForkContextListener {
|
||||
public:
|
||||
virtual ~ForkContextListener() = default;
|
||||
|
||||
virtual void onForkContextFinished(const std::shared_ptr<ForkContext>& ctx) = 0;
|
||||
|
||||
/**
|
||||
* Called when a fork context need a dispatch for specific contact.
|
||||
*/
|
||||
virtual std::shared_ptr<BranchInfo> onDispatchNeeded(const std::shared_ptr<ForkContext>& ctx,
|
||||
const std::shared_ptr<ExtendedContact>& newContact) = 0;
|
||||
|
||||
/**
|
||||
* Called when onNewRegister was called on a fork and that no dispatch was needed for this contact.
|
||||
*/
|
||||
virtual void onUselessRegisterNotification(const std::shared_ptr<ForkContext>& ctx,
|
||||
const std::shared_ptr<ExtendedContact>& newContact,
|
||||
const SipUri& dest,
|
||||
const std::string& uid,
|
||||
const DispatchStatus reason) = 0;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
25
include/flexisip/global.hh
Normal file
25
include/flexisip/global.hh
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2018 Belledonne Communications SARL.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#define FLEXISIP_DISABLE_COPY(CLASS) \
|
||||
CLASS(const CLASS &) = delete; \
|
||||
CLASS &operator=(const CLASS &) = delete
|
242
include/flexisip/logmanager.hh
Normal file
242
include/flexisip/logmanager.hh
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#ifndef FLEXISIP_USER_ERRORS_LOG_DOMAIN
|
||||
#define FLEXISIP_USER_ERRORS_LOG_DOMAIN "flexisip-users"
|
||||
#endif
|
||||
|
||||
#define FLEXISIP_LOG_DOMAIN "flexisip"
|
||||
|
||||
#ifndef BCTBX_LOG_DOMAIN
|
||||
#define BCTBX_LOG_DOMAIN FLEXISIP_LOG_DOMAIN
|
||||
#endif
|
||||
|
||||
#include <bctoolbox/logging.h>
|
||||
#include <sofia-sip/sip.h>
|
||||
|
||||
#include "flexisip/sip-boolean-expressions.hh"
|
||||
#include "flexisip/sofia-wrapper/timer.hh"
|
||||
|
||||
/*
|
||||
* These are the classic C-style logging macros.
|
||||
*/
|
||||
#define LOGT bctbx_debug
|
||||
#define LOGD bctbx_debug
|
||||
#define LOGI bctbx_message
|
||||
#define LOGW bctbx_warning
|
||||
#define LOGE bctbx_error
|
||||
#define LOGA bctbx_fatal
|
||||
|
||||
#define LOGV(thelevel, thefmt, theargs) bctbx_logv(FLEXISIP_LOG_DOMAIN, thelevel, (thefmt), (theargs))
|
||||
#define LOGDV(thefmt, theargs) LOGV(BCTBX_LOG_DEBUG, thefmt, theargs)
|
||||
|
||||
/*
|
||||
* These are the C++ logging macros, that can be used with << operator.
|
||||
*/
|
||||
#define SLOG(thelevel) BCTBX_SLOG(FLEXISIP_LOG_DOMAIN, thelevel)
|
||||
#define SLOGT SLOG(BCTBX_LOG_DEBUG)
|
||||
#define SLOGD SLOG(BCTBX_LOG_DEBUG)
|
||||
#define SLOGI SLOG(BCTBX_LOG_MESSAGE)
|
||||
#define SLOGW SLOG(BCTBX_LOG_WARNING)
|
||||
#define SLOGE SLOG(BCTBX_LOG_ERROR)
|
||||
#define SLOGUE BCTBX_SLOG(FLEXISIP_USER_ERRORS_LOG_DOMAIN, BCTBX_LOG_ERROR)
|
||||
|
||||
namespace sofiasip {
|
||||
class MsgSip;
|
||||
}
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class SipLogContext;
|
||||
|
||||
using MsgSip = sofiasip::MsgSip;
|
||||
|
||||
/*
|
||||
* The LogManager is the main entry point to configure logs in Flexisip.
|
||||
*/
|
||||
class LogManager {
|
||||
public:
|
||||
// Public types
|
||||
struct Parameters {
|
||||
std::shared_ptr<sofiasip::SuRoot> root{nullptr}; /* MUST be set to have reopenFiles() working. */
|
||||
std::string logDirectory{};
|
||||
std::string logFilename{};
|
||||
size_t fileMaxSize{std::numeric_limits<decltype(fileMaxSize)>::max()};
|
||||
BctbxLogLevel level{BCTBX_LOG_ERROR};
|
||||
BctbxLogLevel syslogLevel{BCTBX_LOG_ERROR};
|
||||
bool enableSyslog{true};
|
||||
bool enableUserErrors{false};
|
||||
bool enableStdout{false};
|
||||
};
|
||||
|
||||
// Public ctor
|
||||
LogManager(const LogManager&) = delete;
|
||||
~LogManager();
|
||||
|
||||
// Public methods
|
||||
BctbxLogLevel logLevelFromName(const std::string& name) const;
|
||||
// Initialize logging system
|
||||
void initialize(const Parameters& params);
|
||||
// Change log level
|
||||
void setLogLevel(BctbxLogLevel level);
|
||||
// Change log level
|
||||
void setSyslogLevel(BctbxLogLevel level);
|
||||
void enableUserErrorsLogs(bool val);
|
||||
/*
|
||||
* Set a contextual filter based on sip message contents, and associated log level to use when the filter matches.
|
||||
* Returns -1 if the filter is not valid.
|
||||
*/
|
||||
int setContextualFilter(const std::string& expression);
|
||||
/*
|
||||
* Set the log level when the contextual filter is matched.
|
||||
*/
|
||||
void setContextualLevel(BctbxLogLevel level);
|
||||
|
||||
// Disable all logs.
|
||||
void disable();
|
||||
|
||||
bool syslogEnabled() const {
|
||||
return mSysLogHandler != nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Require the reopening of each log file.
|
||||
* @note This method can be used inside UNIX signal handlers.
|
||||
*/
|
||||
void reopenFiles() {
|
||||
mReopenRequired = true;
|
||||
}
|
||||
|
||||
// Public class methods
|
||||
static LogManager& get();
|
||||
|
||||
private:
|
||||
// Private ctor
|
||||
LogManager() = default;
|
||||
|
||||
// Private methods
|
||||
void setCurrentContext(const SipLogContext& ctx);
|
||||
void clearCurrentContext();
|
||||
void checkForReopening();
|
||||
static void stdoutLogHandler(const char* domain, BctbxLogLevel level, const char* msg, va_list args);
|
||||
static void logStub(const char* domain, BctbxLogLevel level, const char* msg, va_list args);
|
||||
|
||||
// Private attributes
|
||||
std::mutex mMutex{};
|
||||
mutable std::mutex mRootDomainMutex{};
|
||||
std::shared_ptr<SipBooleanExpression> mCurrentFilter{};
|
||||
std::string mRootDomain{}; // This domain prefixed the domain part of every log message. Useful to distinct the log
|
||||
// messages comming from other processus.
|
||||
BctbxLogLevel mLevel{BCTBX_LOG_ERROR}; // The normal log level.
|
||||
BctbxLogLevel mContextLevel{BCTBX_LOG_ERROR}; // The log level when log context matches the condition.
|
||||
bctbx_log_handler_t* mLogHandler{nullptr};
|
||||
bctbx_log_handler_t* mSysLogHandler{nullptr};
|
||||
std::unique_ptr<sofiasip::Timer> mTimer{};
|
||||
bool mInitialized{false};
|
||||
bool mReopenRequired{false};
|
||||
|
||||
// Private class attributes
|
||||
static std::unique_ptr<LogManager> sInstance;
|
||||
|
||||
// Friendship
|
||||
friend class SipLogContext;
|
||||
friend class LogContext;
|
||||
};
|
||||
|
||||
class LogContext {
|
||||
public:
|
||||
LogContext() = default;
|
||||
~LogContext();
|
||||
};
|
||||
|
||||
/*
|
||||
* Class for contextual logs.
|
||||
* For now it just uses the MsgSip being processed by Flexisip.
|
||||
* This class should typically be instantiated on stack (not with new).
|
||||
* When it goes out of scope, it automatically clears the context with the LogManager.
|
||||
*/
|
||||
class SipLogContext : public LogContext {
|
||||
friend class LogManager;
|
||||
|
||||
public:
|
||||
SipLogContext(const MsgSip& msg);
|
||||
SipLogContext(const std::shared_ptr<MsgSip>& msg);
|
||||
|
||||
private:
|
||||
const MsgSip& mMsgSip;
|
||||
};
|
||||
|
||||
} // end of namespace flexisip
|
||||
|
||||
static BctbxLogLevel flexisip_sysLevelMin = BCTBX_LOG_ERROR;
|
||||
|
||||
/*
|
||||
* We want LOGN to output all the time (in standard output or syslog): this is for startup notice.
|
||||
*/
|
||||
template <typename... Args>
|
||||
inline void LOGN(const char* format, const Args&... args) {
|
||||
if (!flexisip::LogManager::get().syslogEnabled()) {
|
||||
fprintf(stdout, format, args...);
|
||||
fprintf(stdout, "\n");
|
||||
} else if (flexisip_sysLevelMin >= BCTBX_LOG_MESSAGE) {
|
||||
syslog(LOG_INFO, format, args...);
|
||||
}
|
||||
bctbx_set_thread_log_level(NULL, BCTBX_LOG_MESSAGE);
|
||||
bctbx_log(FLEXISIP_LOG_DOMAIN, BCTBX_LOG_MESSAGE, format, args...);
|
||||
bctbx_clear_thread_log_level(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* LOGEN and LOGF must be used to report any startup or configuration fatal error that needs to be seen by the
|
||||
* operator.
|
||||
* This is why it goes to standard output if syslog is not used (mostly for daemon mode).
|
||||
**/
|
||||
template <typename... Args>
|
||||
inline void LOGEN(const char* format, const Args&... args) {
|
||||
if (!flexisip::LogManager::get().syslogEnabled()) {
|
||||
fprintf(stderr, format, args...);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
bctbx_set_thread_log_level(NULL, BCTBX_LOG_MESSAGE);
|
||||
bctbx_log(FLEXISIP_LOG_DOMAIN, BCTBX_LOG_ERROR, format, args...);
|
||||
bctbx_clear_thread_log_level(NULL);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void LOGF(const char* format, const Args&... args) {
|
||||
LOGEN(format, args...);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and secure : warning - format string is not a string literal (potentially insecure)
|
||||
* While using a string with no arguments
|
||||
*/
|
||||
inline void LOGEN(const char* simpleLog) {
|
||||
LOGEN("%s", simpleLog);
|
||||
}
|
||||
inline void LOGF(const char* simpleLog) {
|
||||
LOGF("%s", simpleLog);
|
||||
}
|
70
include/flexisip/module-auth.hh
Normal file
70
include/flexisip/module-auth.hh
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "flexisip/module-authentication-base.hh"
|
||||
#include "flexisip/module.hh"
|
||||
#include "flexisip/sofia-wrapper/auth-module.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class Agent;
|
||||
class AuthDb;
|
||||
|
||||
class Authentication : public ModuleAuthenticationBase {
|
||||
friend std::shared_ptr<Module> ModuleInfo<Authentication>::create(Agent*);
|
||||
|
||||
public:
|
||||
StatCounter64* mCountAsyncRetrieve = nullptr;
|
||||
StatCounter64* mCountSyncRetrieve = nullptr;
|
||||
StatCounter64* mCountPassFound = nullptr;
|
||||
StatCounter64* mCountPassNotFound = nullptr;
|
||||
|
||||
~Authentication() override;
|
||||
|
||||
void onLoad(const GenericStruct* mc) override;
|
||||
bool tlsClientCertificatePostCheck(const std::shared_ptr<RequestSipEvent>& ev);
|
||||
virtual bool handleTlsClientAuthentication(const std::shared_ptr<RequestSipEvent>& ev);
|
||||
void onResponse(std::shared_ptr<ResponseSipEvent>& ev) override;
|
||||
void onIdle() override;
|
||||
bool doOnConfigStateChanged(const ConfigValue& conf, ConfigState state) override;
|
||||
|
||||
static void declareConfig(GenericStruct& moduleConfig);
|
||||
|
||||
protected:
|
||||
Authentication(Agent* ag, const ModuleInfoBase* moduleInfo);
|
||||
|
||||
private:
|
||||
FlexisipAuthModuleBase* createAuthModule(const std::string& domain, int nonceExpire, bool qopAuth) override;
|
||||
|
||||
void processAuthentication(const std::shared_ptr<RequestSipEvent>& request, FlexisipAuthModuleBase& am) override;
|
||||
|
||||
const char* findIncomingSubjectInTrusted(const std::shared_ptr<RequestSipEvent>& ev, const char* fromDomain);
|
||||
|
||||
static ModuleInfo<Authentication> sInfo;
|
||||
std::list<std::string> mTrustedClientCertificates;
|
||||
regex_t mRequiredSubject;
|
||||
bool mNewAuthOn407 = false;
|
||||
bool mRequiredSubjectCheckSet = false;
|
||||
bool mRejectWrongClientCertificates = false;
|
||||
bool mTrustDomainCertificates = false;
|
||||
AuthDb& mAuthDb;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
126
include/flexisip/module-authentication-base.hh
Normal file
126
include/flexisip/module-authentication-base.hh
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "flexisip/auth/flexisip-auth-module-base.hh"
|
||||
#include "flexisip/module.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
// Forward declaration to avoid to have to publish the RealmExtractor class header.
|
||||
class RealmExtractor;
|
||||
|
||||
/**
|
||||
* Base class for Flexisip authentication modules.
|
||||
*/
|
||||
class ModuleAuthenticationBase : public Module {
|
||||
public:
|
||||
ModuleAuthenticationBase(Agent* agent, const ModuleInfoBase* moduleInfo);
|
||||
~ModuleAuthenticationBase();
|
||||
|
||||
bool isTrustedPeer(const std::shared_ptr<RequestSipEvent>& ev);
|
||||
static void declareConfig(GenericStruct& root);
|
||||
|
||||
protected:
|
||||
// ================
|
||||
// Protected types
|
||||
// ================
|
||||
|
||||
/**
|
||||
* This exception is globally caught by ModuleAuthenticationBase::onRequest()
|
||||
* causing onRequest() return. It is to used in any sub-functions
|
||||
* of onRequest() in order to stop the request event processing
|
||||
* and pass to the next Flexisip module.
|
||||
*/
|
||||
class StopRequestProcessing : public std::exception {};
|
||||
|
||||
// ==================
|
||||
// Protected methods
|
||||
// ==================
|
||||
void onLoad(const GenericStruct* root) override;
|
||||
void onRequest(std::shared_ptr<RequestSipEvent>& ev) override;
|
||||
void onResponse([[maybe_unused]] std::shared_ptr<ResponseSipEvent>& ev) override {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to specify the specialization of #FlexisipAuthModuleBase to instantiate.
|
||||
*/
|
||||
virtual FlexisipAuthModuleBase* createAuthModule(const std::string& domain, int nonceExpire, bool qopAuth) = 0;
|
||||
/**
|
||||
* @brief Create and configure a #FlexisipAuthStatus according the information extracted from ev.
|
||||
*
|
||||
* This method may be overridden in order to instantiate a specialization of #FlexisipAuthStatus. Should it be,
|
||||
* the overriding method might call #configureAuthStatus() for configuring the base of the returned object.
|
||||
*/
|
||||
virtual FlexisipAuthStatus* createAuthStatus(const std::shared_ptr<RequestSipEvent>& ev);
|
||||
/**
|
||||
* Called by createAuthStatus() for setting #FlexisipAuthStatus attribute for the event request information.
|
||||
*/
|
||||
void configureAuthStatus(FlexisipAuthStatus& as, const std::shared_ptr<RequestSipEvent>& ev);
|
||||
|
||||
void validateRequest(const std::shared_ptr<RequestSipEvent>& request);
|
||||
virtual void processAuthentication(const std::shared_ptr<RequestSipEvent>& request, FlexisipAuthModuleBase& am);
|
||||
|
||||
/**
|
||||
* Called by onRequest() for getting a #FlexisipAuthModuleBase instance from a domain name.
|
||||
*/
|
||||
FlexisipAuthModuleBase* findAuthModule(const std::string name);
|
||||
|
||||
/**
|
||||
* This method is called synchronously or asynchronously on result of AuthModule::verify() method.
|
||||
* It calls onSuccess() and errorReply() according the authentication result.
|
||||
*/
|
||||
void processAuthModuleResponse(AuthStatus& as);
|
||||
virtual void onSuccess(const FlexisipAuthStatus& as);
|
||||
virtual void errorReply(const FlexisipAuthStatus& as);
|
||||
|
||||
void loadTrustedHosts(const ConfigStringList& trustedHosts);
|
||||
bool empty(const char* value) {
|
||||
return value == NULL || value[0] == '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a string match a valid algorithm in specified by sValidAlgos.
|
||||
*/
|
||||
static bool validAlgo(const std::string& algo);
|
||||
|
||||
// =====================
|
||||
// Protected attributes
|
||||
// =====================
|
||||
std::set<BinaryIp> mTrustedHosts;
|
||||
std::map<std::string, std::unique_ptr<FlexisipAuthModuleBase>> mAuthModules;
|
||||
std::list<std::string> mAlgorithms;
|
||||
auth_challenger_t mRegistrarChallenger;
|
||||
auth_challenger_t mProxyChallenger;
|
||||
RealmExtractor* mRealmExtractor{nullptr}; /* initially, this attribute was declared as
|
||||
std::unique_ptr<RealmExtractor> but that broke the compilation on Debian/Ubuntu platforms although the default
|
||||
destructor of ModuleAuthenticationBase was declared in the .cc file */
|
||||
std::shared_ptr<SipBooleanExpression> mNo403Expr;
|
||||
|
||||
static const std::array<std::string, 2> sValidAlgos;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
186
include/flexisip/module-registrar.hh
Normal file
186
include/flexisip/module-registrar.hh
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sofia-sip/sip_status.h>
|
||||
#include <sofia-sip/su_random.h>
|
||||
|
||||
#include "flexisip/module.hh"
|
||||
#include "flexisip/registrar/registar-listeners.hh"
|
||||
#include "flexisip/signal-handling/sofia-driven-signal-handler.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
struct RegistrarStats {
|
||||
std::unique_ptr<StatPair> mCountBind;
|
||||
std::unique_ptr<StatPair> mCountClear;
|
||||
StatCounter64* mCountLocalActives;
|
||||
};
|
||||
|
||||
class ModuleRegistrar;
|
||||
class Agent;
|
||||
class ResponseContext;
|
||||
|
||||
// Listener class NEED to copy the shared pointer
|
||||
class OnRequestBindListener : public ContactUpdateListener {
|
||||
ModuleRegistrar* mModule;
|
||||
std::shared_ptr<RequestSipEvent> mEv;
|
||||
sip_from_t* mSipFrom;
|
||||
su_home_t mHome;
|
||||
sip_contact_t* mContact;
|
||||
sip_path_t* mPath;
|
||||
|
||||
public:
|
||||
OnRequestBindListener(ModuleRegistrar* module,
|
||||
std::shared_ptr<RequestSipEvent> ev,
|
||||
const sip_from_t* sipuri = NULL,
|
||||
sip_contact_t* contact = NULL,
|
||||
sip_path_t* path = NULL);
|
||||
~OnRequestBindListener();
|
||||
|
||||
void onContactUpdated(const std::shared_ptr<ExtendedContact>& ec) override;
|
||||
void onRecordFound(const std::shared_ptr<Record>& r) override;
|
||||
void onError(const SipStatus& response) override;
|
||||
void onInvalid(const SipStatus& response) override;
|
||||
};
|
||||
|
||||
class OnResponseBindListener : public ContactUpdateListener {
|
||||
ModuleRegistrar* mModule;
|
||||
std::shared_ptr<ResponseSipEvent> mEv;
|
||||
std::shared_ptr<OutgoingTransaction> mTr;
|
||||
std::shared_ptr<ResponseContext> mCtx;
|
||||
|
||||
public:
|
||||
OnResponseBindListener(ModuleRegistrar* module,
|
||||
std::shared_ptr<ResponseSipEvent> ev,
|
||||
std::shared_ptr<OutgoingTransaction> tr,
|
||||
std::shared_ptr<ResponseContext> ctx);
|
||||
void onContactUpdated(const std::shared_ptr<ExtendedContact>& ec) override;
|
||||
void onRecordFound(const std::shared_ptr<Record>& r) override;
|
||||
void onError(const SipStatus& response) override;
|
||||
void onInvalid(const SipStatus& response) override;
|
||||
};
|
||||
|
||||
// Listener class NEED to copy the shared pointer
|
||||
class OnStaticBindListener : public ContactUpdateListener {
|
||||
friend class ModuleRegistrar;
|
||||
sofiasip::Home mHome;
|
||||
std::string mContact;
|
||||
std::string mFrom;
|
||||
|
||||
public:
|
||||
OnStaticBindListener(const url_t* from, const sip_contact_t* ct);
|
||||
|
||||
void onContactUpdated(const std::shared_ptr<ExtendedContact>& ec) override;
|
||||
void onRecordFound(const std::shared_ptr<Record>& r) override;
|
||||
void onError(const SipStatus& response) override;
|
||||
void onInvalid(const SipStatus& response) override;
|
||||
};
|
||||
|
||||
class FakeFetchListener : public ContactUpdateListener {
|
||||
friend class ModuleRegistrar;
|
||||
|
||||
public:
|
||||
FakeFetchListener();
|
||||
void onContactUpdated(const std::shared_ptr<ExtendedContact>& ec) override;
|
||||
void onRecordFound(const std::shared_ptr<Record>& r) override;
|
||||
void onError(const SipStatus& response) override;
|
||||
void onInvalid(const SipStatus& response) override;
|
||||
};
|
||||
|
||||
class ResponseContext {
|
||||
public:
|
||||
ResponseContext(std::shared_ptr<RequestSipEvent>&& ev, int globalDelta);
|
||||
const std::shared_ptr<RequestSipEvent> mRequestSipEvent;
|
||||
};
|
||||
|
||||
class ModuleRegistrar : public Module {
|
||||
|
||||
friend std::shared_ptr<Module> ModuleInfo<ModuleRegistrar>::create(Agent*);
|
||||
friend class OnRequestBindListener;
|
||||
friend class OnResponseBindListener;
|
||||
|
||||
public:
|
||||
~ModuleRegistrar() {
|
||||
}
|
||||
|
||||
virtual void onLoad(const GenericStruct* mc);
|
||||
|
||||
virtual void onUnload();
|
||||
|
||||
virtual void onRequest(std::shared_ptr<RequestSipEvent>& ev);
|
||||
|
||||
virtual void onResponse(std::shared_ptr<ResponseSipEvent>& ev);
|
||||
|
||||
template <typename SipEventT, typename ListenerT>
|
||||
void processUpdateRequest(std::shared_ptr<SipEventT>& ev, const sip_t* sip);
|
||||
|
||||
void idle();
|
||||
|
||||
void
|
||||
reply(std::shared_ptr<RequestSipEvent>& ev, int code, const char* reason, const sip_contact_t* contacts = NULL);
|
||||
|
||||
void readStaticRecords();
|
||||
|
||||
static void declareConfig(GenericStruct& moduleConfig);
|
||||
|
||||
protected:
|
||||
ModuleRegistrar(Agent* ag, const ModuleInfoBase* moduleInfo);
|
||||
|
||||
private:
|
||||
static int numberOfContactHeaders(const sip_contact_t* rootHeader);
|
||||
|
||||
std::shared_ptr<RequestSipEvent> createUpstreamRequestEvent(std::shared_ptr<RequestSipEvent>&& ev, int globalDelta);
|
||||
void deleteResponseContext(const std::shared_ptr<ResponseContext>& ctx);
|
||||
|
||||
void updateLocalRegExpire();
|
||||
bool isManagedDomain(const url_t* url);
|
||||
bool isAdjacentRegistration(const sip_t* sip);
|
||||
std::string routingKey(const url_t* sipUri);
|
||||
void removeInternalParams(sip_contact_t* ct);
|
||||
|
||||
RegistrarStats mStats;
|
||||
bool mUpdateOnResponse;
|
||||
bool mAllowDomainRegistrations;
|
||||
std::list<std::string> mDomains;
|
||||
std::list<std::string> mUniqueIdParams;
|
||||
std::string mServiceRoute;
|
||||
static std::list<std::string> mPushNotifParams;
|
||||
std::string mRoutingParam;
|
||||
unsigned int mMaxExpires, mMinExpires;
|
||||
std::string mStaticRecordsFile;
|
||||
su_timer_t* mStaticRecordsTimer;
|
||||
int mStaticRecordsTimeout;
|
||||
int mStaticRecordsVersion;
|
||||
bool mAssumeUniqueDomains;
|
||||
static ModuleInfo<ModuleRegistrar> sInfo;
|
||||
bool mUseGlobalDomain;
|
||||
int mExpireRandomizer;
|
||||
int mMaxContactsPerRegistration;
|
||||
std::list<std::string> mParamsToRemove;
|
||||
std::unique_ptr<signal_handling::SofiaDrivenSignalHandler> mSignalHandler = nullptr;
|
||||
};
|
||||
|
||||
class RegistrarMgt {
|
||||
public:
|
||||
virtual unsigned long long int getTotalNumberOfAddedRecords() = 0;
|
||||
virtual unsigned long long int getTotalNumberOfExpiredRecords() = 0;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
41
include/flexisip/module-router-interface.hh
Normal file
41
include/flexisip/module-router-interface.hh
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class ForkContext;
|
||||
class RequestSipEvent;
|
||||
|
||||
/**
|
||||
* Interface for the ModuleRouter object, this interface is under construction.
|
||||
* For now it allow to mock the Agent in some test cases.
|
||||
*/
|
||||
class ModuleRouterInterface {
|
||||
public:
|
||||
virtual ~ModuleRouterInterface() = default;
|
||||
|
||||
virtual void sendToInjector(const std::shared_ptr<RequestSipEvent>& ev,
|
||||
const std::shared_ptr<ForkContext>& context,
|
||||
const std::string& contactId) = 0;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
201
include/flexisip/module-router.hh
Normal file
201
include/flexisip/module-router.hh
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "flexisip/fork-context/fork-context.hh"
|
||||
#include "flexisip/module-router-interface.hh"
|
||||
#include "flexisip/module.hh"
|
||||
#include "flexisip/registrar/registar-listeners.hh"
|
||||
#include "flexisip/utils/sip-uri.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
struct RouterStats {
|
||||
std::unique_ptr<StatPair> mCountForks;
|
||||
std::shared_ptr<StatPair> mCountBasicForks;
|
||||
std::shared_ptr<StatPair> mCountCallForks;
|
||||
std::shared_ptr<StatPair> mCountMessageForks;
|
||||
std::shared_ptr<StatPair> mCountMessageProxyForks;
|
||||
};
|
||||
|
||||
class OnContactRegisteredListener;
|
||||
class Injector;
|
||||
class Agent;
|
||||
class Record;
|
||||
|
||||
class ModuleRouter : public Module,
|
||||
public ModuleRouterInterface,
|
||||
public ForkContextListener,
|
||||
public std::enable_shared_from_this<ModuleRouter> {
|
||||
|
||||
friend std::shared_ptr<Module> ModuleInfo<ModuleRouter>::create(Agent*);
|
||||
|
||||
public:
|
||||
~ModuleRouter();
|
||||
|
||||
void onLoad(const GenericStruct* mc) override;
|
||||
|
||||
void onUnload() override{};
|
||||
|
||||
void onRequest(std::shared_ptr<RequestSipEvent>& ev) override;
|
||||
|
||||
void onResponse(std::shared_ptr<ResponseSipEvent>& ev) override;
|
||||
|
||||
void onForkContextFinished(const std::shared_ptr<ForkContext>& ctx) override;
|
||||
std::shared_ptr<BranchInfo> onDispatchNeeded(const std::shared_ptr<ForkContext>& ctx,
|
||||
const std::shared_ptr<ExtendedContact>& newContact) override;
|
||||
void onUselessRegisterNotification(const std::shared_ptr<ForkContext>& ctx,
|
||||
const std::shared_ptr<ExtendedContact>& newContact,
|
||||
const SipUri& dest,
|
||||
const std::string& uid,
|
||||
const DispatchStatus reason) override;
|
||||
|
||||
void sendReply(std::shared_ptr<RequestSipEvent>& ev,
|
||||
int code,
|
||||
const char* reason,
|
||||
int warn_code = 0,
|
||||
const char* warning = nullptr);
|
||||
void routeRequest(std::shared_ptr<RequestSipEvent>& ev, const std::shared_ptr<Record>& aor, const url_t* sipUri);
|
||||
void onContactRegistered(const std::shared_ptr<OnContactRegisteredListener>& listener,
|
||||
const std::string& uid,
|
||||
const std::shared_ptr<Record>& aor);
|
||||
|
||||
const std::string& getFallbackRoute() const {
|
||||
return mFallbackRoute;
|
||||
}
|
||||
const url_t* getFallbackRouteParsed() const {
|
||||
return mFallbackRouteParsed;
|
||||
}
|
||||
|
||||
bool isFallbackToParentDomainEnabled() const {
|
||||
return mFallbackParentDomain;
|
||||
}
|
||||
|
||||
bool isDomainRegistrationAllowed() const {
|
||||
return mAllowDomainRegistrations;
|
||||
}
|
||||
|
||||
bool isManagedDomain(const url_t* url) const;
|
||||
|
||||
const std::shared_ptr<SipBooleanExpression>& getFallbackRouteFilter() const {
|
||||
return mFallbackRouteFilter;
|
||||
}
|
||||
|
||||
const std::shared_ptr<ForkContextConfig>& getCallForkCfg() const {
|
||||
return mCallForkCfg;
|
||||
}
|
||||
const std::shared_ptr<ForkContextConfig>& getMessageForkCfg() const {
|
||||
return mMessageForkCfg;
|
||||
}
|
||||
const std::shared_ptr<ForkContextConfig>& getOtherForkCfg() const {
|
||||
return mOtherForkCfg;
|
||||
}
|
||||
|
||||
void sendToInjector(const std::shared_ptr<RequestSipEvent>& ev,
|
||||
const std::shared_ptr<ForkContext>& context,
|
||||
const std::string& contactId) override;
|
||||
|
||||
static void setMaxPriorityHandled(sofiasip::MsgSipPriority maxPriorityHandled) {
|
||||
sMaxPriorityHandled = maxPriorityHandled;
|
||||
}
|
||||
|
||||
static void declareConfig(GenericStruct& moduleConfig);
|
||||
|
||||
RouterStats mStats;
|
||||
|
||||
protected:
|
||||
ModuleRouter(Agent* ag, const ModuleInfoBase* moduleInfo);
|
||||
|
||||
using ForkMapElem = std::shared_ptr<ForkContext>;
|
||||
using ForkMap = std::multimap<std::string, ForkMapElem>;
|
||||
using ForkRefList = std::vector<ForkMapElem>;
|
||||
|
||||
// This template method has a single specialization that returns the key
|
||||
// as a Record::Key object. It is declared in the module-router.cc file.
|
||||
// Originally a standard method, it was transformed into a template method
|
||||
// to prevent the need for including "record.hh", which would otherwise
|
||||
// require placing this header in the public API.
|
||||
//
|
||||
// @todo Remove this method and replace its usage with direct Record::Key construction.
|
||||
template <typename KeyT>
|
||||
KeyT routingKey(const url_t* sipUri);
|
||||
|
||||
std::vector<std::string> split(const char* data, const char* delim);
|
||||
ForkRefList getLateForks(const std::string& key) const noexcept;
|
||||
|
||||
std::shared_ptr<BranchInfo> dispatch(const std::shared_ptr<ForkContext>& context,
|
||||
const std::shared_ptr<ExtendedContact>& contact,
|
||||
const std::string& targetUris = "");
|
||||
|
||||
std::list<std::string> mDomains;
|
||||
std::shared_ptr<ForkContextConfig> mCallForkCfg;
|
||||
std::shared_ptr<ForkContextConfig> mMessageForkCfg;
|
||||
std::shared_ptr<ForkContextConfig> mOtherForkCfg;
|
||||
ForkMap mForks;
|
||||
bool mUseGlobalDomain = false;
|
||||
bool mAllowDomainRegistrations = false;
|
||||
bool mAllowTargetFactorization = false;
|
||||
bool mResolveRoutes = false;
|
||||
bool mFallbackParentDomain = false;
|
||||
std::string mFallbackRoute;
|
||||
url_t* mFallbackRouteParsed = nullptr;
|
||||
|
||||
private:
|
||||
#if ENABLE_SOCI
|
||||
void restoreForksFromDatabase();
|
||||
#endif
|
||||
|
||||
static ModuleInfo<ModuleRouter> sInfo;
|
||||
static sofiasip::MsgSipPriority sMaxPriorityHandled;
|
||||
std::shared_ptr<SipBooleanExpression> mFallbackRouteFilter;
|
||||
std::shared_ptr<OnContactRegisteredListener> mOnContactRegisteredListener{nullptr};
|
||||
std::unique_ptr<Injector> mInjector;
|
||||
std::vector<SipUri> mStaticTargets;
|
||||
};
|
||||
|
||||
class OnContactRegisteredListener : public ContactRegisteredListener,
|
||||
public ContactUpdateListener,
|
||||
public std::enable_shared_from_this<OnContactRegisteredListener> {
|
||||
friend class ModuleRouter;
|
||||
ModuleRouter* mModule;
|
||||
sofiasip::Home mHome;
|
||||
|
||||
public:
|
||||
OnContactRegisteredListener(ModuleRouter* module) : mModule(module) {
|
||||
SLOGD << "OnContactRegisteredListener created";
|
||||
}
|
||||
|
||||
~OnContactRegisteredListener() = default;
|
||||
|
||||
void onContactRegistered(const std::shared_ptr<Record>& r, const std::string& uid) override;
|
||||
|
||||
void onRecordFound([[maybe_unused]] const std::shared_ptr<Record>& r) override {
|
||||
}
|
||||
void onError(const SipStatus&) override {
|
||||
}
|
||||
void onInvalid(const SipStatus&) override {
|
||||
}
|
||||
void onContactUpdated([[maybe_unused]] const std::shared_ptr<ExtendedContact>& ec) override {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
261
include/flexisip/module.hh
Normal file
261
include/flexisip/module.hh
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sofia-sip/msg_header.h>
|
||||
#include <sofia-sip/nta_tport.h>
|
||||
#include <sofia-sip/tport.h>
|
||||
|
||||
#include "flexisip/configmanager.hh"
|
||||
#include "flexisip/event.hh"
|
||||
#include "flexisip/sofia-wrapper/home.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Module.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class ModuleInfoBase;
|
||||
|
||||
template <typename T>
|
||||
class ModuleInfo;
|
||||
|
||||
class SharedLibrary;
|
||||
class EntryFilter;
|
||||
|
||||
enum class ModuleClass { Experimental, Production };
|
||||
|
||||
/**
|
||||
* Abstract base class for all Flexisip module.
|
||||
* A module is an object that is able to process sip requests and sip responses.
|
||||
* It must implements at least:
|
||||
* virtual void onRequest(SipEvent *ev)=0;
|
||||
* virtual void onResponse(SipEvent *ev)=0;
|
||||
**/
|
||||
class Module : protected ConfigValueListener {
|
||||
template <typename T>
|
||||
friend class ModuleInfo;
|
||||
|
||||
public:
|
||||
Module(Agent* agent, const ModuleInfoBase* moduleInfo);
|
||||
virtual ~Module();
|
||||
|
||||
Agent* getAgent() const {
|
||||
return mAgent;
|
||||
}
|
||||
nta_agent_t* getSofiaAgent() const;
|
||||
const std::string& getModuleName() const;
|
||||
const std::string& getModuleConfigName() const;
|
||||
void checkConfig();
|
||||
void load();
|
||||
void unload();
|
||||
void reload();
|
||||
StatCounter64& findStat(const std::string& statName) const;
|
||||
void idle();
|
||||
bool isEnabled() const;
|
||||
ModuleClass getClass() const;
|
||||
|
||||
void processRequest(std::shared_ptr<RequestSipEvent>& ev);
|
||||
void processResponse(std::shared_ptr<ResponseSipEvent>& ev);
|
||||
void process(std::shared_ptr<RequestSipEvent>& ev) {
|
||||
processRequest(ev);
|
||||
}
|
||||
void process(std::shared_ptr<ResponseSipEvent>& ev) {
|
||||
processResponse(ev);
|
||||
}
|
||||
virtual void injectRequestEvent(const std::shared_ptr<RequestSipEvent>& ev);
|
||||
|
||||
const ModuleInfoBase* getInfo() const {
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onLoad([[maybe_unused]] const GenericStruct* root) {
|
||||
}
|
||||
virtual void onUnload() {
|
||||
}
|
||||
|
||||
virtual void onRequest(std::shared_ptr<RequestSipEvent>& ev) = 0;
|
||||
virtual void onResponse(std::shared_ptr<ResponseSipEvent>& ev) = 0;
|
||||
|
||||
virtual bool doOnConfigStateChanged(const ConfigValue& conf, ConfigState state);
|
||||
virtual void onIdle() {
|
||||
}
|
||||
|
||||
virtual bool onCheckValidNextConfig() {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool isValidNextConfig([[maybe_unused]] const ConfigValue& cv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void sendTrap(const std::string& msg);
|
||||
|
||||
protected:
|
||||
sofiasip::Home mHome;
|
||||
Agent* mAgent = nullptr;
|
||||
const ModuleInfoBase* mInfo;
|
||||
GenericStruct* mModuleConfig = nullptr;
|
||||
std::unique_ptr<EntryFilter> mFilter;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ModuleInfo.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class ModuleInfoBase;
|
||||
|
||||
class ModuleInfoManager {
|
||||
friend class ModuleInfoBase;
|
||||
|
||||
public:
|
||||
~ModuleInfoManager();
|
||||
const std::list<ModuleInfoBase*>& getRegisteredModuleInfo() const {
|
||||
return mRegisteredModuleInfo;
|
||||
}
|
||||
std::list<ModuleInfoBase*> buildModuleChain() const;
|
||||
|
||||
static ModuleInfoManager* get();
|
||||
|
||||
private:
|
||||
void registerModuleInfo(ModuleInfoBase* moduleInfo);
|
||||
void unregisterModuleInfo(ModuleInfoBase* moduleInfo);
|
||||
void dumpModuleDependencies(const std::list<ModuleInfoBase*>& l) const;
|
||||
bool moduleDependenciesPresent(const std::list<ModuleInfoBase*>& sortedList, ModuleInfoBase* module) const;
|
||||
void replaceModules(std::list<ModuleInfoBase*>& sortedList,
|
||||
const std::list<ModuleInfoBase*>& replacingModules) const;
|
||||
|
||||
std::list<ModuleInfoBase*> mRegisteredModuleInfo;
|
||||
|
||||
static std::unique_ptr<ModuleInfoManager> sInstance;
|
||||
};
|
||||
|
||||
class ModuleInfoBase {
|
||||
public:
|
||||
enum ModuleOid {
|
||||
SanityChecker = 3,
|
||||
DoSProtection = 4,
|
||||
GarbageIn = 5,
|
||||
Capabilities = 10,
|
||||
NatHelper = 30,
|
||||
Authentication = 60,
|
||||
CustomAuthentication = 61,
|
||||
DateHandler = 75,
|
||||
GatewayAdapter = 90,
|
||||
Registrar = 120,
|
||||
StatisticsCollector = 123,
|
||||
Router = 125,
|
||||
PushNotification = 130,
|
||||
ContactRouteInserter = 150,
|
||||
LoadBalancer = 180,
|
||||
MediaRelay = 210,
|
||||
Transcoder = 240,
|
||||
Forward = 270,
|
||||
Redirect = 290,
|
||||
Presence = 300,
|
||||
RegEvent = 305,
|
||||
B2bua = 307,
|
||||
InterDomainConnections = 310,
|
||||
Plugin = 320
|
||||
};
|
||||
|
||||
ModuleInfoBase(const std::string& moduleName,
|
||||
const std::string& help,
|
||||
const std::vector<std::string>& after,
|
||||
ModuleOid oid,
|
||||
std::function<void(GenericStruct&)> declareConfig,
|
||||
ModuleClass moduleClass,
|
||||
const std::string& replace)
|
||||
: mName(moduleName), mHelp(help), mAfter(after), mOidIndex(oid), mDeclareConfig(declareConfig),
|
||||
mClass(moduleClass), mReplace(replace) {
|
||||
ModuleInfoManager::get()->registerModuleInfo(this);
|
||||
}
|
||||
virtual ~ModuleInfoBase() {
|
||||
if (mRegistered) {
|
||||
ModuleInfoManager::get()->unregisterModuleInfo(this);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& getModuleName() const {
|
||||
return mName;
|
||||
}
|
||||
const std::string& getModuleHelp() const {
|
||||
return mHelp;
|
||||
}
|
||||
const std::vector<std::string>& getAfter() const {
|
||||
return mAfter;
|
||||
}
|
||||
unsigned int getOidIndex() const {
|
||||
return mOidIndex;
|
||||
}
|
||||
ModuleClass getClass() const {
|
||||
return mClass;
|
||||
}
|
||||
const std::string& getReplace() const {
|
||||
return mReplace;
|
||||
}
|
||||
const std::string& getFunction() const {
|
||||
return mReplace.empty() ? mName : mReplace;
|
||||
}
|
||||
void setRegistered(bool newState) {
|
||||
mRegistered = newState;
|
||||
}
|
||||
|
||||
void declareConfig(GenericStruct& rootConfig) const;
|
||||
|
||||
virtual std::shared_ptr<Module> create(Agent* agent) = 0;
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mHelp;
|
||||
std::vector<std::string> mAfter;
|
||||
oid mOidIndex;
|
||||
std::function<void(GenericStruct&)> mDeclareConfig;
|
||||
ModuleClass mClass;
|
||||
std::string mReplace;
|
||||
bool mRegistered{false};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ModuleInfo : public ModuleInfoBase {
|
||||
public:
|
||||
using ModuleType = T;
|
||||
|
||||
ModuleInfo(const std::string& moduleName,
|
||||
const std::string& help,
|
||||
const std::vector<std::string>& after,
|
||||
ModuleOid oid,
|
||||
std::function<void(GenericStruct&)> declareConfig,
|
||||
ModuleClass moduleClass = ModuleClass::Production,
|
||||
const std::string& replace = "")
|
||||
: ModuleInfoBase(moduleName, help, after, oid, declareConfig, moduleClass, replace) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Module> create(Agent* agent) override {
|
||||
std::shared_ptr<Module> module;
|
||||
module.reset(new T(agent, this));
|
||||
return module;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
63
include/flexisip/plugin.hh
Normal file
63
include/flexisip/plugin.hh
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <flexisip/flexisip-version.h>
|
||||
#include <flexisip/module.hh>
|
||||
|
||||
#ifndef FLEXISIP_GIT_VERSION
|
||||
#define FLEXISIP_GIT_VERSION "undefined"
|
||||
#endif // ifndef FLEXISIP_GIT_VERSION
|
||||
|
||||
#define FLEXISIP_PLUGIN_API_VERSION FLEXISIP_GIT_VERSION
|
||||
|
||||
#ifdef WIN32
|
||||
#define FLEXISIP_PLUGIN_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define FLEXISIP_PLUGIN_EXPORT extern "C"
|
||||
#endif // ifdef WIN32
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
struct PluginInfo {
|
||||
const char* className;
|
||||
const char* name;
|
||||
int version;
|
||||
const char* apiVersion;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const PluginInfo& info) {
|
||||
os << "Plugin info:" << std::endl
|
||||
<< " Name: " << info.name << std::endl
|
||||
<< " Class Name: " << info.className << std::endl
|
||||
<< " Version: " << info.version << std::endl
|
||||
<< " Api Version: " << info.apiVersion;
|
||||
return os;
|
||||
}
|
||||
|
||||
#define FLEXISIP_DECLARE_PLUGIN(MODULE_INFO, NAME, VERSION) \
|
||||
static_assert(std::is_base_of<ModuleInfoBase, decltype(MODULE_INFO)>::value, \
|
||||
"Flexisip plugin must be derived from ModuleInfoBase class."); \
|
||||
FLEXISIP_PLUGIN_EXPORT const ModuleInfoBase* __flexisipGetPluginModuleInfo() { \
|
||||
return &MODULE_INFO; \
|
||||
} \
|
||||
FLEXISIP_PLUGIN_EXPORT const PluginInfo __flexisipPluginInfo = {#MODULE_INFO, NAME, VERSION, \
|
||||
FLEXISIP_PLUGIN_API_VERSION};
|
||||
|
||||
} // namespace flexisip
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class PushNotificationContext;
|
||||
|
||||
/**
|
||||
* Interface for PushNotificationContext observers.
|
||||
*/
|
||||
class PushNotificationContextObserver {
|
||||
public:
|
||||
virtual ~PushNotificationContextObserver() = default;
|
||||
/**
|
||||
* Notify the observer that a push notification has been sent by the PushNotificationContext.
|
||||
* @param aPNCtx The PushNotificationContext that has sent the PN.
|
||||
* @param aRingingPush Tells whether the sent PN makes the callee's device to ring without
|
||||
* waking the user agent up.
|
||||
*/
|
||||
virtual void onPushSent(PushNotificationContext& aPNCtx, bool aRingingPush) noexcept = 0;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
96
include/flexisip/registrar/registar-listeners.hh
Normal file
96
include/flexisip/registrar/registar-listeners.hh
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2025 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flexisip/configmanager.hh"
|
||||
#include "flexisip/flexisip-exception.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
class Record;
|
||||
struct ExtendedContact;
|
||||
|
||||
/**
|
||||
* @brief Interface for RegistrarDB listeners.
|
||||
*/
|
||||
class RegistrarDbListener : public StatFinishListener {
|
||||
public:
|
||||
virtual ~RegistrarDbListener();
|
||||
|
||||
/**
|
||||
* Method called when searching for a record matching a given SIP identity is completed.
|
||||
*
|
||||
* @param record The found record or nullptr if no record could be found. If not null, the ownership on the object
|
||||
* is held by the implementation and the object might be destroyed immediately after onRecordFound() has returned.
|
||||
*/
|
||||
virtual void onRecordFound(const std::shared_ptr<Record>& record) = 0;
|
||||
/**
|
||||
* Internal error, translated to a 5xx response by the registrar module.
|
||||
*/
|
||||
virtual void onError(const SipStatus& response) = 0;
|
||||
/**
|
||||
* Client error, translated to a 4xx (Invalid) response by the registrar module.
|
||||
*/
|
||||
virtual void onInvalid(const SipStatus& response) = 0;
|
||||
};
|
||||
|
||||
class ContactUpdateListener : public RegistrarDbListener {
|
||||
public:
|
||||
~ContactUpdateListener() override;
|
||||
|
||||
virtual void onContactUpdated(const std::shared_ptr<ExtendedContact>& ec) = 0;
|
||||
};
|
||||
|
||||
class ListContactUpdateListener {
|
||||
public:
|
||||
virtual ~ListContactUpdateListener();
|
||||
|
||||
virtual void onContactsUpdated() = 0;
|
||||
|
||||
std::vector<std::shared_ptr<Record>> records;
|
||||
};
|
||||
|
||||
/*TODO: the listener should be also used to report when the subscription is active.
|
||||
* Indeed if we send a push notification to a device while REDIS has not yet confirmed the subscription, we will not do
|
||||
* anything when receiving the REGISTER from the device. The router module should wait confirmation that subscription is
|
||||
* active before injecting the forked request to the module chain.*/
|
||||
class ContactRegisteredListener {
|
||||
public:
|
||||
virtual ~ContactRegisteredListener();
|
||||
|
||||
virtual void onContactRegistered(const std::shared_ptr<Record>& record, const std::string& uid) = 0;
|
||||
};
|
||||
|
||||
class LocalRegExpireListener {
|
||||
public:
|
||||
virtual ~LocalRegExpireListener();
|
||||
|
||||
virtual void onLocalRegExpireUpdated(unsigned int count) = 0;
|
||||
};
|
||||
|
||||
class RegistrarDbStateListener {
|
||||
public:
|
||||
virtual ~RegistrarDbStateListener();
|
||||
|
||||
virtual void onRegistrarDbWritable(bool writable) = 0;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
70
include/flexisip/signal-handling/signal-handling.hh
Normal file
70
include/flexisip/signal-handling/signal-handling.hh
Normal file
|
@ -0,0 +1,70 @@
|
|||
/** Copyright (C) 2010-2023 Belledonne Communications SARL
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
namespace signal_handling {
|
||||
|
||||
using SigNum = decltype(SIGTERM);
|
||||
using PipeDescriptor = int;
|
||||
|
||||
union SignalData {
|
||||
SigNum signum;
|
||||
uint8_t bytes[sizeof(signum)];
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a simple handler for the given POSIX signals that will forward the signal number to a pipe on reception.
|
||||
* A safe handler can then be implemented that reads the value from the pipe outside of the special signal context.
|
||||
*
|
||||
* On destruction, the PipedSignal will unbind the signal handler from the given signals and close the pipe.
|
||||
*
|
||||
* In the event that two PipedSignals are created for the same signal, the one created last will shadow the first (which
|
||||
* will therefore never be called again)
|
||||
*/
|
||||
class PipedSignal {
|
||||
public:
|
||||
PipedSignal(std::vector<SigNum>&& signals);
|
||||
~PipedSignal();
|
||||
|
||||
PipedSignal(PipedSignal&& other) = delete;
|
||||
PipedSignal(const PipedSignal& other) = delete;
|
||||
PipedSignal& operator=(const PipedSignal& other) = delete;
|
||||
PipedSignal& operator=(PipedSignal&& other) = delete;
|
||||
|
||||
/* Get the file descriptor for the read end of the pipe */
|
||||
PipeDescriptor descriptor() {
|
||||
return mPipe.fd.read;
|
||||
}
|
||||
|
||||
/* Read a signal number from the pipe into `data`.
|
||||
* This is just a wrapper for POSIX `read` and will __block__ until there is data in the pipe
|
||||
*/
|
||||
ssize_t read(SignalData& data);
|
||||
|
||||
private:
|
||||
static std::unordered_map<SigNum, PipeDescriptor> sSignalToPipe;
|
||||
|
||||
union SignalPipe {
|
||||
struct Descriptors {
|
||||
PipeDescriptor read;
|
||||
PipeDescriptor write;
|
||||
} fd;
|
||||
PipeDescriptor array[2];
|
||||
} mPipe;
|
||||
std::vector<SigNum> mSignals{};
|
||||
};
|
||||
|
||||
} // namespace signal_handling
|
||||
|
||||
} // namespace flexisip
|
|
@ -0,0 +1,71 @@
|
|||
/** Copyright (C) 2010-2023 Belledonne Communications SARL
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "flexisip/logmanager.hh"
|
||||
#include "flexisip/signal-handling/signal-handling.hh"
|
||||
#include "flexisip/sofia-wrapper/waker.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
namespace signal_handling {
|
||||
|
||||
/**
|
||||
* Register a lambda to be called by the sofia loop after the given POSIX signals have been received.
|
||||
*
|
||||
* This lambda runs outside of the signal action callback and therefore does not need to be signal-safe.
|
||||
*
|
||||
* On destruction, this object unregisters from the sofia loop and signal handling mechanism.
|
||||
*
|
||||
* In the event that two handlers are created for the same signal, the one created last will shadow the first (which
|
||||
* will therefore never be called again)
|
||||
*/
|
||||
class SofiaDrivenSignalHandler {
|
||||
using Callback = std::function<void(SigNum)>;
|
||||
|
||||
public:
|
||||
/** SAFETY:
|
||||
* - `root` MUST NOT be null and MUST be valid for the lifetime of the Handler
|
||||
*/
|
||||
SofiaDrivenSignalHandler(su_root_t* root, std::vector<SigNum>&& signals, Callback&& callback)
|
||||
: mSignalPipe(std::move(signals)), mCallback(std::move(callback)),
|
||||
mWaker(
|
||||
root,
|
||||
mSignalPipe.descriptor(),
|
||||
// SAFETY: Capturing `this` is safe because we own the Waker.
|
||||
[this](su_root_magic_t*, su_wait_t* waiter) noexcept {
|
||||
// Logging is safe in here since we're out of the signal handler
|
||||
if (waiter->revents & SU_WAIT_ERR) {
|
||||
LOGE("Error on signal pipe");
|
||||
return 0;
|
||||
}
|
||||
if (waiter->revents & SU_WAIT_HUP) {
|
||||
LOGE("Signal pipe closed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SignalData signal;
|
||||
if (mSignalPipe.read(signal) != sizeof(signal)) {
|
||||
LOGE("Error reading from signal pipe");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mCallback(signal.signum);
|
||||
return 0;
|
||||
},
|
||||
su_pri_normal) {
|
||||
}
|
||||
|
||||
private:
|
||||
PipedSignal mSignalPipe;
|
||||
Callback mCallback;
|
||||
sofiasip::Waker mWaker;
|
||||
};
|
||||
|
||||
} // namespace signal_handling
|
||||
|
||||
} // namespace flexisip
|
40
include/flexisip/sip-boolean-expressions.hh
Normal file
40
include/flexisip/sip-boolean-expressions.hh
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010 Belledonne Communications SARL.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "flexisip/expressionparser.hh"
|
||||
|
||||
typedef struct sip_s sip_t;
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
using SipBooleanExpression = BooleanExpression<sip_t>;
|
||||
|
||||
class SipBooleanExpressionBuilder : public BooleanExpressionBuilder<sip_t> {
|
||||
public:
|
||||
static SipBooleanExpressionBuilder &get();
|
||||
std::shared_ptr<SipBooleanExpression> parse(const std::string &expression);
|
||||
|
||||
private:
|
||||
SipBooleanExpressionBuilder();
|
||||
static std::shared_ptr<SipBooleanExpressionBuilder> sInstance;
|
||||
};
|
||||
|
||||
} //end of namespace
|
96
include/flexisip/sofia-wrapper/auth-module.hh
Normal file
96
include/flexisip/sofia-wrapper/auth-module.hh
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <sofia-sip/auth_module.h>
|
||||
|
||||
#include "flexisip/sofia-wrapper/auth-status.hh"
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
/**
|
||||
* @brief Interface for authentication modules.
|
||||
* @note This class is a plain C++ wrapper of SofiaSip's auth_mod_t
|
||||
* object. Please look at http://sofia-sip.sourceforge.net/refdocs/iptsec/auth__module_8h.html
|
||||
* for a complete documentation.
|
||||
*/
|
||||
class AuthModule {
|
||||
public:
|
||||
AuthModule(su_root_t* root, tag_type_t, tag_value_t, ...);
|
||||
virtual ~AuthModule() {
|
||||
auth_mod_destroy(mAm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer on the underlying SofiaSip's authentication module.
|
||||
* This method is useful if you mean to call a SofiaSip function that needs
|
||||
* an auth_mod_t object as parameter.
|
||||
*/
|
||||
auth_mod_t* getPtr() const {
|
||||
return mAm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event loop which the authentication module is working on.
|
||||
* This has been define on module construction.
|
||||
*/
|
||||
su_root_t* getRoot() const {
|
||||
return mRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* These methods are C++ version of public method of auth_mod_t API. To find the associated
|
||||
* SofiaSip function, just prefix the name of the method by "auth_mod_" e.g. verify() -> auth_mod_verify().
|
||||
*/
|
||||
void verify(AuthStatus& as, msg_auth_t* credentials, auth_challenger_t const* ach) {
|
||||
auth_mod_verify(mAm, as.getPtr(), credentials, ach);
|
||||
}
|
||||
void challenge(AuthStatus& as, auth_challenger_t const* ach) {
|
||||
auth_mod_challenge(mAm, as.getPtr(), ach);
|
||||
}
|
||||
void authorize(AuthStatus& as, auth_challenger_t const* ach) {
|
||||
auth_mod_challenge(mAm, as.getPtr(), ach);
|
||||
}
|
||||
void cancel(AuthStatus& as) {
|
||||
auth_mod_cancel(mAm, as.getPtr());
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onCheck(AuthStatus& as, msg_auth_t* credentials, auth_challenger_t const* ach) = 0;
|
||||
virtual void onChallenge(AuthStatus& as, auth_challenger_t const* ach) = 0;
|
||||
virtual void onCancel(AuthStatus& as) = 0;
|
||||
|
||||
auth_mod_t* mAm = nullptr;
|
||||
|
||||
private:
|
||||
static void checkCb(auth_mod_t* am, auth_status_t* as, msg_auth_t* auth, auth_challenger_t const* ch) noexcept;
|
||||
static void challengeCb(auth_mod_t* am, auth_status_t* as, auth_challenger_t const* ach) noexcept;
|
||||
static void cancelCb(auth_mod_t* am, auth_status_t* as) noexcept;
|
||||
|
||||
static void registerScheme();
|
||||
|
||||
su_root_t* mRoot = nullptr;
|
||||
static const char* sMethodName;
|
||||
static auth_scheme_t sAuthScheme;
|
||||
static bool sSchemeRegistered;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
223
include/flexisip/sofia-wrapper/auth-status.hh
Normal file
223
include/flexisip/sofia-wrapper/auth-status.hh
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <sofia-sip/auth_module.h>
|
||||
|
||||
namespace flexisip {
|
||||
|
||||
/**
|
||||
* @brief Plain C++ wrapper for SofiaSip's auth_status_t structure.
|
||||
* @warning Like auth_status_t, this classe doesn't take ownership
|
||||
* on strings that have been set by setters. That means you must
|
||||
* guarantees the life of such strings while the authentication is processing.
|
||||
* If you cannot, you may copy the string by using the AuthStatus' internal
|
||||
* home_t object before giving it to the setter method. This one can be
|
||||
* got thanks to home() method.
|
||||
* @see See http://sofia-sip.sourceforge.net/refdocs/iptsec/structauth__status__t.html
|
||||
* for more documentation.
|
||||
*/
|
||||
class AuthStatus {
|
||||
public:
|
||||
using ResponseCb = std::function<void(AuthStatus& as)>;
|
||||
|
||||
AuthStatus() {
|
||||
su_home_init(&mHome);
|
||||
mPriv = auth_status_new(&mHome);
|
||||
mPriv->as_plugin = reinterpret_cast<auth_splugin_t*>(this);
|
||||
mPriv->as_callback = responseCb;
|
||||
}
|
||||
AuthStatus(const AuthStatus& other) = delete;
|
||||
virtual ~AuthStatus() {
|
||||
su_home_deinit(&mHome);
|
||||
}
|
||||
|
||||
bool allow() const {
|
||||
return mPriv->as_allow;
|
||||
}
|
||||
void allow(bool val) {
|
||||
mPriv->as_allow = val;
|
||||
}
|
||||
|
||||
bool anonymous() const {
|
||||
return mPriv->as_anonymous;
|
||||
}
|
||||
void anonymous(bool val) {
|
||||
mPriv->as_anonymous = val;
|
||||
}
|
||||
|
||||
const void* body() const {
|
||||
return mPriv->as_body;
|
||||
}
|
||||
void body(const void* val) {
|
||||
mPriv->as_body = val;
|
||||
}
|
||||
|
||||
isize_t bodyLen() const {
|
||||
return mPriv->as_bodylen;
|
||||
}
|
||||
void bodyLen(isize_t val) {
|
||||
mPriv->as_bodylen = val;
|
||||
}
|
||||
|
||||
bool blacklist() const {
|
||||
return mPriv->as_blacklist;
|
||||
}
|
||||
void blacklist(bool val) {
|
||||
mPriv->as_blacklist = val;
|
||||
}
|
||||
|
||||
const ResponseCb& callback() const {
|
||||
return mResponseCb;
|
||||
}
|
||||
void callback(const ResponseCb& cb) {
|
||||
mResponseCb = cb;
|
||||
}
|
||||
|
||||
const char* display() const {
|
||||
return mPriv->as_display;
|
||||
}
|
||||
void display(const char* val) {
|
||||
mPriv->as_display = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal home_t, which will be destroyed on destruction
|
||||
* of the AuthStatus.
|
||||
*/
|
||||
su_home_t* home() {
|
||||
return mPriv->as_home;
|
||||
}
|
||||
|
||||
msg_header_t* info() const {
|
||||
return mPriv->as_info;
|
||||
}
|
||||
void info(msg_header_t* val) {
|
||||
mPriv->as_info = val;
|
||||
}
|
||||
|
||||
auth_magic_t* magic() const {
|
||||
return mPriv->as_magic;
|
||||
}
|
||||
void magic(auth_magic_t* val) {
|
||||
mPriv->as_magic = val;
|
||||
}
|
||||
|
||||
msg_header_t* match() const {
|
||||
return mPriv->as_match;
|
||||
}
|
||||
void match(msg_header_t* val) {
|
||||
mPriv->as_match = val;
|
||||
}
|
||||
|
||||
const char* method() const {
|
||||
return mPriv->as_method;
|
||||
}
|
||||
void method(const char* val) {
|
||||
mPriv->as_method = val;
|
||||
}
|
||||
|
||||
msg_time_t nonceIssued() const {
|
||||
return mPriv->as_nonce_issued;
|
||||
}
|
||||
void nonceIssued(msg_time_t val) {
|
||||
mPriv->as_nonce_issued = val;
|
||||
}
|
||||
|
||||
const char* phrase() const {
|
||||
return mPriv->as_phrase;
|
||||
}
|
||||
void phrase(const char* val) {
|
||||
mPriv->as_phrase = val;
|
||||
}
|
||||
|
||||
const char* realm() const {
|
||||
return mPriv->as_realm;
|
||||
}
|
||||
void realm(const char* val) {
|
||||
mPriv->as_realm = val;
|
||||
}
|
||||
void realm(const std::string& val) {
|
||||
mPriv->as_realm = su_strdup(&mHome, val.c_str());
|
||||
}
|
||||
|
||||
msg_header_t* response() const {
|
||||
return mPriv->as_response;
|
||||
}
|
||||
void response(msg_header_t* val) {
|
||||
mPriv->as_response = val;
|
||||
}
|
||||
|
||||
su_addrinfo_t* source() const {
|
||||
return mPriv->as_source;
|
||||
}
|
||||
void source(su_addrinfo_t* val) {
|
||||
mPriv->as_source = val;
|
||||
}
|
||||
|
||||
bool stale() const {
|
||||
return mPriv->as_stale;
|
||||
}
|
||||
void stale(bool val) {
|
||||
mPriv->as_stale = val;
|
||||
}
|
||||
|
||||
int status() const {
|
||||
return mPriv->as_status;
|
||||
}
|
||||
void status(int val) {
|
||||
mPriv->as_status = val;
|
||||
}
|
||||
|
||||
const char* user() const {
|
||||
return mPriv->as_user;
|
||||
}
|
||||
void user(const char* val) {
|
||||
mPriv->as_user = val;
|
||||
}
|
||||
|
||||
const url_t* userUri() const {
|
||||
return mPriv->as_user_uri;
|
||||
}
|
||||
void userUri(const url_t* val) {
|
||||
mPriv->as_user_uri = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying SofiaSip's auth_status_t object.
|
||||
*/
|
||||
auth_status_t* getPtr() {
|
||||
return mPriv;
|
||||
}
|
||||
|
||||
private:
|
||||
static void responseCb([[maybe_unused]] auth_magic_t* magic, auth_status_t* as) {
|
||||
AuthStatus& authStatus = *reinterpret_cast<AuthStatus*>(as->as_plugin);
|
||||
if (authStatus.mResponseCb) authStatus.mResponseCb(authStatus);
|
||||
}
|
||||
|
||||
su_home_t mHome;
|
||||
auth_status_t* mPriv = nullptr;
|
||||
ResponseCb mResponseCb;
|
||||
};
|
||||
|
||||
} // namespace flexisip
|
112
include/flexisip/sofia-wrapper/home.hh
Normal file
112
include/flexisip/sofia-wrapper/home.hh
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "sofia-sip/sip_protos.h"
|
||||
#include "sofia-sip/su_alloc.h"
|
||||
|
||||
#include "flexisip/template-metaprogramming.hh"
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
/**
|
||||
* A wrapper for SofiaSip's su_home_t type.
|
||||
*/
|
||||
class Home {
|
||||
public:
|
||||
Home() noexcept {
|
||||
su_home_init(mHome);
|
||||
}
|
||||
Home(const Home& src) = delete;
|
||||
Home(Home&& src) noexcept : Home() {
|
||||
su_home_move(mHome, src.mHome);
|
||||
}
|
||||
~Home() noexcept {
|
||||
su_home_deinit(mHome);
|
||||
}
|
||||
|
||||
Home& operator=(const Home& src) = delete;
|
||||
Home& operator=(Home&& src) noexcept {
|
||||
reset();
|
||||
su_home_move(mHome, src.mHome);
|
||||
return *this;
|
||||
}
|
||||
|
||||
su_home_t* home() noexcept {
|
||||
return mHome;
|
||||
}
|
||||
const su_home_t* home() const noexcept {
|
||||
return mHome;
|
||||
}
|
||||
|
||||
// Free all the buffers which are referenced by this Home.
|
||||
void reset() noexcept {
|
||||
su_home_deinit(mHome);
|
||||
su_home_init(mHome);
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) noexcept {
|
||||
return su_alloc(mHome, size);
|
||||
}
|
||||
void free(void* data) noexcept {
|
||||
return su_free(mHome, data);
|
||||
}
|
||||
|
||||
char* vsprintf(char const* fmt, va_list ap) noexcept {
|
||||
return su_vsprintf(mHome, fmt, ap);
|
||||
}
|
||||
template <typename... Args>
|
||||
char* sprintf(const char* fmt, Args&&... args) noexcept {
|
||||
return su_sprintf(mHome, fmt, args...);
|
||||
}
|
||||
|
||||
// Equivalent to sip_contact_create
|
||||
template <typename... IterableOrStreamable>
|
||||
sip_contact_t* createContact(const std::string_view& url, IterableOrStreamable&&... params) {
|
||||
std::ostringstream contact{};
|
||||
contact << '<' << url << '>';
|
||||
(appendParam(contact, params), ...);
|
||||
return sip_contact_make(mHome, contact.str().c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename IterableOfStreamable,
|
||||
typename = std::enable_if_t<type::is_iterable<IterableOfStreamable>>,
|
||||
typename = std::enable_if_t<!type::is_streamable<IterableOfStreamable>>>
|
||||
static void appendParam(std::ostream& contact, const IterableOfStreamable& params) {
|
||||
for (const auto& param : params) {
|
||||
appendParam(contact, param);
|
||||
}
|
||||
}
|
||||
template <typename Streamable, typename = std::enable_if_t<type::is_streamable<Streamable>>>
|
||||
static void appendParam(std::ostream& contact, const Streamable& param) {
|
||||
contact << ';' << param;
|
||||
}
|
||||
|
||||
su_home_t mHome[1]{};
|
||||
};
|
||||
|
||||
} // namespace sofiasip
|
170
include/flexisip/sofia-wrapper/msg-sip.hh
Normal file
170
include/flexisip/sofia-wrapper/msg-sip.hh
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <sofia-sip/msg_addr.h>
|
||||
#include <sofia-sip/msg_types.h>
|
||||
#include <sofia-sip/sip_protos.h>
|
||||
#include <sofia-sip/su_alloc.h>
|
||||
|
||||
#include <bctoolbox/ownership.hh>
|
||||
|
||||
#include "flexisip/sip-boolean-expressions.hh"
|
||||
|
||||
#include "sip-header.hh"
|
||||
|
||||
using namespace ownership;
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
/**
|
||||
* Don't forget to update MsgSip::getPreviousPriority and MsgSip::getOrderedPrioritiesList if you update this enum.
|
||||
*/
|
||||
enum class MsgSipPriority { NonUrgent = 0, Normal = 1, Urgent = 2, Emergency = 3 };
|
||||
|
||||
class MsgSip {
|
||||
public:
|
||||
MsgSip() : mMsg{msg_create(sip_default_mclass(), 0)} {
|
||||
}
|
||||
MsgSip(Owned<msg_t>&& msg) : mMsg(std::move(msg)) {
|
||||
}
|
||||
MsgSip(BorrowedMut<msg_t> msg) : mMsg(msg_ref_create(msg)) {
|
||||
}
|
||||
MsgSip(MsgSip&& other) : mMsg(std::move(other.mMsg)) {
|
||||
}
|
||||
MsgSip(const MsgSip& other);
|
||||
/**
|
||||
* Construct a MsgSip parsing the string_view parameter.
|
||||
*
|
||||
* @throw Throw std::runtime_error if a parsing error occurred.
|
||||
*/
|
||||
MsgSip(int flags, std::string_view msg);
|
||||
|
||||
~MsgSip() noexcept {
|
||||
msg_destroy(mMsg.take());
|
||||
}
|
||||
|
||||
MsgSip& operator=(MsgSip&& other) {
|
||||
mMsg = std::move(other.mMsg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Borrowed<msg_t> getMsg() const {
|
||||
return {mMsg};
|
||||
}
|
||||
BorrowedMut<msg_t> getMsg() {
|
||||
return mMsg.borrow();
|
||||
}
|
||||
const sip_t* getSip() const {
|
||||
return (sip_t*)msg_object(mMsg);
|
||||
}
|
||||
sip_t* getSip() {
|
||||
return (sip_t*)msg_object(mMsg);
|
||||
}
|
||||
su_home_t* getHome() {
|
||||
return msg_home(static_cast<msg_t*>(mMsg.borrow()));
|
||||
}
|
||||
sockaddr* getSockAddr() {
|
||||
return msg_addrinfo(mMsg.borrow())->ai_addr;
|
||||
}
|
||||
|
||||
msg_header_t* findHeader(const std::string& name, bool searchUnknowns = false);
|
||||
const msg_header_t* findHeader(const std::string& name, bool searchUnknowns = false) const {
|
||||
return const_cast<MsgSip*>(this)->findHeader(name, searchUnknowns);
|
||||
}
|
||||
|
||||
sip_method_t getSipMethod() const {
|
||||
const auto rq = getSip()->sip_request;
|
||||
return rq != nullptr ? rq->rq_method : sip_method_unknown;
|
||||
}
|
||||
|
||||
std::string getCallID() const;
|
||||
|
||||
MsgSipPriority getPriority() const;
|
||||
|
||||
void serialize() {
|
||||
msg_serialize(mMsg.borrow(), (msg_pub_t*)getSip());
|
||||
}
|
||||
std::string msgAsString() const;
|
||||
std::string contextAsString() const;
|
||||
|
||||
bool isGroupChatInvite() const noexcept;
|
||||
bool isChatService() noexcept;
|
||||
|
||||
/**
|
||||
* Change the sip filter used by Flexisip to show or not request's body in logs.
|
||||
*
|
||||
* @param filterString string containing the name of the method.
|
||||
* @throw invalid_argument if filterString is not valid, or empty.
|
||||
*/
|
||||
static void setShowBodyFor(const std::string& filterString);
|
||||
|
||||
static std::shared_ptr<flexisip::SipBooleanExpression>& getShowBodyForFilter() {
|
||||
if (!sShowBodyFor) {
|
||||
sShowBodyFor = flexisip::SipBooleanExpressionBuilder::get().parse("content-type == 'application/sdp'");
|
||||
}
|
||||
return sShowBodyFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the priority just before the one in parameter;
|
||||
* @throw logic_error if current == MsgSipPriority::NonUrgent
|
||||
*/
|
||||
static MsgSipPriority getPreviousPriority(MsgSipPriority current);
|
||||
|
||||
static std::array<MsgSipPriority, 4> getOrderedPrioritiesList() {
|
||||
return {MsgSipPriority::Emergency, MsgSipPriority::Urgent, MsgSipPriority::Normal, MsgSipPriority::NonUrgent};
|
||||
};
|
||||
/**
|
||||
* Insert or add a SIP header in the SIP message.
|
||||
* If the header already exists in the message and is to be unique, then the new header replace the old one.
|
||||
* If the header already exists in the message and isn't to be unique, then the new header is inserted after
|
||||
* or before the current headers according the kind of the header.
|
||||
*/
|
||||
void insertHeader(SipHeader&& header) {
|
||||
su_home_move(getHome(), header.mHome.home());
|
||||
msg_header_insert(mMsg.borrow(), nullptr, header.mNativePtr);
|
||||
header.mNativePtr = nullptr;
|
||||
}
|
||||
/**
|
||||
* Create and insert a header in a SIP message.
|
||||
* @param HeaderT The header type.
|
||||
* @param args The arguments to give to the header constructor.
|
||||
*/
|
||||
template <typename HeaderT, typename... ArgsT>
|
||||
void makeAndInsert(ArgsT&&... args) {
|
||||
insertHeader(HeaderT{std::forward<ArgsT>(args)...});
|
||||
}
|
||||
|
||||
private:
|
||||
// Private attributes
|
||||
Owned<msg_t> mMsg{nullptr};
|
||||
|
||||
static std::shared_ptr<flexisip::SipBooleanExpression> sShowBodyFor;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& strm, const sofiasip::MsgSip& obj) noexcept;
|
||||
|
||||
}; // namespace sofiasip
|
329
include/flexisip/sofia-wrapper/sdp-parser.hh
Normal file
329
include/flexisip/sofia-wrapper/sdp-parser.hh
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sofia-sip/sdp.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
/** The error message associated with an SDP parser */
|
||||
class SdpParsingError : public std::string_view {
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream&, const SdpParsingError&);
|
||||
};
|
||||
|
||||
/**
|
||||
* SDP session or media attribute
|
||||
* ("a=" line)
|
||||
*/
|
||||
class SdpAttribute : private ::sdp_attribute_t {
|
||||
public:
|
||||
/**
|
||||
* An SDP attribute is just a bunch of pointers.
|
||||
* The default copy constructor will be shallow and (very) unsafe.
|
||||
* If you need a copy, write a dedicated function and think it through.
|
||||
*/
|
||||
SdpAttribute(const SdpAttribute&) = delete;
|
||||
|
||||
static SdpAttribute* wrap(::sdp_attribute_t*);
|
||||
|
||||
std::string_view name() const {
|
||||
return a_name;
|
||||
}
|
||||
|
||||
std::string_view value() const {
|
||||
return a_value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstraction to iterate over all members of a linked-list of ::sdp_attribute_t that match a given name
|
||||
*
|
||||
* This class is iterable.
|
||||
*/
|
||||
class SdpMediaAttributeFilter {
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
explicit Iterator(::sdp_attribute_t* ptr, const char* name);
|
||||
Iterator& operator++();
|
||||
bool operator!=(const Iterator& other) const {
|
||||
return mPtr != other.mPtr;
|
||||
}
|
||||
SdpAttribute& operator*() {
|
||||
return *SdpAttribute::wrap(mPtr);
|
||||
}
|
||||
|
||||
private:
|
||||
const char* const mName;
|
||||
::sdp_attribute_t* mPtr;
|
||||
};
|
||||
|
||||
explicit SdpMediaAttributeFilter(::sdp_attribute_t* head, const char* name) : mHead(head), mName(name) {
|
||||
}
|
||||
|
||||
Iterator begin() {
|
||||
return Iterator(mHead, mName);
|
||||
}
|
||||
Iterator end() {
|
||||
return Iterator(nullptr, mName);
|
||||
}
|
||||
|
||||
private:
|
||||
::sdp_attribute_t* mHead;
|
||||
const char* const mName;
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstraction to access a linked-list of ::sdp_attribute_t
|
||||
*/
|
||||
class SdpMediaAttributeList {
|
||||
public:
|
||||
explicit SdpMediaAttributeList(::sdp_attribute_t* head) : mHead(head){};
|
||||
|
||||
/** Find attributes matching given name. */
|
||||
SdpMediaAttributeFilter find(const char* name) {
|
||||
return SdpMediaAttributeFilter(mHead, name);
|
||||
}
|
||||
|
||||
private:
|
||||
::sdp_attribute_t* mHead;
|
||||
};
|
||||
|
||||
/**
|
||||
* SDP connection - host or group address.
|
||||
* ("c=" line)
|
||||
*
|
||||
* Some getters and setters are not yet implemented. They may be added later.
|
||||
*/
|
||||
class SdpConnection : private ::sdp_connection_t {
|
||||
public:
|
||||
using SofiaType = ::sdp_connection_t;
|
||||
/**
|
||||
* An SDP connection is just a bunch of pointers.
|
||||
* The default copy constructor will be shallow and (very) unsafe.
|
||||
* If you need a copy, write a dedicated function and think it through.
|
||||
*/
|
||||
SdpConnection(const SdpConnection&) = delete;
|
||||
|
||||
static SdpConnection* wrap(SofiaType*);
|
||||
SdpConnection* next() {
|
||||
return wrap(c_next);
|
||||
}
|
||||
|
||||
// Host or group address
|
||||
std::string_view address() const {
|
||||
return c_address;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstraction to iterate over sofia's embedded linked-list pattern.
|
||||
*
|
||||
* This class is iterable.
|
||||
*/
|
||||
template <typename WrapperT>
|
||||
class List {
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
explicit Iterator(WrapperT* ptr) : mPtr(ptr) {
|
||||
}
|
||||
Iterator& operator++() {
|
||||
mPtr = mPtr->next();
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const Iterator& other) const {
|
||||
return mPtr == other.mPtr;
|
||||
}
|
||||
bool operator!=(const Iterator& other) const {
|
||||
return mPtr != other.mPtr;
|
||||
}
|
||||
WrapperT& operator*() {
|
||||
return *mPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
WrapperT* mPtr;
|
||||
};
|
||||
|
||||
explicit List(typename WrapperT::SofiaType* head) : mHead(WrapperT::wrap(head)) {
|
||||
}
|
||||
|
||||
Iterator begin() {
|
||||
return Iterator(mHead);
|
||||
}
|
||||
static Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
WrapperT* mHead;
|
||||
};
|
||||
|
||||
/** Mapping from RTP payload to codec.
|
||||
* ("a=rtpmap:")
|
||||
*
|
||||
* Defines a mapping from an RTP payload to a particular codec.
|
||||
* In case of well-known payloads, the SdpRtpmap may be predefined, that is, generated by SDP parser without
|
||||
* corresponding "a" line in the SDP. It may also* contain the @c fmtp attribute, which is used to convey
|
||||
* format-specific parameters.
|
||||
*/
|
||||
class SdpRtpmap : private ::sdp_rtpmap_t {
|
||||
public:
|
||||
using SofiaType = ::sdp_rtpmap_t;
|
||||
|
||||
SdpRtpmap(const SdpRtpmap&) = delete;
|
||||
|
||||
static SdpRtpmap* wrap(SofiaType*);
|
||||
SdpRtpmap* next() {
|
||||
return wrap(rm_next);
|
||||
}
|
||||
|
||||
// Codec name
|
||||
auto encoding() const {
|
||||
return std::string_view(rm_encoding);
|
||||
}
|
||||
// Sampling rate
|
||||
unsigned long rate() const {
|
||||
return rm_rate;
|
||||
}
|
||||
};
|
||||
|
||||
/** Media announcement.
|
||||
* ("m=" line)
|
||||
*
|
||||
* This structure describes one media type, e.g., audio. The description
|
||||
* contains the transport address (IP address and port) used for the group,
|
||||
* the transport protocol used, the media formats or RTP payload types, and
|
||||
* optionally media-specific bandwidth specification, encryption key and
|
||||
* attributes.
|
||||
*
|
||||
* There is a pointer (m_user) for the application data, too.
|
||||
*
|
||||
* Some getters and setters are not yet implemented. They may be added later.
|
||||
*/
|
||||
class SdpMedia : private ::sdp_media_t {
|
||||
public:
|
||||
using SofiaType = ::sdp_media_t;
|
||||
/**
|
||||
* An SDP media is just a bunch of pointers.
|
||||
* The default copy constructor will be shallow and (very) unsafe.
|
||||
* If you need a copy, write a dedicated function and think it through.
|
||||
*/
|
||||
SdpMedia(const SdpMedia&) = delete;
|
||||
|
||||
static SdpMedia* wrap(SofiaType*);
|
||||
SdpMedia* next() {
|
||||
return wrap(m_next);
|
||||
}
|
||||
|
||||
// Media attributes
|
||||
SdpMediaAttributeList attributes() {
|
||||
return SdpMediaAttributeList(m_attributes);
|
||||
}
|
||||
// List of addresses used
|
||||
auto connections() {
|
||||
return List<SdpConnection>(m_connections);
|
||||
}
|
||||
// List of RTP maps
|
||||
auto rtpMaps() {
|
||||
return List<SdpRtpmap>(m_rtpmaps);
|
||||
}
|
||||
// Media type name
|
||||
std::string_view typeName() const {
|
||||
return m_type_name;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SDP session description
|
||||
*
|
||||
* Created by `SdpParser`
|
||||
*
|
||||
* Some getters and setters are not yet implemented. They may be added later.
|
||||
*/
|
||||
class SdpSession : private ::sdp_session_t {
|
||||
public:
|
||||
/**
|
||||
* An SDP session is just a bunch of pointers.
|
||||
* The default copy constructor will be shallow and (very) unsafe.
|
||||
* If you need a copy, write a dedicated function and think it through.
|
||||
*/
|
||||
SdpSession(const SdpSession&) = delete;
|
||||
|
||||
static SdpSession* wrap(::sdp_session_t*);
|
||||
|
||||
// Media descriptors
|
||||
auto medias() {
|
||||
return List<SdpMedia>(sdp_media);
|
||||
}
|
||||
// Group (or member) address
|
||||
SdpConnection& connection();
|
||||
};
|
||||
|
||||
/**
|
||||
* A thin wrapper for SofiaSip's `sdp_parser` type.
|
||||
*/
|
||||
class SdpParser {
|
||||
public:
|
||||
struct Deleter {
|
||||
void operator()(SdpParser*) noexcept;
|
||||
};
|
||||
using UniquePtr = std::unique_ptr<SdpParser, Deleter>;
|
||||
|
||||
// The flags list is not exhaustive. The other flags supported by sdp_parse may be added later.
|
||||
enum class Flags : int {
|
||||
None = 0,
|
||||
Strict = ::sdp_parse_flags_e::sdp_f_strict,
|
||||
};
|
||||
|
||||
// Create a new stand-alone SdpParser
|
||||
static UniquePtr parse(std::string_view msg, Flags flags = Flags::None);
|
||||
// Create a new SdpParser managed by a su_home_t
|
||||
static SdpParser& parse(su_home_t&, std::string_view msg, Flags flags = Flags::None);
|
||||
|
||||
// Prevent creating instances of this class.
|
||||
// Only references will be obtained via `reinterpret_cast`ing
|
||||
SdpParser() = delete;
|
||||
SdpParser(const SdpParser&) = delete;
|
||||
SdpParser& operator=(const SdpParser&) = delete;
|
||||
~SdpParser() = delete;
|
||||
|
||||
/** Retrieve an SDP session structure.
|
||||
*
|
||||
* @return
|
||||
* Returns a reference to a parsed SDP message or, if an error has occurred, a string description of the error.
|
||||
* The reference and all the data in the structure are valid until the SdpParser is destructed.
|
||||
*/
|
||||
std::variant<std::reference_wrapper<SdpSession>, SdpParsingError> session();
|
||||
|
||||
private:
|
||||
// Bare wrapper to `sdp_parse`
|
||||
static SdpParser* parse(su_home_t*, std::string_view msg, Flags flags);
|
||||
|
||||
// Retrieve the raw sofia pointer
|
||||
::sdp_parser toSofia();
|
||||
};
|
||||
|
||||
} // namespace sofiasip
|
119
include/flexisip/sofia-wrapper/sip-header.hh
Normal file
119
include/flexisip/sofia-wrapper/sip-header.hh
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2024 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <sofia-sip/msg_header.h>
|
||||
|
||||
#include "flexisip/flexisip-exception.hh"
|
||||
#include "flexisip/sofia-wrapper/home.hh"
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
/**
|
||||
* Base class for all SIP header classes.
|
||||
* It is actually a wrapper for the SofiaSip msg_header_t type.
|
||||
* Every header are copy-constructable and move-constructable.
|
||||
*/
|
||||
class SipHeader {
|
||||
public:
|
||||
const msg_header_t* getNativePtr() const {
|
||||
return mNativePtr;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class MsgSip;
|
||||
|
||||
SipHeader() = default;
|
||||
SipHeader(const SipHeader& src) {
|
||||
mNativePtr = msg_header_dup(mHome.home(), src.mNativePtr);
|
||||
}
|
||||
SipHeader(SipHeader&& src) noexcept {
|
||||
mHome = std::move(src.mHome);
|
||||
mNativePtr = src.mNativePtr;
|
||||
src.mNativePtr = nullptr;
|
||||
}
|
||||
virtual ~SipHeader() = default;
|
||||
|
||||
template <typename HeaderT>
|
||||
void setNativePtr(HeaderT* header) {
|
||||
mNativePtr = reinterpret_cast<msg_header_t*>(header);
|
||||
}
|
||||
|
||||
Home mHome{};
|
||||
msg_header_t* mNativePtr{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* Represent a sofiasip @ref msg_param_t.
|
||||
*/
|
||||
class SipMsgParam {
|
||||
public:
|
||||
SipMsgParam() = delete;
|
||||
/**
|
||||
* Automatically parses the given parameter.
|
||||
* The parameter should be formatted as "key=value".
|
||||
*
|
||||
* @throw flexisip::FlexisipException if the parameter is ill-formatted.
|
||||
*/
|
||||
explicit SipMsgParam(std::string_view param) : mParam(param) {
|
||||
const auto delimiterPosition = mParam.find('=');
|
||||
if (delimiterPosition == std::string::npos) {
|
||||
throw flexisip::FlexisipException{R"(parameter is ill-formatted, missing "=" character ")" +
|
||||
std::string{mParam} + "\""};
|
||||
}
|
||||
|
||||
mKey = mParam.substr(0, delimiterPosition);
|
||||
mValue = mParam.substr(delimiterPosition + 1, mParam.size());
|
||||
}
|
||||
SipMsgParam(const SipMsgParam& other) = default;
|
||||
SipMsgParam(SipMsgParam&& other) = default;
|
||||
|
||||
/*
|
||||
* Get raw parameter value.
|
||||
*/
|
||||
std::string_view getParam() const {
|
||||
return mParam;
|
||||
}
|
||||
std::string_view getKey() const {
|
||||
return mKey;
|
||||
}
|
||||
std::string_view getValue() const {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
const char* str() const {
|
||||
return mParam.data();
|
||||
}
|
||||
|
||||
bool operator==(const SipMsgParam& other) const {
|
||||
return mParam == other.mParam;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view mParam;
|
||||
std::string_view mKey;
|
||||
std::string_view mValue;
|
||||
};
|
||||
|
||||
} // namespace sofiasip
|
87
include/flexisip/sofia-wrapper/su-root.hh
Normal file
87
include/flexisip/sofia-wrapper/su-root.hh
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2022 Belledonne Communications SARL.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "flexisip/sofia-wrapper/timer.hh"
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
class SuRoot {
|
||||
public:
|
||||
using NativeDuration = std::chrono::duration<su_duration_t, std::milli>;
|
||||
|
||||
SuRoot() : mCPtr{su_root_create(nullptr)} {
|
||||
if (mCPtr == nullptr) {
|
||||
throw std::runtime_error{"su_root_t allocation failed"};
|
||||
}
|
||||
}
|
||||
SuRoot(const SuRoot&) = delete;
|
||||
~SuRoot() {
|
||||
// Clear the list first because su_root_destroy free all timers, and lead to
|
||||
// heap-use-after-free if done before the list destruction.
|
||||
mOneShotTimerList.clear();
|
||||
su_root_destroy(mCPtr);
|
||||
}
|
||||
|
||||
su_root_t* getCPtr() const noexcept {
|
||||
return mCPtr;
|
||||
}
|
||||
|
||||
template <typename Duration>
|
||||
auto step(Duration timeout) {
|
||||
return NativeDuration(su_root_step(mCPtr, std::chrono::duration_cast<NativeDuration>(timeout).count()));
|
||||
}
|
||||
|
||||
template <typename Duration>
|
||||
auto sleep(Duration duration) {
|
||||
return NativeDuration(su_root_sleep(mCPtr, std::chrono::duration_cast<NativeDuration>(duration).count()));
|
||||
}
|
||||
|
||||
void run() {
|
||||
su_root_run(mCPtr);
|
||||
}
|
||||
void quit() {
|
||||
su_root_break(mCPtr);
|
||||
}
|
||||
_su_task_r getTask() const {
|
||||
return su_root_task(mCPtr);
|
||||
}
|
||||
|
||||
void addToMainLoop(std::function<void()>&& functionToAdd);
|
||||
void addToMainLoop(const std::function<void()>& functionToAdd);
|
||||
void addOneShotTimer(const std::function<void()>& timerFunction, NativeDuration ms);
|
||||
template <typename Duration>
|
||||
void addOneShotTimer(const std::function<void()>& timerFunction, Duration ms) {
|
||||
addOneShotTimer(timerFunction, std::chrono::duration_cast<NativeDuration>(ms));
|
||||
}
|
||||
|
||||
private:
|
||||
static void mainLoopFunctionCallback(su_root_magic_t* rm, su_msg_r msg, void* u) noexcept;
|
||||
static void mainLoopFunctionCallbackDeinitializer(su_msg_arg_t* data) noexcept;
|
||||
|
||||
::su_root_t* mCPtr{nullptr};
|
||||
std::list<sofiasip::Timer> mOneShotTimerList{};
|
||||
};
|
||||
|
||||
} // namespace sofiasip
|
126
include/flexisip/sofia-wrapper/timer.hh
Normal file
126
include/flexisip/sofia-wrapper/timer.hh
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Flexisip, a flexible SIP proxy server with media capabilities.
|
||||
Copyright (C) 2010-2025 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <sofia-sip/su_wait.h>
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
class SuRoot;
|
||||
|
||||
/**
|
||||
* @brief Helping class for manipulating SofiaSip's timers.
|
||||
*/
|
||||
class Timer {
|
||||
public:
|
||||
/**
|
||||
* @brief Callbacks that is called when the timer expires.
|
||||
*/
|
||||
using Func = std::function<void()>;
|
||||
using NativeDuration = std::chrono::duration<su_duration_t, std::milli>;
|
||||
|
||||
/**
|
||||
* @brief Create a timer.
|
||||
* @param[in] root SofiaSip's event loop.
|
||||
* @param[in] intervalMs Default timer expiration interval in milliseconds.
|
||||
* @throw std::logic_error if the timer couldn't been created.
|
||||
*/
|
||||
[[deprecated]] explicit Timer(su_root_t* root, su_duration_t intervalMs = 0);
|
||||
|
||||
[[deprecated]] Timer(su_root_t* root, NativeDuration interval) : Timer{root, interval.count()} {};
|
||||
[[deprecated]] Timer(const sofiasip::SuRoot& root, NativeDuration interval);
|
||||
|
||||
[[deprecated]] explicit Timer(const std::shared_ptr<sofiasip::SuRoot>& root, su_duration_t intervalMs = 0);
|
||||
|
||||
explicit Timer(const std::shared_ptr<sofiasip::SuRoot>& root, NativeDuration interval);
|
||||
|
||||
~Timer();
|
||||
|
||||
/**
|
||||
* Copying or moving a timer has no sense.
|
||||
*/
|
||||
Timer(const Timer&) = delete;
|
||||
Timer(Timer&&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Start the timer with the default expiration time.
|
||||
* @param[in] func The function to call when the timer expires. The
|
||||
* context of the function is copied and automatically destroyed on
|
||||
* timer expiration.
|
||||
* @throw std::logic_error if the time couldn't be set.
|
||||
*/
|
||||
void set(const Func& func);
|
||||
/**
|
||||
* @brief Start the timer with a specific expiration time.
|
||||
* @param[in] func The function to call when the timer expires. The
|
||||
* context of the function is copied and automatically destroyed on
|
||||
* timer expiration.
|
||||
* @param[in] intervalMs The expiration time in ms.
|
||||
* @throw std::logic_error if the timer couldn't been set.
|
||||
*/
|
||||
void set(const Func& func, su_duration_t intervalMs);
|
||||
|
||||
/**
|
||||
* @brief Same as before, but using std::chrono for time interval.
|
||||
*/
|
||||
void set(const Func& func, NativeDuration interval) {
|
||||
set(func, interval.count());
|
||||
}
|
||||
template <typename Duration>
|
||||
void set(const Func& func, Duration interval) {
|
||||
set(func, std::chrono::duration_cast<NativeDuration>(interval));
|
||||
}
|
||||
/**
|
||||
* @brief Start the timer to be executed regularly.
|
||||
* @param[in] func The function to call on each interval
|
||||
* of time. The context of the function is copied and is
|
||||
* only destroyed on reset() call.
|
||||
* @throw std::logic_error if the timer couldn't be stated.
|
||||
*
|
||||
* Use with care as it will be called numerous times in case of time leap.
|
||||
*/
|
||||
void run(const Func& func);
|
||||
/**
|
||||
* @brief Same as run() except it doesn't try to catch up missed callbacks.
|
||||
*/
|
||||
void setForEver(const Func& func);
|
||||
/**
|
||||
* @brief Stop the timer and delete the internal function.
|
||||
* @throw std::logic_error if the timer couldn't been reset.
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* @brief Check whether the timer has already been set.
|
||||
*/
|
||||
bool isRunning() const;
|
||||
|
||||
private:
|
||||
static void _oneShotTimerCb(su_root_magic_t* magic, su_timer_t* t, su_timer_arg_t* arg) noexcept;
|
||||
static void _regularTimerCb(su_root_magic_t* magic, su_timer_t* t, su_timer_arg_t* arg) noexcept;
|
||||
|
||||
std::shared_ptr<sofiasip::SuRoot> mRoot{};
|
||||
su_timer_t* _timer = nullptr;
|
||||
Func _func;
|
||||
};
|
||||
|
||||
} // namespace sofiasip
|
50
include/flexisip/sofia-wrapper/waker.hh
Normal file
50
include/flexisip/sofia-wrapper/waker.hh
Normal file
|
@ -0,0 +1,50 @@
|
|||
/** Copyright (C) 2010-2023 Belledonne Communications SARL
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <sofia-sip/su_wait.h>
|
||||
|
||||
namespace sofiasip {
|
||||
|
||||
/**
|
||||
* Wraps a sofia wait register to unregister it on destruction
|
||||
*/
|
||||
class Waker {
|
||||
public:
|
||||
using Callback = std::function<int(su_root_magic_t*, su_wait_t*)>;
|
||||
|
||||
/** SAFETY:
|
||||
* - `root` MUST NOT be null and MUST be valid for the lifetime of the Waker
|
||||
*/
|
||||
Waker(su_root_t* root, int fileDescriptor, Callback&& callback, int priority)
|
||||
: mCallback(std::move(callback)), mRoot(root) {
|
||||
su_wait_create(&mWait, fileDescriptor, SU_WAIT_IN);
|
||||
su_root_register(
|
||||
mRoot, &mWait,
|
||||
[](su_root_magic_t* root, su_wait_t* wait, su_wakeup_arg_t* arg) noexcept {
|
||||
auto& lambda = *static_cast<Callback*>(arg);
|
||||
return lambda(root, wait);
|
||||
},
|
||||
&mCallback, priority);
|
||||
}
|
||||
~Waker() {
|
||||
su_root_unregister(mRoot, &mWait, nullptr, &mCallback);
|
||||
}
|
||||
|
||||
Waker(const Waker& other) = delete;
|
||||
Waker& operator=(const Waker& other) = delete;
|
||||
Waker(Waker&& other) = delete;
|
||||
Waker& operator=(Waker&& other) = delete;
|
||||
|
||||
private:
|
||||
Callback mCallback;
|
||||
su_root_t* mRoot; // borrow
|
||||
su_wait_t mWait{0};
|
||||
};
|
||||
|
||||
} // namespace sofiasip
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue