From c05bf4ac67b7badbaf4f6b1b4a031a3cc341243c Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Sat, 15 Jun 2024 19:48:36 -0700 Subject: [PATCH 1/7] rtp.io: add a new rtp.io module. What rtp.io module does is it starts up a RTP handling threads in the separate "opensips" process and let rtpproxy module access those threads via a 1:1 socketpair, thus providing usual media relaying functionality without using any external relay process. The module requires RTPProxy 3.1 or higher, compiled with --enable-librtpproxy (or respective Docker image that is pushed to GHCR and Docker.hub on every commit). When rtpproxy module is loaded without arguments and rtp.io is loaded as well, the sockets exported by the rtp.io will be used automatically in the set 0. Otherwise those sockets can be used as part of other set(s) by using "rtp.io:auto" moniker. Provided is also a CI job that builds rtp.io in a rtpproxy container for all supported architectures and tests it using voiptests package. TODO list: o hook up notification socket directly into appropriate handler on the OpenSIPS side; o generate -l / -6 option(s) based on OpenSIPS's own socket list; o more documentation. --- .github/workflows/.rtp.io.yml | 274 ++++++++++++++++++++++++ .github/workflows/rtp.io.yml | 132 ++++++++++++ Makefile.conf.template | 13 +- docker/Dockerfile.rtp.io | 57 +++++ modules/rtp.io/Makefile | 12 ++ modules/rtp.io/doc/contributors.xml | 0 modules/rtp.io/doc/rtp.io.xml | 29 +++ modules/rtp.io/doc/rtp.io_admin.xml | 72 +++++++ modules/rtp.io/rtp_io.c | 239 +++++++++++++++++++++ modules/rtp.io/rtp_io.h | 34 +++ modules/rtp.io/rtp_io_api.h | 3 + modules/rtp.io/rtp_io_host.c | 105 +++++++++ modules/rtp.io/rtp_io_host.h | 7 + modules/rtp.io/rtp_io_params.c | 38 ++++ modules/rtp.io/rtp_io_params.h | 3 + modules/rtp.io/rtp_io_util.c | 105 +++++++++ modules/rtp.io/rtp_io_util.h | 13 ++ scripts/build/do_build.sh | 15 +- scripts/build/get-arch-buildargs.rtp.io | 67 ++++++ 19 files changed, 1214 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/.rtp.io.yml create mode 100644 .github/workflows/rtp.io.yml create mode 100644 docker/Dockerfile.rtp.io create mode 100644 modules/rtp.io/Makefile create mode 100644 modules/rtp.io/doc/contributors.xml create mode 100644 modules/rtp.io/doc/rtp.io.xml create mode 100644 modules/rtp.io/doc/rtp.io_admin.xml create mode 100644 modules/rtp.io/rtp_io.c create mode 100644 modules/rtp.io/rtp_io.h create mode 100644 modules/rtp.io/rtp_io_api.h create mode 100644 modules/rtp.io/rtp_io_host.c create mode 100644 modules/rtp.io/rtp_io_host.h create mode 100644 modules/rtp.io/rtp_io_params.c create mode 100644 modules/rtp.io/rtp_io_params.h create mode 100644 modules/rtp.io/rtp_io_util.c create mode 100644 modules/rtp.io/rtp_io_util.h create mode 100755 scripts/build/get-arch-buildargs.rtp.io diff --git a/.github/workflows/.rtp.io.yml b/.github/workflows/.rtp.io.yml new file mode 100644 index 00000000000..fc163091029 --- /dev/null +++ b/.github/workflows/.rtp.io.yml @@ -0,0 +1,274 @@ +name: rtp.io + +on: + workflow_call: + inputs: + llvm-version: + required: true + type: string + llvm-version-old: + required: true + type: string + ghcr-repo: + required: false + type: string + default: ghcr.io/${{ github.repository_owner }}/opensips + rtpp-repo: + required: false + type: string + default: ghcr.io/sippy/rtpproxy:latest + rtpp-tag: + required: false + type: string + default: debian_12-slim + +jobs: + set_env: + name: Set Environment + runs-on: ubuntu-latest + env: + BASE_IMAGE: ${{ inputs.rtpp-repo }}-${{ inputs.rtpp-tag }} + outputs: + platforms: ${{ steps.set-env.outputs.platforms }} + build-matrix: ${{ steps.set-env.outputs.build-matrix }} + test-matrix: ${{ steps.set-env.outputs.test-matrix }} + build-os: ${{ steps.set-env.outputs.build-os }} + build-image: ${{ steps.set-env.outputs.build-image }} + git-branch: ${{ steps.set-env.outputs.git-branch }} + steps: + - uses: actions/checkout@v4 + + - name: Set dynamic environment + id: set-env + run: | + BUILD_OS="`echo ${{ inputs.rtpp-tag }} | sed 's|-.*|| ; s|_|-|g'`" + PLATFORMS="`docker manifest inspect ${{ env.BASE_IMAGE }} | \ + jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture)\(if .platform.variant != null then "/\(.platform.variant)" else "" end)"' | \ + sort -u | grep -v unknown | BUILD_OS="${BUILD_OS}" ./scripts/build/get-arch-buildargs.rtp.io fltplatforms | paste -sd ','`" + BUILD_MATRIX="`echo ${PLATFORMS} | tr ',' '\n' | jq -R . | jq -s . | tr '\n' ' '`" + GIT_BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" + GIT_BRANCH="${GIT_BRANCH#refs/tags/}" + BUILD_IMAGE="${{ inputs.ghcr-repo }}:rtp.io-${{ inputs.rtpp-tag }}-${GIT_BRANCH}" + echo "Platforms: ${PLATFORMS}" + for _p in `echo ${PLATFORMS} | tr ',' '\n'`; \ + do \ + if TARGETPLATFORM="${_p}" BUILD_OS="${BUILD_OS}" ./scripts/build/get-arch-buildargs.rtp.io isbrokenplatform; \ + then \ + TEST_MATRIX="${_p}${TEST_MATRIX:+,}${TEST_MATRIX}"; \ + fi; \ + done + TEST_MATRIX="`echo ${TEST_MATRIX} | tr ',' '\n' | jq -R . | jq -s . | tr '\n' ' '`" + echo "platforms=${PLATFORMS}" >> $GITHUB_OUTPUT + echo "build-matrix=${BUILD_MATRIX}" >> $GITHUB_OUTPUT + echo "test-matrix=${TEST_MATRIX}" >> $GITHUB_OUTPUT + echo "build-os=${BUILD_OS}" >> $GITHUB_OUTPUT + echo "build-image=${BUILD_IMAGE}" >> $GITHUB_OUTPUT + echo "git-branch=${GIT_BRANCH}" >> $GITHUB_OUTPUT + + build_rtp_io_dock: + name: Build Container (GHCR) + needs: set_env + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + permissions: + packages: write + env: + BASE_IMAGE: ${{ inputs.rtpp-repo }}-${{ inputs.rtpp-tag }} + BUILD_OS: ${{ needs.set_env.outputs.build-os }} + PLATFORMS: ${{ needs.set_env.outputs.platforms }} + BUILD_IMAGE: ${{ needs.set_env.outputs.build-image }} + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Checkout VoIPTests repo + uses: actions/checkout@v4 + with: + repository: 'sippy/voiptests' + path: dist/voiptests + + - name: Checkout RTPProxy repo + uses: actions/checkout@v4 + with: + repository: 'sippy/rtpproxy' + path: dist/rtpproxy + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Docker image + uses: docker/build-push-action@v6 + env: + CACHE_SPEC: "type=registry,ref=${{ env.BUILD_IMAGE }}-buildcache" + with: + context: . + file: ./docker/Dockerfile.rtp.io + build-args: | + BASE_IMAGE=${{ env.BASE_IMAGE }} + BUILD_OS=${{ env.BUILD_OS }} + LLVM_VER=${{ inputs.llvm-version }} + LLVM_VER_OLD=${{ inputs.llvm-version-old }} + platforms: ${{ env.PLATFORMS }} + cache-from: ${{ env.CACHE_SPEC }} + cache-to: ${{ env.CACHE_SPEC }},mode=max + tags: ${{ env.BUILD_IMAGE }} + push: true + + build_rtp_io_dock_local: + name: Build Container (Local) + needs: set_env + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request' }} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJSON(needs.set_env.outputs.build-matrix) }} + env: + BASE_IMAGE: ${{ inputs.rtpp-repo }}-${{ inputs.rtpp-tag }} + BUILD_OS: ${{ needs.set_env.outputs.build-os }} + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Checkout VoIPTests repo + uses: actions/checkout@v4 + with: + repository: 'sippy/voiptests' + path: dist/voiptests + + - name: Checkout RTPProxy repo + uses: actions/checkout@v4 + with: + repository: 'sippy/rtpproxy' + path: dist/rtpproxy + + - name: Set up QEMU + if: matrix.platform != 'linux/386' && matrix.platform != 'linux/amd64' + uses: docker/setup-qemu-action@v3 + with: + platforms: ${{ matrix.platform }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set dynamic environment + id: set-env + run: | + OUTPUT_TAG="myimage:`echo ${{ matrix.platform }} | sed 's|/|-|g'`" + OUTPUT_IMAGE_N="image-${BUILD_OS}-`echo ${{ matrix.platform }} | sed 's|/|-|g'`" + OUTPUT_IMAGE="./${OUTPUT_IMAGE_N}.tar" + CACHE_SPEC="type=gha,scope=${OUTPUT_IMAGE_N}-buildcache" + echo OUTPUT_TAG="${OUTPUT_TAG}" >> $GITHUB_ENV + echo OUTPUT_IMAGE="${OUTPUT_IMAGE}" >> $GITHUB_ENV + echo OUTPUT_IMAGE_N="${OUTPUT_IMAGE_N}" >> $GITHUB_ENV + echo CACHE_SPEC="${CACHE_SPEC}" >> $GITHUB_ENV + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/Dockerfile.rtp.io + build-args: | + BASE_IMAGE=${{ env.BASE_IMAGE }} + BUILD_OS=${{ env.BUILD_OS }} + LLVM_VER=${{ inputs.llvm-version }} + LLVM_VER_OLD=${{ inputs.llvm-version-old }} + platforms: ${{ matrix.platform }} + tags: ${{ env.OUTPUT_TAG }} + outputs: type=docker,dest=${{ env.OUTPUT_IMAGE }} + cache-from: ${{ env.CACHE_SPEC }} + cache-to: ${{ env.CACHE_SPEC }},mode=max + + - name: Upload image artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.OUTPUT_IMAGE_N }} + path: ${{ env.OUTPUT_IMAGE }} + + test_rtp_io_dock: + name: Test (GHCR) + needs: [build_rtp_io_dock, set_env] + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJSON(needs.set_env.outputs.test-matrix) }} + env: + TARGETPLATFORM: ${{ matrix.platform }} + BUILD_IMAGE: ${{ needs.set_env.outputs.build-image }} + BUILD_OS: ${{ needs.set_env.outputs.build-os }} + + steps: + - name: Set up QEMU + if: matrix.platform != 'linux/386' && matrix.platform != 'linux/amd64' + uses: docker/setup-qemu-action@v3 + with: + platforms: ${{ env.TARGETPLATFORM }} + + - name: Test ${{ env.TARGETPLATFORM }} + run: | + docker pull ${BUILD_IMAGE} + docker run --platform ${TARGETPLATFORM} --name test --cap-add=SYS_PTRACE \ + --privileged --sysctl net.ipv6.conf.all.disable_ipv6=0 ${BUILD_IMAGE} + timeout-minutes: 2 + + test_rtp_io_local: + name: Test (LOCAL) + needs: [build_rtp_io_dock_local, set_env] + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request' }} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJSON(needs.set_env.outputs.test-matrix) }} + env: + TARGETPLATFORM: ${{ matrix.platform }} + BUILD_IMAGE: ${{ needs.set_env.outputs.build-image }} + BUILD_OS: ${{ needs.set_env.outputs.build-os }} + + steps: + - name: Set dynamic environment + id: set-env + run: | + OUTPUT_TAG="myimage:`echo ${{ matrix.platform }} | sed 's|/|-|g'`" + OUTPUT_IMAGE_N="image-${BUILD_OS}-`echo ${{ matrix.platform }} | sed 's|/|-|g'`" + OUTPUT_IMAGE="./${OUTPUT_IMAGE_N}.tar" + echo OUTPUT_TAG="${OUTPUT_TAG}" >> $GITHUB_ENV + echo OUTPUT_IMAGE="${OUTPUT_IMAGE}" >> $GITHUB_ENV + echo OUTPUT_IMAGE_N="${OUTPUT_IMAGE_N}" >> $GITHUB_ENV + + - name: Set up QEMU + if: matrix.platform != 'linux/386' && matrix.platform != 'linux/amd64' + uses: docker/setup-qemu-action@v3 + with: + platforms: ${{ env.TARGETPLATFORM }} + + - name: Download image artifact + uses: actions/download-artifact@v4 + with: + name: ${{ env.OUTPUT_IMAGE_N }} + path: . + + - name: Load Docker image + run: docker load -i ${{ env.OUTPUT_IMAGE }} + + - name: Test ${{ env.TARGETPLATFORM }} + run: | + docker run --platform ${TARGETPLATFORM} --name test --cap-add=SYS_PTRACE \ + --privileged --sysctl net.ipv6.conf.all.disable_ipv6=0 ${OUTPUT_TAG} + timeout-minutes: 2 diff --git a/.github/workflows/rtp.io.yml b/.github/workflows/rtp.io.yml new file mode 100644 index 00000000000..c29b77b85db --- /dev/null +++ b/.github/workflows/rtp.io.yml @@ -0,0 +1,132 @@ +# This is a basic workflow to help you get started with Actions + +name: rtp.io + +# Controls when the action will run. +on: + # Triggers the workflow on all push or pull request events + push: + pull_request: + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + LLVM_VER: 18 + LLVM_VER_OLD: 16 + GHCR_REPO: ghcr.io/${{ github.repository_owner }}/opensips + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build_test_rtp_io_quick: + name: Build & Test rtp.io module (Quick) + # The type of runner that the job will run on + runs-on: ubuntu-latest + container: + image: sippylabs/rtpproxy:latest + options: --cap-add=SYS_PTRACE --privileged --sysctl net.ipv6.conf.all.disable_ipv6=0 + env: + PYTHON_VERSION: 3.12 + BUILD_OS: ubuntu-latest + outputs: + llvm_ver: ${{ steps.set_outputs.outputs.LLVM_VER }} + llvm_ver_old: ${{ steps.set_outputs.outputs.LLVM_VER_OLD }} + ghcr-repo: ${{ steps.set_outputs.outputs.GHCR_REPO }} + + steps: + - name: Set up environment + run: echo "COMPILER=clang-${LLVM_VER}" >> $GITHUB_ENV + + - name: Install git + run: | + apt-get update + apt-get install -y git lsb-release gnupg2 wget + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Checkout VoIPTests repo + uses: actions/checkout@v4 + with: + repository: 'sippy/voiptests' + path: dist/voiptests + + - name: Checkout RTPProxy repo + uses: actions/checkout@v4 + with: + repository: 'sippy/rtpproxy' + path: dist/rtpproxy + + - name: Install dependencies + run: | + sh -x scripts/build/reset_sources.sh + sh -x scripts/build/install_depends.sh + + - name: Build + run: | + KEEP_MODULES="dialog sipmsgops sl tm rr maxfwd rtp.io rtpproxy textops" + SKIP_MODULES="usrloc event_routing clusterer rtp_relay" + mkdir tmp + cd modules + mv ${KEEP_MODULES} ${SKIP_MODULES} ../tmp + rm -rf * + cd ../tmp + mv ${KEEP_MODULES} ${SKIP_MODULES} ../modules + cd .. + rmdir tmp + EXCLUDE_MODULES_ADD="${SKIP_MODULES}" sh -x scripts/build/do_build.sh + + - name: Build rtp.io module + run: | + apt-get install -y libsrtp2-dev + ONE_MODULE=rtp.io LDFLAGS=-flto CFLAGS=-flto sh -x scripts/build/do_build.sh + + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Define PYTHON_CMD + run: | + PYTHON_VER="`echo ${{ env.PYTHON_VERSION }} | sed 's|-dev$||'`" + echo "PYTHON_CMD=python${PYTHON_VER}" >> $GITHUB_ENV + + - name: Test rtp.io module + env: + MM_TYPE: opensips + MM_BRANCH: master + MM_ROOT: ../.. + RTPP_BRANCH: DOCKER + RTPPC_TYPE: rtp.io + RTPPROXY_DIST: ../../dist/rtpproxy + run: | + export CC="${COMPILER}" + cd dist/rtpproxy + ./configure + cd ../../dist/voiptests + python -m pip install -r requirements.txt + DEBIAN_FRONTEND=noninteractive apt-get install -y gpp + sh -x ./test_run.sh + + - name: Pass Environment + id: set_outputs + run: | + echo "LLVM_VER=${LLVM_VER}" >> $GITHUB_OUTPUT + echo "LLVM_VER_OLD=${LLVM_VER_OLD}" >> $GITHUB_OUTPUT + GHCR_REPO="ghcr.io/${{ github.repository_owner }}/opensips" + echo "GHCR_REPO=${GHCR_REPO}" | tr '[:upper:]' '[:lower:]' >> $GITHUB_OUTPUT + + build_test_rtp_io_dock: + name: Build & Test OpenSIPS+rtp.io + needs: build_test_rtp_io_quick + uses: ./.github/workflows/.rtp.io.yml + with: + rtpp-tag: ${{ matrix.rtpp-tag }} + llvm-version: ${{ needs.build_test_rtp_io_quick.outputs.llvm_ver }} + llvm-version-old: ${{ needs.build_test_rtp_io_quick.outputs.llvm_ver_old }} + ghcr-repo: ${{ needs.build_test_rtp_io_quick.outputs.ghcr-repo }} + strategy: + fail-fast: false + matrix: + rtpp-tag: [debian_12-slim, ubuntu_latest] diff --git a/Makefile.conf.template b/Makefile.conf.template index 83765830130..04260d2df1b 100644 --- a/Makefile.conf.template +++ b/Makefile.conf.template @@ -71,7 +71,18 @@ #xmpp= Gateway between OpenSIPS and a jabber server. It enables the exchange of IMs between SIP clients and XMPP(jabber) clients. | parsing/building XML files, typically libexpat1-devel #uuid= UUID generator | uuid-dev -exclude_modules?= aaa_diameter aaa_radius auth_jwt b2b_logic_xml cachedb_cassandra cachedb_couchbase cachedb_dynamodb cachedb_memcached cachedb_mongodb cachedb_redis carrierroute cgrates compression cpl_c db_berkeley db_http db_mysql db_oracle db_perlvdb db_postgres db_sqlite db_unixodbc dialplan emergency event_rabbitmq event_kafka event_sqs h350 httpd http2d identity jabber json launch_darkly ldap lua mi_xmlrpc_ng mmgeoip osp perl pi_http presence presence_dialoginfo presence_mwi presence_reginfo presence_xml presence_dfks proto_ipsec proto_sctp proto_tls proto_wss pua pua_bla pua_dialoginfo pua_mi pua_reginfo pua_usrloc pua_xmpp python regex rabbitmq_consumer rest_client rls siprec sngtc snmpstats stir_shaken tls_mgm tls_openssl tls_wolfssl uuid xcap xcap_client xml xmpp +exclude_modules?= aaa_diameter aaa_radius auth_jwt b2b_logic_xml \ + cachedb_cassandra cachedb_couchbase cachedb_dynamodb cachedb_memcached \ + cachedb_mongodb cachedb_redis carrierroute cgrates compression cpl_c \ + db_berkeley db_http db_mysql db_oracle db_perlvdb db_postgres db_sqlite \ + db_unixodbc dialplan emergency event_rabbitmq event_kafka event_sqs h350 \ + httpd http2d identity jabber json launch_darkly ldap lua mi_xmlrpc_ng \ + mmgeoip osp perl pi_http presence presence_dialoginfo presence_mwi \ + presence_reginfo presence_xml presence_dfks proto_ipsec proto_sctp proto_tls \ + proto_wss pua pua_bla pua_dialoginfo pua_mi pua_reginfo pua_usrloc pua_xmpp \ + python regex rabbitmq_consumer rest_client rls siprec sngtc snmpstats \ + stir_shaken tls_mgm tls_openssl tls_wolfssl uuid xcap xcap_client xml \ + xmpp rtp.io include_modules?= diff --git a/docker/Dockerfile.rtp.io b/docker/Dockerfile.rtp.io new file mode 100644 index 00000000000..8debfe6b90f --- /dev/null +++ b/docker/Dockerfile.rtp.io @@ -0,0 +1,57 @@ +# syntax=docker/dockerfile:1.7-labs + +ARG BASE_IMAGE="sippylabs/rtpproxy:latest" +FROM --platform=$TARGETPLATFORM $BASE_IMAGE AS build +LABEL maintainer="Maksym Sobolyev " + +USER root + +# Set Environment Variables +ENV DEBIAN_FRONTEND=noninteractive + +WORKDIR /src + +ARG LLVM_VER=18 +ARG LLVM_VER_OLD=16 +ARG TARGETPLATFORM +ARG BUILD_OS=ubuntu-latest +RUN --mount=type=bind,source=scripts/build,target=scripts/build \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + env `./scripts/build/get-arch-buildargs.rtp.io platformopts` \ + sh -x scripts/build/install_depends.sh && \ + eval `./scripts/build/get-arch-buildargs.rtp.io platformopts` && \ + apt-get install -y libsrtp2-dev ${LINKER} +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + apt-get install -y gpp python-is-python3 python3-pip +RUN --mount=type=bind,source=dist/voiptests/requirements.txt,target=requirements.txt \ + --mount=type=cache,target=/root/.cache/pip,sharing=locked \ + python -m pip install --break-system-packages -U -r requirements.txt + +COPY --exclude=.git --exclude=.github --exclude=docker --exclude=dist \ + . . + +ARG KEEP_MODULES="dialog sipmsgops sl tm rr maxfwd rtp.io rtpproxy textops" +ARG SKIP_MODULES="usrloc event_routing clusterer rtp_relay" +RUN mkdir tmp && cd modules && mv ${KEEP_MODULES} ${SKIP_MODULES} ../tmp && \ + rm -rf * && cd ../tmp && mv ${KEEP_MODULES} ${SKIP_MODULES} ../modules && \ + cd .. && rmdir tmp +RUN EXCLUDE_MODULES_ADD="${SKIP_MODULES}" \ + env `./scripts/build/get-arch-buildargs.rtp.io platformopts` \ + sh -x scripts/build/do_build.sh +RUN env ONE_MODULE=rtp.io LDFLAGS="-flto -fuse-ld=lld" CFLAGS=-flto \ + env `./scripts/build/get-arch-buildargs.rtp.io platformopts` \ + sh -x scripts/build/do_build.sh +COPY --exclude=.git --exclude=.github dist/rtpproxy dist/rtpproxy +RUN eval `./scripts/build/get-arch-buildargs.rtp.io platformopts` && \ + cd dist/rtpproxy && CC="${COMPILER}" ./configure + +COPY --exclude=.git --exclude=.github dist/voiptests dist/voiptests + +ENV MM_TYPE=opensips +ENV MM_BRANCH=master +ENV MM_ROOT=../.. +ENV RTPP_BRANCH=DOCKER +ENV RTPPC_TYPE=rtp.io +ENV RTPPROXY_DIST=../../dist/rtpproxy +WORKDIR dist/voiptests +ENTRYPOINT [ "sh", "-x", "./test_run.sh" ] diff --git a/modules/rtp.io/Makefile b/modules/rtp.io/Makefile new file mode 100644 index 00000000000..5b8b8f9f008 --- /dev/null +++ b/modules/rtp.io/Makefile @@ -0,0 +1,12 @@ +# rtp.io module makefile + +include ../../Makefile.defs + +auto_gen= +NAME=rtp.io.so + +DEFS+=-I$(LOCALBASE)/include +LIBS += -Wl,--whole-archive $(LOCALBASE)/lib/librtpproxy.a -Wl,--no-whole-archive \ + -lm -lssl -lcrypto `pkg-config --libs --static libsrtp2` + +include ../../Makefile.modules diff --git a/modules/rtp.io/doc/contributors.xml b/modules/rtp.io/doc/contributors.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/rtp.io/doc/rtp.io.xml b/modules/rtp.io/doc/rtp.io.xml new file mode 100644 index 00000000000..63f10a0d03b --- /dev/null +++ b/modules/rtp.io/doc/rtp.io.xml @@ -0,0 +1,29 @@ + + + + + + + +%docentities; + +]> + + + + RTP.io Module + &osipsname; + + + + &admin; + &faq; + &contrib; + + &docCopyrights; + ©right; 2023 Sippy Software, Inc. + diff --git a/modules/rtp.io/doc/rtp.io_admin.xml b/modules/rtp.io/doc/rtp.io_admin.xml new file mode 100644 index 00000000000..37e678046b7 --- /dev/null +++ b/modules/rtp.io/doc/rtp.io_admin.xml @@ -0,0 +1,72 @@ + + + + &adminguide; + +
+ Overview + + The RTP.io module provides an integrated solution + for handling RTP traffic within &osips;, enabling RTP relaying and + processing directly inside the OpenSIPS process. This eliminates the + need for external processes such as RTPProxy, resulting in a more + streamlined, efficient, and manageable system for certain use cases. + + + The rtp.io module starts RTP handling threads in the main + OpenSIPS process and allows the rtpproxy module to access these + threads via a one-to-one socket pair. This tight integration facilitates efficient + RTP traffic management within OpenSIPS without relying on external RTP handling + services. + + + The module requires RTPProxy version 3.1 or higher, compiled + with the option to build. It utilizes the + librtpproxy library to manage RTP traffic and interfaces with the + existing rtpproxy module to generate commands, parse responses, + and process SIP messages. + + + When the rtpproxy module is loaded without arguments and the + rtp.io module is also loaded, the sockets exported by + rtp.io are used automatically in set 0. + Alternatively, these sockets can be incorporated into other sets by using the + "rtp.io:auto" moniker. + +
+ +
+ Dependencies + +
+ +
+ Exported Parameters +
+ <varname>rtpproxy_args</varname>(string) + + Command-line parameteres passed down to the embedded RTPProxy + module upon initialization. Refer to the RTPProxy + documentation for the full list. + + + + Parameter has no default value. + + + + Set <varname>rtpproxy_args</varname> parameter + +... +modparam("rtp.io", "rtpproxy_args", "-m 12000 -M 15000 -l 0.0.0.0 -6 /::") +... + + +
+
+ +
+ Exported Functions + +
+
diff --git a/modules/rtp.io/rtp_io.c b/modules/rtp.io/rtp_io.c new file mode 100644 index 00000000000..e2510983d7b --- /dev/null +++ b/modules/rtp.io/rtp_io.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2023 Sippy Software, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips 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 + * + * opensips 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 +#include +#include + +#include "../../sr_module.h" +#include "../../mod_fix.h" +#include "../../pt.h" +#include "../../dprint.h" +#include "../../timer.h" + +#include "rtp_io.h" +#include "rtp_io_util.h" +#include "rtp_io_params.h" +#include "rtp_io_host.h" + +static int mod_init(void); +static int child_init(int rank); +static void mod_destroy(void); + +static const dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "rtpproxy", DEP_SILENT|DEP_REVERSE }, + { MOD_TYPE_NULL, NULL, 0 }, + }, +}; + +static int rtp_io_getchildsock(int); + +/* + * Exported functions + */ +static const cmd_export_t cmds[] = { + {"rtp_io_getchildsock", (cmd_function)rtp_io_getchildsock, {0}, 0}, + {0} +}; + +/* + * Exported params + */ +static const param_export_t params[] = { + {"rtpproxy_args", STR_PARAM|USE_FUNC_PARAM, (void*)rio_set_rtpp_args}, + {0} +}; + +static const proc_export_t procs[] = { + {.name = "RTPProxy host process", .function = rtpproxy_host_process, + .no = 1, .flags = PROC_FLAG_HAS_IPC, + .post_fork_function = rtp_io_close_serv_socks}, + {0} +}; + +struct module_exports exports= { + "rtp.io", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, /* dlopen flags */ + 0, /* load function */ + &deps, /* OpenSIPS module dependencies */ + cmds, /* exported functions */ + 0, /* exported async functions */ + params, /* param exports */ + 0, /* exported statistics */ + 0, /* exported MI functions */ + NULL, /* exported pseudo-variables */ + 0, /* exported transformations */ + procs, /* extra processes */ + 0, /* module pre-initialization function */ + mod_init, /* module initialization function */ + 0, /* reply processing function */ + mod_destroy, + child_init, /* per-child init function */ + 0 +}; + +#define howmany(x, y) (sizeof(x) / sizeof(y)) + +static struct rtpp_env argv0 = {.cp = "rtpproxy"}; + +static struct rtp_io_desc rpi_desc = { + .env = {.len = 1, .first = &argv0, .last = &argv0}, +}; + +struct rtp_io_desc *rpi_descp = &rpi_desc; + +#define ENV_ADD(x, elabel, ...) { \ + struct rtpp_env *_e = rtp_io_env_asprintf((x), ##__VA_ARGS__); \ + if (_e == NULL) \ + goto elabel; \ + rtp_io_env_append(&rpi_descp->env, _e); \ +} + +static int +rio_socks_init(int nsocks) +{ + size_t asize; + struct rtp_io_socks *socks; + + LM_DBG("allocating %s(%d)\n", exports.name, nsocks); + + asize = sizeof(struct rtp_io_socks) + (nsocks * sizeof(int) * 2); + socks = malloc(asize); + if (socks == NULL) + goto e0; + + memset(socks, '\0', asize); + rpi_descp->socks = socks; + return 0; +e0: + return -1; +} + +static int mod_init(void) +{ + int nsocks; + const char * const argv_stat[] = { + "-d", "err", + "-n", "tcp:127.0.0.1:9642", + "--dso", "catch_dtmf", + "--dso", "dtls_gw", + "--dso", "ice_lite", + }; + + unsigned int extra = 0; + nsocks = count_child_processes() - count_module_procs(0) - timer_count_processes(&extra); + nsocks -= extra; + + if (nsocks <= 1) + goto e0; + + LM_DBG("initializing %s(%d)\n", exports.name, nsocks); + + if (rio_socks_init(nsocks) != 0) + goto e0; + if (init_rtpp_host() != 0) + goto e1; + + for (int i = 0; i < howmany(argv_stat, *argv_stat); i++) { + ENV_ADD(argv_stat[i], e1); + } + + for (int i = 0; i < nsocks; i++) { + int *fdp = &rpi_descp->socks->holder[i * 2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdp) < 0) + goto e1; + ENV_ADD("-s", e1); + ENV_ADD("fd:%d", e1, fdp[0]); + } + + rpi_descp->socks->n = nsocks; + + return 0; +e1: + free(rpi_descp->socks); +e0: + return -1; +} + +void mod_destroy(void) +{ + struct rtpp_env *enext; + + LM_DBG("cleaning up %s...\n", exports.name); + if (rtpp_host_process_no != NULL && *rtpp_host_process_no != 0) { + if (ipc_send_rpc(*rtpp_host_process_no, ipc_shutdown_rtpp_host, NULL) != 0) + LM_ERR("could not send shutdown request to the RTPProxy host process!\n"); + } + for (const struct rtpp_env *e = rpi_descp->env.first; e != NULL; e = enext) { + enext = e->next; + if (e->atype == env_heap) + free(e->_cp); + if (e == &argv0) + continue; + free((void *)e); + } + rtp_io_close_serv_socks(); + rtp_io_close_cnlt_socks(); + free(rpi_descp->socks); +} + +#include + +static int +child_init(int rank) +{ + if (rank > rpi_descp->socks->n) { + LM_ERR("BUG: rank is higher than the number of sockets!\n"); + return -1; + } + + if (rank <= 0) { + if (rtp_io_close_cnlt_socks() != 0) { + LM_ERR("rtp_io_close_cnlt_socks() failed\n"); + return -1; + } + return 0; + } + + for (int i = 0; i < rpi_descp->socks->n; i++) { + if (i == rank - 1) + continue; + int *fdp = &rpi_descp->socks->holder[i * 2]; + if (close(fdp[1]) < 0) + return (-1); + fdp[1] = -1; + } + + return (0); +} + +static int rtp_io_getchildsock(int rank) +{ + + if (rank < 1 || rank > rpi_descp->socks->n) + return (-1); + + int *fdp = &rpi_descp->socks->holder[(rank - 1) * 2]; + return (fdp[1]); +} diff --git a/modules/rtp.io/rtp_io.h b/modules/rtp.io/rtp_io.h new file mode 100644 index 00000000000..3990cdbe655 --- /dev/null +++ b/modules/rtp.io/rtp_io.h @@ -0,0 +1,34 @@ +#pragma once + +struct rtpp_cfg; + +struct rtpp_env { + union { + const char *cp; + char *_cp; + }; + enum {env_static=0, env_heap=1} atype; + struct rtpp_env *next; +}; + +struct rtpp_env_hd { + int len; + const struct rtpp_env *first; + union { + const struct rtpp_env *last; + struct rtpp_env *_last; + }; +}; + +struct rtp_io_socks { + int n; + int holder[]; +}; + +struct rtp_io_desc { + struct rtpp_cfg *rtpp_cfsp; + struct rtpp_env_hd env; + struct rtp_io_socks *socks; +}; + +extern struct rtp_io_desc *rpi_descp; diff --git a/modules/rtp.io/rtp_io_api.h b/modules/rtp.io/rtp_io_api.h new file mode 100644 index 00000000000..c09bf127e69 --- /dev/null +++ b/modules/rtp.io/rtp_io_api.h @@ -0,0 +1,3 @@ +#pragma once + +typedef int (*rtp_io_getchildsock_t)(int); diff --git a/modules/rtp.io/rtp_io_host.c b/modules/rtp.io/rtp_io_host.c new file mode 100644 index 00000000000..a5eddd49fd9 --- /dev/null +++ b/modules/rtp.io/rtp_io_host.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023-2025 Sippy Software, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips 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 + * + * opensips 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 "../../sr_module.h" +#include "../../reactor_defs.h" +#include "../../reactor_proc.h" + +#include "librtpproxy.h" + +#include "rtp_io.h" +#include "rtp_io_host.h" +#include "rtp_io_util.h" + +#if defined(__linux__) +static int optreset; /* Not present in linux */ +#endif + +static struct opt_save { + char *optarg; + int optind; + int optopt; + int opterr; + int optreset; +} opt_save = {.optind = 1}; + +#define OPT_SAVE() (opt_save = (struct opt_save){optarg, optind, optopt, opterr, optreset}) +#define OPT_RESTORE() ({ \ + optarg = opt_save.optarg; \ + optind = opt_save.optind; \ + optopt = opt_save.optopt; \ + opterr = opt_save.opterr; \ + optreset = opt_save.optreset; \ +}) + +int *rtpp_host_process_no; + +int init_rtpp_host(void) +{ + rtpp_host_process_no = shm_malloc(sizeof *rtpp_host_process_no); + if (!rtpp_host_process_no) { + LM_ERR("cannot allocate space for rtpp host process number\n"); + return -1; + } + *rtpp_host_process_no = 0; + + return 0; +} + +void rtpproxy_host_process(int rank) +{ + int argc; + const char *const *argv = rtp_io_env_gen_argv(&rpi_descp->env, &argc); + if (argv == NULL) + goto e1; + if (rtp_io_close_cnlt_socks() != 0) + goto e1; + + OPT_RESTORE(); + rpi_descp->rtpp_cfsp = rtpp_main(argc, argv); + free((void *)argv); + if (rpi_descp->rtpp_cfsp == NULL) + goto e1; + + if (reactor_proc_init("rtp.io events") < 0) { + LM_ERR("failed to init the rtp.io events\n"); + goto e1; + } + + *rtpp_host_process_no = process_no; + reactor_proc_loop(); + return; +e1: + abort(); +} + +void +ipc_shutdown_rtpp_host(int sender, void *param) +{ + + LM_DBG("shutting down rtpproxy host...\n"); + rtpp_shutdown(rpi_descp->rtpp_cfsp); + for (int i = 0; i < (rpi_descp->socks->n * 2); i++) { + if (rpi_descp->socks->holder[i] != -1) + close(rpi_descp->socks->holder[i]); + } + free(rpi_descp->socks); +} diff --git a/modules/rtp.io/rtp_io_host.h b/modules/rtp.io/rtp_io_host.h new file mode 100644 index 00000000000..2c23ba1cafd --- /dev/null +++ b/modules/rtp.io/rtp_io_host.h @@ -0,0 +1,7 @@ +#pragma once + +extern int *rtpp_host_process_no; + +int init_rtpp_host(void); +void rtpproxy_host_process(int); +void ipc_shutdown_rtpp_host(int, void *); diff --git a/modules/rtp.io/rtp_io_params.c b/modules/rtp.io/rtp_io_params.c new file mode 100644 index 00000000000..ca75c8eeef4 --- /dev/null +++ b/modules/rtp.io/rtp_io_params.c @@ -0,0 +1,38 @@ +#include +#include + +#include "../../sr_module.h" + +#include "rtp_io.h" +#include "rtp_io_util.h" +#include "rtp_io_params.h" + +int +rio_set_rtpp_args(modparam_t type, void *val) +{ + char * p; + + p = (char *)val; + + + if (p == NULL || *p == '\0') { + return 0; + } + do { + char *ep = strchr(p, ' '); + if (ep != NULL) { + *ep = '\0'; + } + struct rtpp_env *rep = rtp_io_env_strref(p); + if (rep == NULL) { + return -1; + } + rtp_io_env_append(&rpi_descp->env, rep); + if (ep == NULL) + break; + p = ep + 1; + while (isspace(*p)) + p++; + } while (*p != '\0'); + return 0; +} diff --git a/modules/rtp.io/rtp_io_params.h b/modules/rtp.io/rtp_io_params.h new file mode 100644 index 00000000000..57c273e7813 --- /dev/null +++ b/modules/rtp.io/rtp_io_params.h @@ -0,0 +1,3 @@ +#pragma once + +int rio_set_rtpp_args(modparam_t, void *); diff --git a/modules/rtp.io/rtp_io_util.c b/modules/rtp.io/rtp_io_util.c new file mode 100644 index 00000000000..a04c3697696 --- /dev/null +++ b/modules/rtp.io/rtp_io_util.c @@ -0,0 +1,105 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "../../dprint.h" + +#include "rtp_io.h" +#include "rtp_io_util.h" + +struct rtpp_env * +rtp_io_env_asprintf(const char *format, ...) +{ + va_list ap; + int rc; + char *cp; + + va_start(ap, format); + rc = vasprintf(&cp, format, ap); + va_end(ap); + if (rc < 0) + goto e0; + struct rtpp_env *rep = rtp_io_env_strref(cp); + if (rep != NULL) { + rep->atype = env_heap; + } else { + free(cp); + } + return rep; +e0: + return (NULL); +} + +struct rtpp_env * +rtp_io_env_strref(const char *cp) +{ + struct rtpp_env *rep; + + rep = malloc(sizeof(struct rtpp_env)); + if (rep == NULL) + goto e0; + memset(rep, '\0', sizeof(struct rtpp_env)); + rep->cp = cp; + return (rep); +e0: + return (NULL); +} + +void +rtp_io_env_append(struct rtpp_env_hd *ecp, struct rtpp_env *ep) +{ + if (ecp->first == NULL) { + ecp->last = ecp->first = ep; + } else { + ecp->_last->next = ep; + ecp->last = ep; + } + ecp->len += 1; +} + +const char *const * +rtp_io_env_gen_argv(struct rtpp_env_hd *ecp, int *lenp) +{ + const char **rval; + const struct rtpp_env *ep; + + size_t asize = ecp->len * sizeof(rval[0]); + rval = malloc(asize); + if (rval == NULL) + return (NULL); + memset(rval, '\0', asize); + ep = ecp->first; + for (int i = 0; i < ecp->len; i++) { + rval[i] = ep->cp; + ep = ep->next; + } + *lenp = ecp->len; + return (const char *const *)rval; +} + +int rtp_io_close_serv_socks(void) +{ + + for (int i = 0; i < (rpi_descp->socks->n * 2); i+=2) { + if (rpi_descp->socks->holder[i] != -1) { + close(rpi_descp->socks->holder[i]); + rpi_descp->socks->holder[i] = -1; + } + } + return (0); +} + +int rtp_io_close_cnlt_socks(void) +{ + + for (int i = 0; i < (rpi_descp->socks->n * 2); i+=2) { + if (rpi_descp->socks->holder[i+1] != -1) { + close(rpi_descp->socks->holder[i+1]); + rpi_descp->socks->holder[i+1] = -1; + } + } + return (0); +} diff --git a/modules/rtp.io/rtp_io_util.h b/modules/rtp.io/rtp_io_util.h new file mode 100644 index 00000000000..6dc0cddaaa8 --- /dev/null +++ b/modules/rtp.io/rtp_io_util.h @@ -0,0 +1,13 @@ +#pragma once + +struct rtpp_env; +struct rtpp_env_hd; + +struct rtpp_env *rtp_io_env_asprintf(const char *, ...); +struct rtpp_env *rtp_io_env_strref(const char *); + +void rtp_io_env_append(struct rtpp_env_hd *, struct rtpp_env *); +const char *const * rtp_io_env_gen_argv(struct rtpp_env_hd *, int *); + +int rtp_io_close_serv_socks(void); +int rtp_io_close_cnlt_socks(void); diff --git a/scripts/build/do_build.sh b/scripts/build/do_build.sh index b5f2b103f88..a102da8b5bb 100755 --- a/scripts/build/do_build.sh +++ b/scripts/build/do_build.sh @@ -8,11 +8,20 @@ set -e EXCLUDE_MODULES="db_oracle osp sngtc cachedb_cassandra cachedb_couchbase \ cachedb_mongodb auth_jwt event_kafka aaa_diameter launch_darkly http2d \ - snmpstats cachedb_dynamodb event_sqs" + snmpstats cachedb_dynamodb event_sqs rtp.io" if [ ! -z "${EXCLUDE_MODULES_ADD}" ] then EXCLUDE_MODULES="${EXCLUDE_MODULES} ${EXCLUDE_MODULES_ADD}" fi -CC_EXTRA_OPTS=${CC_EXTRA_OPTS:-"-Werror"} FASTER=1 NICER=0 make \ - exclude_modules="${EXCLUDE_MODULES}" "${@}" ${MAKE_TGT:-"all"} +MAKE_ENV="FASTER=1 NICER=0" +MAKE_CMD="${MAKE_ENV} make" + +if [ ! -z "${ONE_MODULE}" ] +then + env CC_EXTRA_OPTS="${CC_EXTRA_OPTS:-"-Werror"}" ${MAKE_CMD} \ + -C "modules/${ONE_MODULE}" +else + env CC_EXTRA_OPTS="${CC_EXTRA_OPTS:-"-Werror"}" ${MAKE_CMD} \ + exclude_modules="${EXCLUDE_MODULES}" "${@}" ${MAKE_TGT:-"all"} +fi diff --git a/scripts/build/get-arch-buildargs.rtp.io b/scripts/build/get-arch-buildargs.rtp.io new file mode 100755 index 00000000000..0268319a4f9 --- /dev/null +++ b/scripts/build/get-arch-buildargs.rtp.io @@ -0,0 +1,67 @@ +#!/bin/sh + +set -e + +isbrokenplatform() { + case "${BUILD_OS}" in + debian*) + case "${TARGETPLATFORM}" in + linux/386 | linux/arm/v7 | linux/mips64le | linux/ppc64le | linux/s390x) + exit 1 + ;; + esac + ;; + ubuntu*) + case "${TARGETPLATFORM}" in + linux/arm/v7 | linux/ppc64le | linux/s390x | linux/arm64) + exit 1 + ;; + esac + ;; + esac + exit 0 +} + +fltplatforms() { + case "${BUILD_OS}" in + debian*) + FILT="grep -v -e ^linux/arm/v5\$" # broken 64-bit stdatomics + ;; + *) + FILT="cat" + ;; + esac + ${FILT} +} + +platformopts() { + out="COMPILER=clang-${LLVM_VER} LINKER=lld-${LLVM_VER}" + case "${BUILD_OS}" in + debian*) + case "${TARGETPLATFORM}" in + linux/ppc64le | linux/arm/v7 | linux/mips64le | linux/arm/v5) + out="COMPILER=clang-${LLVM_VER_OLD} LINKER=lld-${LLVM_VER_OLD}" + ;; + esac + ;; + esac + echo "${out}" + echo "${@}" +} + +case "${1}" in +platformopts) + shift + platformopts "${@}" + ;; +fltplatforms) + fltplatforms + ;; +isbrokenplatform) + isbrokenplatform + ;; +*) + echo "usage: `basename "${0}"` (platformopts|fltplatforms) [opts]" 2>&1 + exit 1 + ;; +esac From 090d346d90fdd52c071186b01ac5634157b085c9 Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Tue, 16 May 2023 14:34:10 -0700 Subject: [PATCH 2/7] rtpproxy: hook up rtpproxy into rtp.io. Use rtp.io when no explicit rtpproxy configuration is provided. It is also possible to mix internal RTP functionality with externals proxies by adding it up as "rtp.io:auto" into some of the existing set. --- modules/rtpproxy/rtppn_connect.c | 2 + modules/rtpproxy/rtpproxy.c | 101 ++++++++++++++++++++++--------- modules/rtpproxy/rtpproxy.h | 5 +- 3 files changed, 79 insertions(+), 29 deletions(-) diff --git a/modules/rtpproxy/rtppn_connect.c b/modules/rtpproxy/rtppn_connect.c index aed2cb5eddd..13724fdf4ff 100644 --- a/modules/rtpproxy/rtppn_connect.c +++ b/modules/rtpproxy/rtppn_connect.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,7 @@ int connect_rtpp_node(struct rtpp_node *pnode) struct addrinfo hints, *res; struct sockaddr_un sau; + assert(pnode->rn_umode != CM_RTPIO); /* * This is UDP, TCP, UDP6 or TCP6. Detect host and port; lookup host; * do connect() in order to specify peer address diff --git a/modules/rtpproxy/rtpproxy.c b/modules/rtpproxy/rtpproxy.c index 902b54d3b97..69d1166d7ea 100644 --- a/modules/rtpproxy/rtpproxy.c +++ b/modules/rtpproxy/rtpproxy.c @@ -188,6 +188,8 @@ #include "rtpproxy_vcmd.h" #include "rtppn_connect.h" #include "../rtp_relay/rtp_relay.h" +#include "../rtp.io/rtp_io_api.h" + #define NH_TABLE_VERSION 0 #define DEFAULT_RTPP_SET_ID 0 @@ -368,6 +370,7 @@ static int rtpproxy_autobridge = 0; static pid_t mypid; static int myrand = 0; static unsigned int myseqn = 0; +static int myrank = 0; static str nortpproxy_str = str_init("a=nortpproxy:yes"); str rtpp_notify_socket = {0, 0}; /* @@ -385,8 +388,13 @@ struct rtpp_set_head ** rtpp_set_list =0; struct rtpp_set ** default_rtpp_set=0; static int default_rtpp_set_no = DEFAULT_RTPP_SET_ID; +struct rtpp_sock { + int fd; + enum comm_modes rn_umode; +}; + /* array with the sockets used by rtpporxy (per process)*/ -static int *rtpp_socks = 0; +static struct rtpp_sock *rtpp_socks = NULL; static unsigned int *rtpp_no = 0; static unsigned int *list_version; static unsigned int my_version = 0; @@ -641,8 +649,7 @@ static int rtpproxy_set_notify(modparam_t type, void * val) return 0; } -static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, - char * rtpproxy){ +static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, char *rtpproxy){ /* Make rtp proxies list. */ char *p, *p1, *p2, *p3, *p4, *plim; struct rtpp_node *pnode; @@ -726,6 +733,13 @@ static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, } else if (strncasecmp(pnode->rn_address, "cunix:", 6) == 0) { pnode->rn_umode = CM_CUNIX; pnode->rn_address += 6; + } else if (strncasecmp(pnode->rn_address, "rtp.io:auto", 11) == 0) { + if (pnode->rn_address[11] != '\0') { + LM_ERR("only \"rtp.io:auto\" is supported\n"); + return -1; + } + pnode->rn_umode = CM_RTPIO; + pnode->rn_address += 11; } if (rtpp_list->rn_first == NULL) { @@ -1131,6 +1145,16 @@ static int mod_preinit(void) return 0; } +static rtp_io_getchildsock_t +rtp_io_childsock_f(void) +{ + static rtp_io_getchildsock_t _rtp_io_getchildsock = {0}; + + if (_rtp_io_getchildsock == NULL) + _rtp_io_getchildsock = (rtp_io_getchildsock_t)find_export("rtp_io_getchildsock", 0); + return _rtp_io_getchildsock; +} + static int mod_init(void) { @@ -1181,8 +1205,11 @@ mod_init(void) if(db_url.s == NULL) { if (rtpp_sets == 0) { - LM_ERR("no rtpproxy set specified\n"); - return -1; + int rtp_io_found = (rtp_io_childsock_f() == NULL) ? 0 : 1; + if (!rtp_io_found || rtpproxy_add_rtpproxy_set("rtp.io:auto", -1) != 0) { + LM_ERR("no rtpproxy set specified"); + return -1; + } } /* storing the list of rtp proxy sets in shared memory*/ @@ -1370,7 +1397,7 @@ mod_init(void) static int mi_child_init(void) { - if(child_init(1) < 0) + if (child_init(1) < 0) { LM_ERR("Failed to initial rtpp socks\n"); return -1; @@ -1480,6 +1507,7 @@ child_init(int rank) mypid = getpid(); myrand = rand()%10000; + myrank = rank; return connect_rtpproxies(NULL); } @@ -1495,7 +1523,8 @@ int connect_rtpproxies(struct rtpp_set *filter) LM_DBG("[Re]connecting sockets (%d > %d)\n", *rtpp_no, rtpp_number); if (*rtpp_no > rtpp_number) { - rtpp_socks = (int*)pkg_realloc(rtpp_socks, *rtpp_no * sizeof(int) ); + size_t asize = *rtpp_no * sizeof(rtpp_socks[0]); + rtpp_socks = (typeof(rtpp_socks))pkg_realloc(rtpp_socks, asize); if (rtpp_socks==NULL) { LM_ERR("no more pkg memory\n"); return -1; @@ -1510,16 +1539,31 @@ int connect_rtpproxies(struct rtpp_set *filter) continue; for (pnode=rtpp_list->rn_first; pnode!=0; pnode = pnode->rn_next){ - if (pnode->rn_umode == CM_UNIX) { - rtpp_socks[pnode->idx] = -1; - } else { - rtpp_socks[pnode->idx] = connect_rtpp_node(pnode); - LM_INFO("created to %d\n", rtpp_socks[pnode->idx]); - if (rtpp_socks[pnode->idx] == -1) { + switch (pnode->rn_umode) { + case CM_UNIX: + rtpp_socks[pnode->idx].fd = -1; + break; + case CM_RTPIO: + { + rtp_io_getchildsock_t gcs_f; + gcs_f = rtp_io_childsock_f(); + if (gcs_f == NULL) { + LM_ERR("rtp.io is not loaded\n"); + return -1; + } + rtpp_socks[pnode->idx].fd = gcs_f(myrank); + } + break; + default: + rtpp_socks[pnode->idx].fd = connect_rtpp_node(pnode); + LM_INFO("created to %d\n", rtpp_socks[pnode->idx].fd); + if (rtpp_socks[pnode->idx].fd == -1) { LM_ERR("connect_rtpp_node() failed\n"); return -1; } + break; } + rtpp_socks[pnode->idx].rn_umode = pnode->rn_umode; pnode->rn_disabled = rtpp_test(pnode, 0, 1); } @@ -1549,13 +1593,15 @@ int update_rtpp_proxies(struct rtpp_set *filter) { update_rtpp_notify(); for (i = 0; i < rtpp_number; i++) { + if (rtpp_socks[i].rn_umode == CM_RTPIO) + continue; if (!filter || (filter->rtpp_socks_idx <= i && i < filter->rtpp_socks_idx + filter->rtpp_node_count)) { - LM_DBG("closing rtpp_socks[%d] | filter_set: %d\n", i, + LM_DBG("closing rtpp_socks[%d].fd | filter_set: %d\n", i, filter ? filter->id_set : -1); - shutdown(rtpp_socks[i], SHUT_RDWR); - close(rtpp_socks[i]); + shutdown(rtpp_socks[i].fd, SHUT_RDWR); + close(rtpp_socks[i].fd); } } @@ -2135,9 +2181,10 @@ send_rtpp_command(struct rtpp_node *node, struct rtpproxy_vcmd *vcmd, int vcnt) max_vcnt = IOV_MAX; #endif - if (rtpp_socks[node->idx] == -1 && node->rn_umode != CM_UNIX) { - rtpp_socks[node->idx] = connect_rtpp_node(node); - if (rtpp_socks[node->idx] == -1) { + if (rtpp_socks[node->idx].fd == -1 && node->rn_umode != CM_UNIX && + node->rn_umode != CM_RTPIO) { + rtpp_socks[node->idx].fd = connect_rtpp_node(node); + if (rtpp_socks[node->idx].fd == -1) { LM_ERR("connect_rtpp_node() failed\n"); return (NULL); } @@ -2218,18 +2265,18 @@ send_rtpp_command(struct rtpp_node *node, struct rtpproxy_vcmd *vcmd, int vcnt) } } else { int rtry = CM_STREAM(node) ? 1 : rtpproxy_retr; - fds[0].fd = rtpp_socks[node->idx]; + fds[0].fd = rtpp_socks[node->idx].fd; fds[0].events = POLLIN | POLLRDHUP; fds[0].revents = 0; /* Drain input buffer */ while ((poll(fds, 1, 0) == 1) && ((fds[0].revents & POLLIN) != 0)) { if (fds[0].revents & (POLLERR|POLLNVAL|POLLRDHUP)) { - LM_ERR("error on rtpproxy socket %d!\n", rtpp_socks[node->idx]); + LM_ERR("error on rtpproxy socket %d!\n", rtpp_socks[node->idx].fd); break; } fds[0].revents = 0; - if (recv(rtpp_socks[node->idx], buf, sizeof(buf) - 1, 0) < 0 && + if (recv(rtpp_socks[node->idx].fd, buf, sizeof(buf) - 1, 0) < 0 && errno != EINTR) { LM_ERR("error while draining rtpproxy %d!\n", errno); break; @@ -2245,7 +2292,7 @@ send_rtpp_command(struct rtpp_node *node, struct rtpproxy_vcmd *vcmd, int vcnt) for (i = 0; i < rtry; i++) { int buflen = sizeof(buf)-1; do { - len = writev(rtpp_socks[node->idx], cv, vcnt + 1); + len = writev(rtpp_socks[node->idx].fd, cv, vcnt + 1); } while (len == -1 && (errno == EINTR || errno == ENOBUFS)); if (len <= 0) { LM_ERR("can't send (#%d iovec buffers) command to a RTP proxy (%d:%s)\n", @@ -2257,7 +2304,7 @@ send_rtpp_command(struct rtpp_node *node, struct rtpproxy_vcmd *vcmd, int vcnt) int s_errno; do { - len = recv(rtpp_socks[node->idx], cp, buflen, 0); + len = recv(rtpp_socks[node->idx].fd, cp, buflen, 0); } while (len == -1 && errno == EINTR); s_errno = (len < 0) ? errno : 0; if (len <= 0) { @@ -2306,9 +2353,9 @@ send_rtpp_command(struct rtpp_node *node, struct rtpproxy_vcmd *vcmd, int vcnt) return cp; badproxy: LM_ERR("proxy <%s> does not respond, disable it\n", node->rn_url.s); - if (CM_STREAM(node)) { - close(rtpp_socks[node->idx]); - rtpp_socks[node->idx] = -1; + if (CM_STREAM(node) && node->rn_umode != CM_RTPIO) { + close(rtpp_socks[node->idx].fd); + rtpp_socks[node->idx].fd = -1; } node->rn_disabled = 1; node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout; diff --git a/modules/rtpproxy/rtpproxy.h b/modules/rtpproxy/rtpproxy.h index 53be6cc1a7d..b2e0c6839ab 100644 --- a/modules/rtpproxy/rtpproxy.h +++ b/modules/rtpproxy/rtpproxy.h @@ -41,7 +41,7 @@ struct rtpproxy_vcmd; #define AF_LOCAL AF_UNIX #endif -enum comm_modes {CM_UNIX = 0, CM_CUNIX, CM_UDP, CM_TCP, CM_UDP6, CM_TCP6}; +enum comm_modes {CM_UNIX = 0, CM_CUNIX, CM_RTPIO, CM_UDP, CM_TCP, CM_UDP6, CM_TCP6}; struct rtpp_node { unsigned int idx; /* overall index */ @@ -57,7 +57,8 @@ struct rtpp_node { struct rtpp_node *rn_next; }; -#define CM_STREAM(ndp) ((ndp)->rn_umode == CM_TCP || (ndp)->rn_umode == CM_TCP6 || (ndp)->rn_umode == CM_CUNIX) +#define CM_STREAM(ndp) ((ndp)->rn_umode == CM_TCP || (ndp)->rn_umode == CM_TCP6 || \ + (ndp)->rn_umode == CM_CUNIX || (ndp)->rn_umode == CM_RTPIO) /* Supported version of the RTP proxy command protocol */ #define SUP_CPROTOVER 20040107 From d9587d2b479d8c1a5eaac33fbca8c0185d21034b Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Sat, 15 Jun 2024 23:19:10 -0700 Subject: [PATCH 3/7] core: undo solaris-bs that breaks things on BSDs. --- modules/osp/timeapi.c | 15 ++------------- modules/stir_shaken/stir_shaken.c | 14 +------------- transformations.c | 14 +------------- 3 files changed, 4 insertions(+), 39 deletions(-) diff --git a/modules/osp/timeapi.c b/modules/osp/timeapi.c index 7321030ce03..8739c56acdc 100644 --- a/modules/osp/timeapi.c +++ b/modules/osp/timeapi.c @@ -32,21 +32,10 @@ * 2016-01-25 Time related functions. */ -#define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */ -#define _XOPEN_SOURCE_EXTENDED 1 /* solaris */ - -/** - * * _XOPEN_SOURCE creates conflict in swab definition in Solaris - * */ -#ifdef __OS_solaris - #undef _XOPEN_SOURCE -#endif - +/* make strptime available */ +#define _GNU_SOURCE #include -#undef _XOPEN_SOURCE -#undef _XOPEN_SOURCE_EXTENDED - #include #include #include "../../dprint.h" diff --git a/modules/stir_shaken/stir_shaken.c b/modules/stir_shaken/stir_shaken.c index 779efc4c6b2..5c76d26c02d 100644 --- a/modules/stir_shaken/stir_shaken.c +++ b/modules/stir_shaken/stir_shaken.c @@ -33,22 +33,10 @@ * */ +/* make strptime available */ #define _GNU_SOURCE -#define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */ -#define _XOPEN_SOURCE_EXTENDED 1 /* solaris */ - -/** - * _XOPEN_SOURCE creates conflict in swab definition in Solaris - */ -#ifdef __OS_solaris - #undef _XOPEN_SOURCE -#endif - #include -#undef _XOPEN_SOURCE -#undef _XOPEN_SOURCE_EXTENDED - #include #undef _GNU_SOURCE diff --git a/transformations.c b/transformations.c index 443a8376cc7..68e108de15c 100644 --- a/transformations.c +++ b/transformations.c @@ -23,22 +23,10 @@ * \brief Support for transformations */ +/* make strptime available */ #define _GNU_SOURCE -#define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */ -#define _XOPEN_SOURCE_EXTENDED 1 /* solaris */ - -/** - * _XOPEN_SOURCE creates conflict in swab definition in Solaris - */ -#ifdef __OS_solaris - #undef _XOPEN_SOURCE -#endif - #include -#undef _XOPEN_SOURCE -#undef _XOPEN_SOURCE_EXTENDED - #include #include #include From 0e75fc4fd88b62a982c53a9d3af07fca036c2ce6 Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Sun, 16 Jun 2024 00:43:11 -0700 Subject: [PATCH 4/7] CI: run with clang-18, handle debian. --- .github/workflows/main.yml | 2 ++ scripts/build/do_build.sh | 4 ++-- scripts/build/install_depends.sh | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6b34bcc88fb..d8e12380ec9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,6 +56,8 @@ jobs: compiler: 'clang-16' - os: 24.04 compiler: 'clang-17' + - os: 24.04 + compiler: 'clang-18' # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/scripts/build/do_build.sh b/scripts/build/do_build.sh index a102da8b5bb..425fdba9676 100755 --- a/scripts/build/do_build.sh +++ b/scripts/build/do_build.sh @@ -19,9 +19,9 @@ MAKE_CMD="${MAKE_ENV} make" if [ ! -z "${ONE_MODULE}" ] then - env CC_EXTRA_OPTS="${CC_EXTRA_OPTS:-"-Werror"}" ${MAKE_CMD} \ + env CC_EXTRA_OPTS="${CC_EXTRA_OPTS:-"-Werror -Wno-atomic-alignment"}" ${MAKE_CMD} \ -C "modules/${ONE_MODULE}" else - env CC_EXTRA_OPTS="${CC_EXTRA_OPTS:-"-Werror"}" ${MAKE_CMD} \ + env CC_EXTRA_OPTS="${CC_EXTRA_OPTS:-"-Werror -Wno-atomic-alignment"}" ${MAKE_CMD} \ exclude_modules="${EXCLUDE_MODULES}" "${@}" ${MAKE_TGT:-"all"} fi diff --git a/scripts/build/install_depends.sh b/scripts/build/install_depends.sh index 845e4989d3c..d8b62dfdf2d 100755 --- a/scripts/build/install_depends.sh +++ b/scripts/build/install_depends.sh @@ -15,6 +15,10 @@ do then pkg="python-dev-is-python3" fi + if [ "${BUILD_OS%-*}" = "debian" -a "${pkg}" = libmysqlclient-dev ] + then + pkg="libmariadb-dev" + fi _PKGS="${_PKGS} ${pkg}" done PKGS="${_PKGS}" From 897a1d5973f859603e8e6664967c5ab0a2c1cea2 Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Sat, 5 Oct 2024 11:20:11 -0700 Subject: [PATCH 5/7] core: only generate backtraces if EXTRA_DEBUG is defined. This fixes build on systems that have no backtrace API in the libc (e.g. BSDs). --- io_wait.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/io_wait.h b/io_wait.h index 0d9eee44a99..5231d07fed2 100644 --- a/io_wait.h +++ b/io_wait.h @@ -94,7 +94,9 @@ #ifdef __OS_linux #include /* for GLIBC version testing */ #endif +#ifdef EXTRA_DEBUG #include "lib/dbg/backtrace.h" +#endif #ifndef FD_TYPE_DEFINED typedef int fd_type; @@ -732,13 +734,17 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, if (!(idx>=0 && idxfd_no)) { LM_CRIT("[%s] FD index check failed, idx=%d, max=%d" " operating on %d\n",h->name, idx, h->fd_no, fd ); +#ifdef EXTRA_DEBUG log_backtrace(); +#endif rla_dump(); idx = -1; } else if (h->fd_array[idx].fd!=fd) { LM_CRIT("[%s] FD consistency check failed, idx=%d points to fd=%d," " but operating on %d\n",h->name, idx, h->fd_array[idx].fd, fd ); +#ifdef EXTRA_DEBUG log_backtrace(); +#endif rla_dump(); idx = -1; } From 61fee87492d14cf20791e0ac7903ebc182a7d9d5 Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Mon, 7 Oct 2024 15:32:19 -0700 Subject: [PATCH 6/7] core: Enable clang for ppc64. CI: handle debian. --- Makefile.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.defs b/Makefile.defs index 2bbf6fa78c6..4b3d9ebd6fc 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -1124,7 +1124,7 @@ endif #ARCH, sparc64 #if ipaq/netwinder ifeq ($(ARCH), arm) # if gcc -ifeq ($(CC_NAME), gcc) +ifeq ($(CC_NAME:clang=gcc), gcc) #common stuff CFLAGS+=$(CC_OPTIMIZE_FLAG) -funroll-loops -Wcast-align $(PROFILE) \ -Wall -marm @@ -1298,7 +1298,7 @@ endif #ARCH, ppc #if ppc64 ifeq ($(ARCH), ppc64) # if gcc -ifeq ($(CC_NAME), gcc) +ifeq ($(CC_NAME:clang=gcc), gcc) #common stuff CFLAGS+=$(CC_OPTIMIZE_FLAG) -funroll-loops $(PROFILE) -Wall ifeq ($(CC_CLASS), 4.x) From a947f1d807d31369310adc32d48e27a368145d22 Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Wed, 16 Apr 2025 21:20:46 -0700 Subject: [PATCH 7/7] Remove Ubuntu 20.04 (to be discontinued by the github) and add 24.04. --- .github/workflows/main.yml | 10 +------ .github/workflows/unittests.yml | 48 +++++++++++++-------------------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d8e12380ec9..80d9a836d1f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,17 +27,9 @@ jobs: strategy: fail-fast: false matrix: - os: [20.04, 22.04, 24.04] + os: [22.04, 24.04] compiler: ['gcc', 'clang'] include: - - os: 20.04 - compiler: 'gcc-9' - - os: 20.04 - compiler: 'gcc-10' - - os: 20.04 - compiler: 'clang-9' - - os: 20.04 - compiler: 'clang-10' - os: 22.04 compiler: 'gcc-11' - os: 22.04 diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 70bb395b433..4dd92823027 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -20,40 +20,30 @@ jobs: continue-on-error: true env: COMPILER: ${{ matrix.compiler }} - BUILD_OS: ${{ matrix.os }} + BUILD_OS: ubuntu-${{ matrix.os }} strategy: fail-fast: false matrix: - compiler: ['gcc', 'clang', 'gcc-9', 'gcc-10', 'clang-9', 'clang-10'] - os: [ubuntu-20.04] + os: [22.04] + compiler: ['gcc', 'clang', 'gcc-11', 'gcc-12', 'clang-11', 'clang-12', 'clang-13', 'clang-14', 'clang-15', 'gcc-arm64-qemu-cross', 'gcc-arm32-qemu-cross', 'clang-arm64-qemu-cross', 'clang-arm32-qemu-cross'] include: - - compiler: 'gcc' - os: ubuntu-22.04 - - compiler: 'clang' - os: ubuntu-22.04 - - compiler: 'gcc-11' - os: ubuntu-22.04 - - compiler: 'gcc-12' - os: ubuntu-22.04 - - compiler: 'clang-11' - os: ubuntu-22.04 - - compiler: 'clang-12' - os: ubuntu-22.04 - - compiler: 'clang-13' - os: ubuntu-22.04 - - compiler: 'clang-14' - os: ubuntu-22.04 - - compiler: 'clang-15' - os: ubuntu-22.04 - - compiler: 'gcc-arm64-qemu-cross' - os: ubuntu-22.04 - - compiler: 'gcc-arm32-qemu-cross' - os: ubuntu-22.04 - - compiler: 'clang-arm64-qemu-cross' - os: ubuntu-22.04 - - compiler: 'clang-arm32-qemu-cross' - os: ubuntu-22.04 + - os: 24.04 + compiler: 'gcc' + - os: 24.04 + compiler: 'clang' + - os: 24.04 + compiler: 'gcc-13' + - os: 24.04 + compiler: 'gcc-14' + - os: 24.04 + compiler: 'clang-16' + - os: 24.04 + compiler: 'clang-17' + - os: 24.04 + compiler: 'clang-18' + - os: 24.04 + compiler: 'clang-19' # Steps represent a sequence of tasks that will be executed as part of the job steps: