3rdParty: update SDL_net

This commit is contained in:
Rosalie Wanders
2026-01-13 14:08:11 +01:00
parent 02eef161e7
commit 85265575ea
13 changed files with 856 additions and 531 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
${{ matrix.platform.msys-env }}-ninja
${{ matrix.platform.msys-env }}-perl
- name: Get SDL3_net sources
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Install Ninja
if: ${{ !contains(matrix.platform.shell, 'msys2') }}
uses: aseprite/get-ninja@main
+242 -241
View File
@@ -24,12 +24,12 @@ jobs:
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
- name: 'Set up SDL sources'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
path: 'SDL'
@@ -47,7 +47,7 @@ jobs:
--github \
--debug
- name: 'Store source archives'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: sources
path: '${{ github.workspace}}/dist'
@@ -69,7 +69,7 @@ jobs:
with:
python-version: '3.11'
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '/tmp'
@@ -97,7 +97,7 @@ jobs:
run: |
${{ steps.tar.outputs.path }}/build-scripts/test-versioning.sh
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
@@ -139,224 +139,225 @@ jobs:
cmake --build /tmp/build --verbose
# ctest --test-dir /tmp/build --no-tests=error --output-on-failure
# dmg:
# needs: [src]
# runs-on: macos-latest
# outputs:
# dmg: ${{ steps.releaser.outputs.dmg }}
# steps:
# - name: 'Set up Python'
# uses: actions/setup-python@v5
# with:
# python-version: '3.11'
# - name: 'Fetch build-release.py'
# uses: actions/checkout@v4
# with:
# ref: ${{ inputs.commit }}
# sparse-checkout: 'build-scripts/build-release.py'
# - name: 'Download source archives'
# uses: actions/download-artifact@v4
# with:
# name: sources
# path: '${{ github.workspace }}'
# - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
# id: tar
dmg:
needs: [src]
runs-on: macos-latest
outputs:
dmg: ${{ steps.releaser.outputs.dmg }}
steps:
- name: 'Set up Python'
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
- name: 'Download source archives'
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
- name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
id: tar
run: |
mkdir -p "${{ github.workspace }}/tardir"
tar -C "${{ github.workspace }}/tardir" -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
echo "path=${{ github.workspace }}/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
# - name: 'Download external dependencies'
# run: |
# mkdir -p "${{ github.workspace }}/tardir"
# tar -C "${{ github.workspace }}/tardir" -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
# echo "path=${{ github.workspace }}/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
## - name: 'Download external dependencies'
## run: |
## sh "${{ steps.tar.outputs.path }}/external/download.sh" --depth 1
# - name: 'Build SDL3_net.dmg'
# id: releaser
# shell: bash
# env:
# GH_TOKEN: ${{ github.token }}
# run: |
# python build-scripts/build-release.py \
# --actions dmg \
# --commit ${{ inputs.commit }} \
# --root "${{ steps.tar.outputs.path }}" \
# --github \
# --debug
# - name: 'Store DMG image file'
# uses: actions/upload-artifact@v4
# with:
# name: dmg
# path: '${{ github.workspace }}/dist'
#
# dmg-verify:
# needs: [dmg, src]
# runs-on: macos-latest
# steps:
# - name: 'Set up Python'
# uses: actions/setup-python@v5
# with:
# python-version: '3.11'
# - name: 'Fetch build-release.py'
# uses: actions/checkout@v4
# with:
# ref: ${{ inputs.commit }}
# sparse-checkout: 'build-scripts/build-release.py'
# - name: 'Download source archives'
# uses: actions/download-artifact@v4
# with:
# name: sources
# path: '${{ github.workspace }}'
# - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
# id: src
# run: |
# mkdir -p /tmp/tardir
# tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
# echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
# - name: 'Download dependencies'
# id: deps
# env:
# GH_TOKEN: ${{ github.token }}
# run: |
# python build-scripts/build-release.py \
# --actions download \
# --commit ${{ inputs.commit }} \
# --root "${{ steps.src.outputs.path }}" \
# --github \
# --debug
# - name: 'Mount dependencies'
# id: deps-mount
# run: |
# hdiutil attach "${{ steps.deps.outputs.dep-path }}/SDL3-${{ steps.deps.outputs.dep-sdl-version }}.dmg"
# sdl_mount_pount="/Volumes/SDL3"
# if [ ! -d "$sdl_mount_pount/SDL3.xcframework" ]; then
# echo "Cannot find SDL3.xcframework!"
# exit 1
# fi
# echo "path=${sdl_mount_pount}" >>$GITHUB_OUTPUT
# - name: 'Download ${{ needs.dmg.outputs.dmg }}'
# uses: actions/download-artifact@v4
# with:
# name: dmg
# path: '${{ github.workspace }}'
# - name: 'Mount ${{ needs.dmg.outputs.dmg }}'
# id: mount
# run: |
# hdiutil attach '${{ github.workspace }}/${{ needs.dmg.outputs.dmg }}'
# mount_point="/Volumes/${{ needs.src.outputs.project }}"
# if [ ! -d "$mount_point/${{ needs.src.outputs.project }}.xcframework" ]; then
# echo "Cannot find ${{ needs.src.outputs.project }}.xcframework!"
# exit 1
# fi
# echo "mount-point=${mount_point}">>$GITHUB_OUTPUT
# - name: 'CMake (configure + build) Darwin'
# run: |
# set -e
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
# -DCMAKE_SYSTEM_NAME=Darwin \
# -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
# -Werror=dev \
# -B build_darwin
# cmake --build build_darwin --config Release --verbose
#
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/macos-arm64_x86_64;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/macos-arm64_x86_64" \
# -DCMAKE_SYSTEM_NAME=Darwin \
# -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
# -B build_darwin2
# cmake --build build_darwin2 --config Release --verbose
#
# - name: 'CMake (configure + build) iOS'
# run: |
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
# -DCMAKE_SYSTEM_NAME=iOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64" \
# -Werror=dev \
# -B build_ios
# cmake --build build_ios --config Release --verbose
#
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/ios-arm64;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/ios-arm64" \
# -DCMAKE_SYSTEM_NAME=iOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64" \
# -B build_ios2
# cmake --build build_ios2 --config Release --verbose
# - name: 'CMake (configure + build) tvOS'
# run: |
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
# -DCMAKE_SYSTEM_NAME=tvOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64" \
# -Werror=dev \
# -B build_tvos
# cmake --build build_tvos --config Release --verbose
#
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/tvos-arm64;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/tvos-arm64" \
# -DCMAKE_SYSTEM_NAME=tvOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64" \
# -B build_tvos2
# cmake --build build_tvos2 --config Release --verbose
# - name: 'CMake (configure + build) iOS simulator'
# run: |
# sysroot=$(xcodebuild -version -sdk iphonesimulator Path)
# echo "sysroot=$sysroot"
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
# -DCMAKE_SYSTEM_NAME=iOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
# -DCMAKE_OSX_SYSROOT="${sysroot}" \
# -Werror=dev \
# -B build_ios_simulator
# cmake --build build_ios_simulator --config Release --verbose
#
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/ios-arm64_x86_64-simulator;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/ios-arm64_x86_64-simulator" \
# -DCMAKE_SYSTEM_NAME=iOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
# -DCMAKE_OSX_SYSROOT="${sysroot}" \
# -B build_ios_simulator2
# cmake --build build_ios_simulator2 --config Release --verbose
# - name: 'CMake (configure + build) tvOS simulator'
# run: |
# sysroot=$(xcodebuild -version -sdk appletvsimulator Path)
# echo "sysroot=$sysroot"
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
# -DCMAKE_SYSTEM_NAME=tvOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
# -DCMAKE_OSX_SYSROOT="${sysroot}" \
# -Werror=dev \
# -B build_tvos_simulator
# cmake --build build_tvos_simulator --config Release --verbose
#
# cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
# -DTEST_SHARED=TRUE \
# -DTEST_STATIC=FALSE \
# -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/tvos-arm64_x86_64-simulator;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/tvos-arm64_x86_64-simulator" \
# -DCMAKE_SYSTEM_NAME=tvOS \
# -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
# -DCMAKE_OSX_SYSROOT="${sysroot}" \
# -B build_tvos_simulator2
# cmake --build build_tvos_simulator2 --config Release --verbose
# sh "${{ steps.tar.outputs.path }}/external/download.sh" --depth 1
- name: 'Build SDL3_net.dmg'
id: releaser
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
python build-scripts/build-release.py \
--actions dmg \
--commit ${{ inputs.commit }} \
--root "${{ steps.tar.outputs.path }}" \
--github \
--debug
- name: 'Store DMG image file'
uses: actions/upload-artifact@v6
with:
name: dmg
path: '${{ github.workspace }}/dist'
dmg-verify:
needs: [dmg, src]
runs-on: macos-latest
steps:
- name: 'Set up Python'
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
- name: 'Download source archives'
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
- name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
id: src
run: |
mkdir -p /tmp/tardir
tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
- name: 'Download dependencies'
id: deps
env:
GH_TOKEN: ${{ github.token }}
run: |
python build-scripts/build-release.py \
--actions download \
--commit ${{ inputs.commit }} \
--root "${{ steps.src.outputs.path }}" \
--github \
--debug
- name: 'Mount dependencies'
id: deps-mount
run: |
hdiutil attach "${{ steps.deps.outputs.dep-path }}/SDL3-${{ steps.deps.outputs.dep-sdl-version }}.dmg"
sdl_mount_pount="/Volumes/SDL3"
if [ ! -d "$sdl_mount_pount/SDL3.xcframework" ]; then
echo "Cannot find SDL3.xcframework!"
exit 1
fi
echo "path=${sdl_mount_pount}" >>$GITHUB_OUTPUT
- name: 'Download ${{ needs.dmg.outputs.dmg }}'
uses: actions/download-artifact@v6
with:
name: dmg
path: '${{ github.workspace }}'
- name: 'Mount ${{ needs.dmg.outputs.dmg }}'
id: mount
run: |
hdiutil attach '${{ github.workspace }}/${{ needs.dmg.outputs.dmg }}'
mount_point="/Volumes/${{ needs.src.outputs.project }}"
if [ ! -d "$mount_point/${{ needs.src.outputs.project }}.xcframework" ]; then
echo "Cannot find ${{ needs.src.outputs.project }}.xcframework!"
exit 1
fi
echo "mount-point=${mount_point}">>$GITHUB_OUTPUT
- name: 'CMake (configure + build) Darwin'
run: |
set -e
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
-DCMAKE_SYSTEM_NAME=Darwin \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-Werror=dev \
-B build_darwin
cmake --build build_darwin --config Release --verbose
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/macos-arm64_x86_64;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/macos-arm64_x86_64" \
-DCMAKE_SYSTEM_NAME=Darwin \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-B build_darwin2
cmake --build build_darwin2 --config Release --verbose
- name: 'CMake (configure + build) iOS'
run: |
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-Werror=dev \
-B build_ios
cmake --build build_ios --config Release --verbose
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/ios-arm64;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/ios-arm64" \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-B build_ios2
cmake --build build_ios2 --config Release --verbose
- name: 'CMake (configure + build) tvOS'
run: |
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-Werror=dev \
-B build_tvos
cmake --build build_tvos --config Release --verbose
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/tvos-arm64;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/tvos-arm64" \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-B build_tvos2
cmake --build build_tvos2 --config Release --verbose
- name: 'CMake (configure + build) iOS simulator'
run: |
sysroot=$(xcodebuild -version -sdk iphonesimulator Path)
echo "sysroot=$sysroot"
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_OSX_SYSROOT="${sysroot}" \
-Werror=dev \
-B build_ios_simulator
cmake --build build_ios_simulator --config Release --verbose
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/ios-arm64_x86_64-simulator;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/ios-arm64_x86_64-simulator" \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_OSX_SYSROOT="${sysroot}" \
-B build_ios_simulator2
cmake --build build_ios_simulator2 --config Release --verbose
- name: 'CMake (configure + build) tvOS simulator'
run: |
sysroot=$(xcodebuild -version -sdk appletvsimulator Path)
echo "sysroot=$sysroot"
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_OSX_SYSROOT="${sysroot}" \
-Werror=dev \
-B build_tvos_simulator
cmake --build build_tvos_simulator --config Release --verbose
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_SHARED=TRUE \
-DTEST_STATIC=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }}/SDL3_net.xcframework/tvos-arm64_x86_64-simulator;${{ steps.deps-mount.outputs.path }}/SDL3.xcframework/tvos-arm64_x86_64-simulator" \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_OSX_SYSROOT="${sysroot}" \
-B build_tvos_simulator2
cmake --build build_tvos_simulator2 --config Release --verbose
msvc:
needs: [src]
runs-on: windows-2025
@@ -370,12 +371,12 @@ jobs:
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
@@ -401,7 +402,7 @@ jobs:
--github `
--debug
- name: 'Store MSVC archives'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: msvc
path: '${{ github.workspace }}/dist'
@@ -411,7 +412,7 @@ jobs:
runs-on: windows-latest
steps:
- name: 'Fetch .github/actions/setup-ninja/action.yml'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: |
@@ -424,7 +425,7 @@ jobs:
- name: Set up ninja
uses: ./.github/actions/setup-ninja
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
@@ -454,7 +455,7 @@ jobs:
unzip "${{ steps.deps.outputs.dep-path }}/SDL3-devel-${{ steps.deps.outputs.dep-sdl-version }}-VC.zip"
echo "path=${{ github.workspace }}/deps-vc" >>$env:GITHUB_OUTPUT
- name: 'Download MSVC binaries'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: msvc
path: '${{ github.workspace }}'
@@ -529,7 +530,7 @@ jobs:
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
@@ -538,7 +539,7 @@ jobs:
sudo apt-get update -y
sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
@@ -560,7 +561,7 @@ jobs:
--github \
--debug
- name: 'Store MinGW archives'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: mingw
path: '${{ github.workspace }}/dist'
@@ -574,7 +575,7 @@ jobs:
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ inputs.commit }}
sparse-checkout: 'build-scripts/build-release.py'
@@ -583,7 +584,7 @@ jobs:
sudo apt-get update -y
sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
@@ -619,7 +620,7 @@ jobs:
mkdir -p /tmp/deps-mingw/cmake
cp -rv /tmp/deps-mingw-extract/sdl3/SDL3-${{ steps.deps.outputs.dep-sdl-version }}/cmake/* /tmp/deps-mingw/cmake
- name: 'Download MinGW binaries'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: mingw
path: '${{ github.workspace }}'
@@ -665,7 +666,7 @@ jobs:
with:
python-version: '3.11'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
sparse-checkout: 'build-scripts/build-release.py'
- name: 'Setup Android NDK'
@@ -675,7 +676,7 @@ jobs:
local-cache: false
ndk-version: r28c
- name: 'Setup Java JDK'
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '11'
@@ -684,7 +685,7 @@ jobs:
sudo apt-get update -y
sudo apt-get install -y ninja-build
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
@@ -708,7 +709,7 @@ jobs:
--github \
--debug
- name: 'Store Android archive(s)'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: android
path: '${{ github.workspace }}/dist'
@@ -721,17 +722,17 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: '3.11'
- uses: actions/setup-java@v4
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: 'Download source archives'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: sources
path: '${{ github.workspace }}'
- name: 'Download Android .aar archive'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: android
path: '${{ github.workspace }}'
+1
View File
@@ -1,5 +1,6 @@
build/
buildbot/
!build-scripts/
/VERSION.txt
*.so
+2 -2
View File
@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:libsdl-org/SDL_net.git
branch = main
commit = cb287ed74f612f137e29fab9dfc08b3dc87a67e4
parent = d23f381dfa7d85acfa198a20d5cf5b202676b297
commit = 4dd85af45d8597f93796815fba0defa5d499be21
parent = 02eef161e7f4ac7a4deebd0115574b7a27c5f58f
method = merge
cmdver = 0.4.9
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+34 -22
View File
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
# Simple DirectMedia Layer
# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
# Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
@@ -37,6 +37,11 @@ my $versionfname = 'include/SDL_version.h';
my $versionmajorregex = '\A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z';
my $versionminorregex = '\A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z';
my $versionmicroregex = '\A\#define\s+SDL_MICRO_VERSION\s+(\d+)\Z';
my $wikidocsectionsym = 'SDL_WIKI_DOCUMENTATION_SECTION';
my $forceinlinesym = 'SDL_FORCE_INLINE';
my $deprecatedsym = 'SDL_DEPRECATED';
my $declspecsym = '(?:SDLMAIN_|SDL_)?DECLSPEC';
my $callconvsym = 'SDLCALL';
my $mainincludefname = 'SDL.h';
my $selectheaderregex = '\ASDL.*?\.h\Z';
my $projecturl = 'https://libsdl.org/';
@@ -147,6 +152,12 @@ if (defined $optionsfname) {
$envvardesc = $val, next if $key eq 'envvardesc';
$envvarsymregex = $val, next if $key eq 'envvarsymregex';
$envvarsymreplace = $val, next if $key eq 'envvarsymreplace';
$wikidocsectionsym = $val, next if $key eq 'wikidocsectionsym';
$forceinlinesym = $val, next if $key eq 'forceinlinesym';
$deprecatedsym = $val, next if $key eq 'deprecatedsym';
$declspecsym = $val, next if $key eq 'declspecsym';
$callconvsym = $val, next if $key eq 'callconvsym';
}
}
close(OPTIONS);
@@ -750,6 +761,7 @@ sub print_undocumented_section {
}
}
# !!! FIXME: generalize this for other libraries to use.
sub strip_fn_declaration_metadata {
my $decl = shift;
$decl =~ s/SDL_(PRINTF|SCANF)_FORMAT_STRING\s*//; # don't want this metadata as part of the documentation.
@@ -1153,7 +1165,7 @@ while (my $d = readdir(DH)) {
} elsif ($ignoring_lines) {
push @contents, $_;
next;
} elsif (/\A\s*\#\s*ifndef\s+SDL_WIKI_DOCUMENTATION_SECTION\s*\Z/) {
} elsif (/\A\s*\#\s*ifndef\s+$wikidocsectionsym\s*\Z/) {
$ignoring_lines = 1;
push @contents, $_;
next;
@@ -1162,13 +1174,13 @@ while (my $d = readdir(DH)) {
#print("CATEGORY FOR '$dent' CHANGED TO " . (defined($current_wiki_category) ? "'$current_wiki_category'" : '(undef)') . "\n");
push @contents, $_;
next;
} elsif (/\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC/) { # a function declaration without a doxygen comment?
} elsif (/\A\s*extern\s+(?:$deprecatedsym\s+|)$declspecsym/) { # a function declaration without a doxygen comment?
$symtype = 1; # function declaration
@templines = ();
$decl = $_;
$str = '';
$has_doxygen = 0;
} elsif (/\A\s*SDL_FORCE_INLINE/) { # a (forced-inline) function declaration without a doxygen comment?
} elsif (/\A\s*$forceinlinesym/) { # a (forced-inline) function declaration without a doxygen comment?
$symtype = 1; # function declaration
@templines = ();
$decl = $_;
@@ -1235,9 +1247,9 @@ while (my $d = readdir(DH)) {
$lineno++ if defined $decl;
$decl = '' if not defined $decl;
chomp($decl);
if ($decl =~ /\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC/) {
if ($decl =~ /\A\s*extern\s+(?:$deprecatedsym\s+|)$declspecsym/) {
$symtype = 1; # function declaration
} elsif ($decl =~ /\A\s*SDL_FORCE_INLINE/) {
} elsif ($decl =~ /\A\s*$forceinlinesym/) {
$symtype = 1; # (forced-inline) function declaration
} elsif ($decl =~ /\A\s*\#\s*define\s+/) {
$symtype = 2; # macro
@@ -1274,7 +1286,7 @@ while (my $d = readdir(DH)) {
}
$headercategorydocs{$current_wiki_category} = $sym;
} elsif ($symtype == 1) { # a function
my $is_forced_inline = ($decl =~ /\A\s*SDL_FORCE_INLINE/);
my $is_forced_inline = ($decl =~ /\A\s*$forceinlinesym/);
if ($is_forced_inline) {
if (not $decl =~ /\)\s*(\{.*|)\s*\Z/) {
@@ -1311,14 +1323,14 @@ while (my $d = readdir(DH)) {
my $paramsstr = undef;
if (!$is_forced_inline && $decl =~ /\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC\w*\s+(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(\*?)\s*SDLCALL\s+(.*?)\s*\((.*?)\);/) {
$sym = $8;
$rettype = "$3$4$5$6";
$paramsstr = $9;
} elsif ($is_forced_inline && $decl =~ /\A\s*SDL_FORCE_INLINE\s+(SDL_DEPRECATED\s+|)(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(.*?)\s*\((.*?)\);/) {
if (!$is_forced_inline && $decl =~ /\A\s*extern\s+(?:$deprecatedsym\s+|)$declspecsym\w*\s+(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(\*?)\s*$callconvsym\s+(.*?)\s*\((.*?)\);/) {
$sym = $6;
$rettype = "$2$3$4$5";
$rettype = "$1$2$3$4$5";
$paramsstr = $7;
} elsif ($is_forced_inline && $decl =~ /\A\s*$forceinlinesym\s+(?:$deprecatedsym\s+|)(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(.*?)\s*\((.*?)\);/) {
$sym = $5;
$rettype = "$1$2$3$4";
$paramsstr = $6;
} else {
#print "Found doxygen but no function sig:\n$str\n\n";
foreach (@templines) {
@@ -1384,7 +1396,7 @@ while (my $d = readdir(DH)) {
$decl = $_;
$temp = $decl;
$temp =~ s/\Aextern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC\w*\s+(.*?)\s+(\*?)SDLCALL\s+/$3$4 /;
$temp =~ s/\Aextern\s+(?:$deprecatedsym\s+|)$declspecsym\w*\s+(.*?)\s+(\*?)$callconvsym\s+/$1$2 /;
$shrink_length = length($decl) - length($temp);
$decl = $temp;
} else {
@@ -2259,10 +2271,10 @@ if ($copy_direction == 1) { # --copy-to-headers
$desc =~ s/[\s\n]+\Z//ms;
if (0) { # !!! FIXME: disabled because it's not currently suitable for general use, but for manually inspecting the output, it can be useful.
if (($desc =~ /\A[A-Z]/) && (not $desc =~ /\ASDL_/)) {
print STDERR "WARNING: $sym\'s '\\param $arg' text starts with a capital letter: '$desc'. Fixing.\n";
$desc = lcfirst($desc);
if (0) {
if (($desc =~ /\A[a-z]/) && (not $desc =~ /$apiprefixregex/)) {
print STDERR "WARNING: $sym\'s '\\param $arg' text starts with a lowercase letter: '$desc'. Fixing.\n";
$desc = ucfirst($desc);
}
}
@@ -2306,8 +2318,8 @@ if ($copy_direction == 1) { # --copy-to-headers
}
$desc =~ s/[\s\n]+\Z//ms;
if (0) { # !!! FIXME: disabled because it's not currently suitable for general use, but for manually inspecting the output, it can be useful.
if (($desc =~ /\A[A-Z]/) && (not $desc =~ /\ASDL_/)) {
if (0) {
if (($desc =~ /\A[A-Z]/) && (not $desc =~ /$apiprefixregex/)) {
print STDERR "WARNING: $sym\'s '\\returns' text starts with a capital letter: '$desc'. Fixing.\n";
$desc = lcfirst($desc);
}
@@ -2451,7 +2463,7 @@ if ($copy_direction == 1) { # --copy-to-headers
} else {
die("Unexpected symbol type $symtype!");
}
my $str = "This $symtypename is available since SDL 3.0.0.";
my $str = "This $symtypename is available since $projectshortname 3.0.0.";
$sections{'Version'} = wordwrap(wikify($wikitype, $str)) . "\n";
}
}
@@ -2916,7 +2928,7 @@ __EOF__
$str .= ".\\\" Please report issues in this manpage's content at:\n";
$str .= ".\\\" $bugreporturl\n";
$str .= ".\\\" Please report issues in the generation of this manpage from the wiki at:\n";
$str .= ".\\\" https://github.com/libsdl-org/SDL/issues/new?title=Misgenerated%20manpage%20for%20$sym\n";
$str .= ".\\\" https://github.com/libsdl-org/SDL/issues/new?title=Misgenerated%20manpage%20for%20$sym\n"; # !!! FIXME: if this becomes a problem for other projects, we'll generalize this.
$str .= ".\\\" $projectshortname can be found at $projecturl\n";
# Define a .URL macro. The "www.tmac" thing decides if we're using GNU roff (which has a .URL macro already), and if so, overrides the macro we just created.
@@ -164,6 +164,22 @@ function(get_git_head_revision _refspecvar _hashvar)
"${GIT_DATA}/grabRef.cmake" @ONLY)
include("${GIT_DATA}/grabRef.cmake")
# Fallback for reftable or other storage formats
if(NOT HEAD_HASH OR HEAD_HASH STREQUAL "")
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE HEAD_HASH
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(HEAD_HASH "")
endif()
endif()
endif()
set(${_refspecvar}
"${HEAD_REF}"
PARENT_SCOPE)
@@ -25,19 +25,21 @@ if(HEAD_CONTENTS MATCHES "ref")
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
elseif(EXISTS "@GIT_DIR@/packed-refs")
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
elseif(EXISTS "@GIT_DIR@/reftable/tables.list")
configure_file("@GIT_DIR@/reftable/tables.list" "@GIT_DATA@/reftable-tables.list" COPYONLY)
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
if(NOT HEAD_HASH AND EXISTS "@GIT_DATA@/head-ref")
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()
+20 -6
View File
@@ -3,6 +3,9 @@
include(CheckCCompilerFlag)
include(CheckCSourceCompiles)
include(CMakePushCheckState)
if(NOT CMAKE_VERSION VERSION_LESS "3.18")
include(CheckLinkerFlag)
endif()
macro(sdl_calculate_derived_version_variables MAJOR MINOR MICRO)
set(SO_VERSION_MAJOR "0")
@@ -241,11 +244,14 @@ function(sdl_check_project_in_subfolder relative_subfolder name vendored_option)
endfunction()
macro(sdl_check_linker_flag flag var)
# FIXME: Use CheckLinkerFlag module once cmake minimum version >= 3.18
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_LINK_OPTIONS "${flag}")
check_c_source_compiles("int main() { return 0; }" ${var} FAIL_REGEX "(unsupported|syntax error|unrecognized option)")
cmake_pop_check_state()
if(NOT CMAKE_VERSION VERSION_LESS "3.18")
check_linker_flag(C "${flag}" "${var}")
else()
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_LINK_OPTIONS "${flag}")
check_c_source_compiles("int main() { return 0; }" ${var} FAIL_REGEX "(unsupported|syntax error|unrecognized option)")
cmake_pop_check_state()
endif()
endmacro()
function(SDL_detect_linker)
@@ -283,7 +289,6 @@ endfunction()
function(sdl_target_link_options_no_undefined TARGET)
if(NOT MSVC AND NOT CMAKE_SYSTEM_NAME MATCHES ".*OpenBSD.*")
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang")
target_link_options(${TARGET} PRIVATE "-Wl,-undefined,error")
else()
sdl_check_linker_flag("-Wl,--no-undefined" HAVE_WL_NO_UNDEFINED)
if(HAVE_WL_NO_UNDEFINED AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") AND WIN32))
@@ -318,6 +323,15 @@ function(sdl_add_warning_options TARGET)
else()
target_compile_options(${TARGET} PRIVATE -Werror)
endif()
get_property(target_type TARGET ${TARGET} PROPERTY TYPE)
if(NOT (APPLE OR MSVC))
if(target_type MATCHES "SHARED_LIBRARY|MODULE_LIBRARY")
sdl_check_linker_flag("-Wl,-fatal-warnings" HAVE_WL_FATAL_WARNINGS)
if(HAVE_WL_FATAL_WARNINGS)
target_link_options(${TARGET} PRIVATE "-Wl,-fatal-warnings")
endif()
endif()
endif()
endif()
endfunction()
+1 -1
View File
@@ -1,6 +1,6 @@
/*
SDL_net: A simple networking library for use with SDL
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+532 -253
View File
@@ -1,6 +1,6 @@
/*
SDL_net: A simple networking library for use with SDL
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -171,6 +171,7 @@ static int WindowsPoll(struct pollfd *fds, unsigned int nfds, int timeout)
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
@@ -179,7 +180,11 @@ static int WindowsPoll(struct pollfd *fds, unsigned int nfds, int timeout)
#include <unistd.h>
#include <fcntl.h>
#ifdef SDL_PLATFORM_ANDROID
#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)
#define USE_NETLINK 1
#endif
#ifdef USE_NETLINK
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#else
@@ -206,6 +211,14 @@ int NET_Version(void)
return SDL_NET_VERSION;
}
typedef enum NET_AddressType
{
NET_ADDRTYPE_UNKNOWN=-1,
NET_ADDRTYPE_UNICAST,
NET_ADDRTYPE_MULTICAST,
NET_ADDRTYPE_BROADCAST
} NET_AddressType;
struct NET_Address
{
char *hostname;
@@ -213,13 +226,24 @@ struct NET_Address
char *errstr;
SDL_AtomicInt refcount;
SDL_AtomicInt status; // This is actually a NET_Status.
NET_AddressType type;
struct addrinfo *ainfo;
NET_Address *resolver_next; // a linked list for the resolution job queue.
};
typedef struct NetworkInterfaces
{
char *name;
int index;
NET_Address *address;
NET_Address *broadcast;
} NetworkInterfaces;
#define MIN_RESOLVER_THREADS 2
#define MAX_RESOLVER_THREADS 10
// Address resolver state...
static NET_Address *resolver_queue = NULL;
static SDL_Thread *resolver_threads[MAX_RESOLVER_THREADS];
static SDL_Mutex *resolver_lock = NULL;
@@ -229,6 +253,13 @@ static SDL_AtomicInt resolver_num_threads;
static SDL_AtomicInt resolver_num_requests;
static SDL_AtomicInt resolver_percent_loss;
// Network interface state...
static SDL_InitState interface_init;
static SDL_RWLock *interface_rwlock = NULL;
static int num_interfaces = 0;
static NetworkInterfaces *interfaces = NULL;
static SDL_AtomicInt interfaces_have_changed;
// between lo and hi (inclusive; it can return lo or hi itself, too!).
static int RandomNumberBetween(const int lo, const int hi)
{
@@ -326,6 +357,470 @@ static bool SetGetAddrInfoErrorBool(const char *msg, int err)
return false;
}
static int MakeSocketNonblocking(Socket handle)
{
#ifdef SDL_PLATFORM_WINDOWS
DWORD one = 1;
return ioctlsocket(handle, FIONBIO, &one);
#else
return fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
#endif
}
static bool WouldBlock(const int err)
{
#ifdef SDL_PLATFORM_WINDOWS
return (err == WSAEWOULDBLOCK);
#else
return ((err == EWOULDBLOCK) || (err == EAGAIN) || (err == EINPROGRESS));
#endif
}
static NET_Address *CreateSDLNetAddrFromSockAddr(const struct sockaddr *saddr, SockLen saddrlen);
/* Network interface enumeration... */
static void FreeNetworkInterfaces(NetworkInterfaces *ifaces, int num_ifaces)
{
for (int i = 0; i < num_ifaces; i++) {
NET_UnrefAddress(ifaces[i].address);
NET_UnrefAddress(ifaces[i].broadcast);
SDL_free(ifaces[i].name);
}
SDL_free(ifaces);
}
#ifdef SDL_PLATFORM_WINDOWS
static HANDLE interface_change_notifications_handle;
static VOID WINAPI NetworkInterfaceChangedCallback(PVOID ctx, PMIB_IPINTERFACE_ROW row, MIB_NOTIFICATION_TYPE type)
{
SDL_SetAtomicInt(&interfaces_have_changed, 1);
}
static bool InitInterfaceChangeNotifications(void) // WINDOWS VERSION
{
// this would need to use NotifyAddrChange for Windows XP, but it doesn't work with IPv6 before Vista.
//return (NotifyAddrChange(&addr_change_notification_handle, &overlapped) == ERROR_IO_PENDING);
// !!! FIXME: this function is available on Vista and later.
return (NotifyIpInterfaceChange(AF_UNSPEC, NetworkInterfaceChangedCallback, NULL, FALSE, &interface_change_notifications_handle) == NO_ERROR);
}
static void QuitInterfaceChangeNotifications(void) // WINDOWS VERSION
{
CancelMibChangeNotify2(interface_change_notifications_handle);
interface_change_notifications_handle = 0;
}
static void RefreshInterfaces(void) // WINDOWS VERSION
{
// MSDN docs say start with a 15K buffer, which usually works on the first
// try, instead of trying to query for size, allocate, and then retry,
// since this tends to be more expensive.
ULONG buflen = 15 * 1024;
IP_ADAPTER_ADDRESSES *addrs = NULL;
ULONG rc;
do {
SDL_free(addrs);
addrs = (IP_ADAPTER_ADDRESSES *) SDL_malloc(buflen);
if (!addrs) {
return;
}
const ULONG flags = GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
rc = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addrs, &buflen);
} while (rc == ERROR_BUFFER_OVERFLOW);
if (rc != NO_ERROR) {
SDL_free(addrs);
return;
}
int new_num_interfaces = 0;
for (IP_ADAPTER_ADDRESSES *i = addrs; i != NULL; i = i->Next) {
for (IP_ADAPTER_UNICAST_ADDRESS *j = i->FirstUnicastAddress; j != NULL; j = j->Next) {
new_num_interfaces++;
}
}
NetworkInterfaces *new_interfaces = (NetworkInterfaces *) SDL_calloc(new_num_interfaces + 1, sizeof (*new_interfaces));
if (!new_interfaces) {
SDL_free(addrs);
return;
}
int count = 0;
for (IP_ADAPTER_ADDRESSES *i = addrs; i != NULL; i = i->Next) {
for (IP_ADAPTER_UNICAST_ADDRESS *j = i->FirstUnicastAddress; j != NULL; j = j->Next) {
NET_Address *addr = CreateSDLNetAddrFromSockAddr(j->Address.lpSockaddr, j->Address.iSockaddrLength);
if (addr) {
new_interfaces[count].address = addr;
if (j->Address.lpSockaddr->sa_family == AF_INET6) {
new_interfaces[count].index = i->Ipv6IfIndex;
} else if (j->Address.lpSockaddr->sa_family == AF_INET) { // if this is IPv4, calculate the broadcast address.
SOCKADDR_IN bcast;
SDL_assert(j->Address.iSockaddrLength == sizeof (bcast));
SDL_memcpy(&bcast, (const SOCKADDR_IN *) j->Address.lpSockaddr, sizeof (SOCKADDR_IN));
bcast.sin_addr.S_un.S_addr |= htonl(~((1 << (32 - j->OnLinkPrefixLength)) - 1));
new_interfaces[count].broadcast = CreateSDLNetAddrFromSockAddr((const struct sockaddr *) &bcast, sizeof (bcast));
new_interfaces[count].broadcast->type = NET_ADDRTYPE_BROADCAST;
new_interfaces[count].index = i->IfIndex;
}
count++;
}
}
}
new_num_interfaces = count; // in case we dropped one somewhere.
SDL_LockRWLockForWriting(interface_rwlock);
NetworkInterfaces *old_interfaces = interfaces;
const int old_num_interfaces = num_interfaces;
interfaces = new_interfaces;
num_interfaces = new_num_interfaces;
SDL_UnlockRWLock(interface_rwlock);
FreeNetworkInterfaces(old_interfaces, old_num_interfaces);
SDL_free(addrs);
}
#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_APPLE) || defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_OPENBSD) || defined(SDL_PLATFORM_NETBSD)
// AF_NETLINK covers Linux (and by extension Android). PF_ROUTE covers the BSDs (and by extension Apple platforms).
// This doesn't cover all Unix platforms that ever existed, but this hits just about everything that is still being maintained seriously.
static SDL_Thread *interface_change_notifications_thread = NULL;
static SDL_AtomicInt interface_change_notifications_flag; // !!! FIXME
static int SDLCALL LinuxInterfaceChangeNotificationThread(void *data)
{
#ifdef USE_NETLINK
const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
#else
const int fd = socket(PF_ROUTE, SOCK_RAW, 0);
#endif
if (fd == -1) {
return 0; // oh well.
}
// !!! FIXME: don't make this non-blocking, find a more efficient way to terminate the thread.
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
#ifdef USE_NETLINK
struct sockaddr_nl addr;
SDL_zero(addr);
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR;
if (bind(fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
close(fd);
return 0; // oh well.
}
#elif defined(RO_MSGFILTER)
const unsigned char filter[] = { RTM_IFANNOUNCE, RTM_IFINFO, RTM_NEWADDR, RTM_DELADDR, RTM_CHGADDR };
setsockopt(fd, PF_ROUTE, RO_MSGFILTER, &filter, sizeof (filter));
#endif
while (SDL_GetAtomicInt(&interface_change_notifications_flag) == 0) {
Uint8 buf[8192];
struct iovec iov = { buf, sizeof (buf) };
struct msghdr msg;
SDL_zero(msg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
#ifdef USE_NETLINK
struct sockaddr_nl sa;
SDL_zero(sa);
msg.msg_name = &sa;
msg.msg_namelen = sizeof (sa);
#endif
const ssize_t br = recvmsg(fd, &msg, 0);
if (br < 0) {
if (WouldBlock(LastSocketError())) {
SDL_Delay(300);
continue;
}
// quit if there's a failure. Presumably this is because another thread close()'d the socket, to unblock the thread and request termination.
break;
}
// we don't currently bother parsing for specifics, we just use this as a signal to reenumerate interfaces.
//for (struct nlmsghdr *i = buf; NLMSG_OK(i, br); i = NLMSG_NEXT(i, br)) {}
SDL_Log("Network interfaces changed!");
SDL_SetAtomicInt(&interfaces_have_changed, 1);
}
close(fd);
return 0;
}
static bool InitInterfaceChangeNotifications(void) // LINUX/BSD VERSION
{
interface_change_notifications_thread = SDL_CreateThread(LinuxInterfaceChangeNotificationThread, "SDLNetIfaceEnum", NULL);
return (interface_change_notifications_thread != NULL);
}
static void QuitInterfaceChangeNotifications(void) // LINUX/BSD VERSION
{
if (interface_change_notifications_thread) {
SDL_SetAtomicInt(&interface_change_notifications_flag, 1);
SDL_WaitThread(interface_change_notifications_thread, NULL);
SDL_SetAtomicInt(&interface_change_notifications_flag, 0);
}
interface_change_notifications_thread = NULL;
}
static void RefreshInterfaces(void) // LINUX/BSD VERSION
{
#ifdef USE_NETLINK
// Android has getifaddrs() in Android 24, but we still target 21, so do it the hard way. Since this works on normal Linux, we'll just use it there, too.
const int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sock < 0) {
return; // oh well.
}
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
// Ask for the address information.
typedef struct reqstruct
{
struct nlmsghdr header;
struct ifaddrmsg msg;
} reqstruct;
reqstruct req;
SDL_zero(req);
req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
req.header.nlmsg_type = RTM_GETADDR;
req.header.nlmsg_len = NLMSG_LENGTH(sizeof (req.msg));
req.msg.ifa_family = AF_UNSPEC;
if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) {
close(sock);
return; // oh well.
}
int new_num_interfaces = 0;
NetworkInterfaces *new_interfaces = NULL;
Uint8 buffer[64 * 1024];
ssize_t br;
while ((br = recv(sock, buffer, sizeof (buffer), 0)) > 0) {
for (const struct nlmsghdr *header = (const struct nlmsghdr *) buffer; NLMSG_OK(header, (size_t) br); header = NLMSG_NEXT(header, br)) {
if (header->nlmsg_type == NLMSG_DONE) {
goto succeeded; // we got it all.
} else if (header->nlmsg_type == NLMSG_ERROR) {
goto failed; // uhoh.
} else if (header->nlmsg_type == RTM_NEWADDR) {
// strictly speaking, one interface can have multiple IP addresses, so you might have multiple addresses with the same interface index.
void *ptr = SDL_realloc(new_interfaces, sizeof (*new_interfaces) * (new_num_interfaces + 1));
if (!ptr) {
goto failed;
}
new_interfaces = (NetworkInterfaces *) ptr;
NetworkInterfaces *iface = &new_interfaces[new_num_interfaces];
SDL_zerop(iface);
const struct ifaddrmsg *msg = (const struct ifaddrmsg *) (NLMSG_DATA(header));
size_t payload_len = IFA_PAYLOAD(header);
for (const struct rtattr *attr = IFA_RTA(msg); RTA_OK(attr, payload_len); attr = RTA_NEXT(attr, payload_len)) {
const bool isbroadcast = (attr->rta_type == IFA_BROADCAST);
if (isbroadcast || (attr->rta_type == IFA_ADDRESS)) {
// this gives us the raw bytes of an address, but not the actual sockaddr_* layout, so we have to go with known protocols. :/
AddressStorage addrstorage;
SockLen addrlen = 0;
SDL_zero(addrstorage);
addrstorage.ss_family = msg->ifa_family;
if (addrstorage.ss_family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *) &addrstorage;
SDL_memcpy(&sa->sin_addr, RTA_DATA(attr), RTA_PAYLOAD(attr));
addrlen = sizeof (*sa);
} else if (addrstorage.ss_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &addrstorage;
SDL_memcpy(&sa6->sin6_addr, RTA_DATA(attr), RTA_PAYLOAD(attr));
addrlen = sizeof (*sa6);
} else {
continue; // unknown protocol family.
}
NET_Address **paddr = isbroadcast ? &iface->broadcast : &iface->address;
SDL_assert(*paddr == NULL); // shouldn't be two of these attributes on a single RTM_NEWADDR.
*paddr = CreateSDLNetAddrFromSockAddr((const struct sockaddr *) &addrstorage, addrlen);
}
}
if (iface->address) {
iface->index = msg->ifa_index;
if (iface->broadcast) {
iface->broadcast->type = NET_ADDRTYPE_BROADCAST;
}
char interface_name[IF_NAMESIZE];
if (if_indextoname((unsigned int) iface->index, interface_name) == NULL) { // miraculously, this function is in Android 21; nothing else is, though! We could have done this with netlink too, but this is the easy button.
interface_name[0] = '\0';
}
iface->name = SDL_strdup(interface_name);
if (!iface->name) {
goto failed;
}
new_num_interfaces++;
} else {
NET_UnrefAddress(iface->broadcast); // just in case.
}
}
}
}
succeeded:
close(sock);
SDL_LockRWLockForWriting(interface_rwlock);
NetworkInterfaces *old_interfaces = interfaces;
const int old_num_interfaces = num_interfaces;
interfaces = new_interfaces;
num_interfaces = new_num_interfaces;
SDL_UnlockRWLock(interface_rwlock);
FreeNetworkInterfaces(old_interfaces, old_num_interfaces);
return;
failed:
close(sock);
FreeNetworkInterfaces(new_interfaces, new_num_interfaces);
// if this was a failure case, oh well, old (maybe incorrect) ones will have to stand.
#else
struct ifaddrs *ifaddr = NULL;
if (getifaddrs(&ifaddr) == -1) {
return; // oh well.
}
NetworkInterfaces *new_interfaces = NULL;
int new_num_interfaces = 0;
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next) {
if (i->ifa_name != NULL) {
new_num_interfaces++;
}
}
if (!new_num_interfaces) {
goto succeeded;
}
new_interfaces = SDL_calloc(new_num_interfaces, sizeof (*new_interfaces));
if (!new_interfaces) {
goto failed;
}
NetworkInterfaces *iface = &new_interfaces[0];
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next, iface++) {
if (i->ifa_name == NULL) {
continue; // i guess.
}
// !!! FIXME: getifaddrs doesn't return the sockaddr length, so we have to go with known protocols. :/
if (i->ifa_addr->sa_family == AF_INET) {
iface->address = CreateSDLNetAddrFromSockAddr(i->ifa_addr, sizeof (struct sockaddr_in));
if (i->ifa_flags & IFF_BROADCAST) {
iface->broadcast = CreateSDLNetAddrFromSockAddr(i->ifa_broadaddr, sizeof (struct sockaddr_in));
}
} else if (i->ifa_addr->sa_family == AF_INET6) {
iface->address = CreateSDLNetAddrFromSockAddr(i->ifa_addr, sizeof (struct sockaddr_in6));
} else {
new_num_interfaces--;
iface--;
continue;
}
if (iface->address) {
if (iface->broadcast) {
iface->broadcast->type = NET_ADDRTYPE_BROADCAST;
}
iface->index = (int) if_nametoindex(i->ifa_name);
iface->name = SDL_strdup(i->ifa_name);
if (!iface->name) {
goto failed;
}
char *ptr = SDL_strchr(iface->address->human_readable, '%'); // chop off interface name.
if (ptr) {
*ptr = '\0';
}
} else {
NET_UnrefAddress(iface->broadcast); // just in case.
goto failed;
}
}
succeeded:
if (ifaddr) {
freeifaddrs(ifaddr);
}
SDL_LockRWLockForWriting(interface_rwlock);
NetworkInterfaces *old_interfaces = interfaces;
const int old_num_interfaces = num_interfaces;
interfaces = new_interfaces;
num_interfaces = new_num_interfaces;
SDL_UnlockRWLock(interface_rwlock);
FreeNetworkInterfaces(old_interfaces, old_num_interfaces);
return;
failed:
if (ifaddr) {
freeifaddrs(ifaddr);
}
FreeNetworkInterfaces(new_interfaces, new_num_interfaces);
// if this was a failure case, oh well, old (maybe incorrect) ones will have to stand.
#endif
}
#else
#error implement me for your platform.
#endif
static bool InterfacesReady(void)
{
if (SDL_ShouldInit(&interface_init)) {
if (!interface_rwlock) {
interface_rwlock = SDL_CreateRWLock();
}
if (!interface_rwlock || !InitInterfaceChangeNotifications()) {
SDL_SetInitialized(&interface_init, false);
return false;
}
SDL_SetAtomicInt(&interfaces_have_changed, 1); // force refresh at start.
SDL_SetInitialized(&interface_init, true);
}
// if there were changes, mark it as unchanged and then we'll enumerate. So if it changes again while enumerating, we'll pick that up next time.
if (SDL_CompareAndSwapAtomicInt(&interfaces_have_changed, 1, 0)) {
RefreshInterfaces();
#if 0
SDL_Log("NETWORK INTERFACE REFRESH");
for (int i = 0; i < num_interfaces; i++) {
const NetworkInterfaces *iface = &interfaces[i];
SDL_Log("Interface %d ('%s')", iface->index, iface->name);
SDL_Log(" - address %s", iface->address->human_readable);
if (iface->broadcast) {
SDL_Log(" - broadcast %s", iface->broadcast->human_readable);
}
}
#endif
}
return true;
}
// this blocks!
static NET_Status ResolveAddress(NET_Address *addr)
{
@@ -354,6 +849,8 @@ static NET_Status ResolveAddress(NET_Address *addr)
addr->human_readable = SDL_strdup(buf);
addr->ainfo = ainfo;
addr->type = NET_ADDRTYPE_UNICAST;
return NET_SUCCESS; // success (zero means "still in progress").
}
@@ -479,6 +976,8 @@ static NET_Address *CreateSDLNetAddrFromSockAddr(const struct sockaddr *saddr, S
return NULL;
}
addr->type = NET_ADDRTYPE_UNICAST; // until told otherwise.
addr->human_readable = SDL_strdup(hostbuf);
if (!addr->human_readable) {
freeaddrinfo(addr->ainfo);
@@ -588,6 +1087,26 @@ void NET_Quit(void)
resolver_queue = NULL;
if (SDL_ShouldQuit(&interface_init)) {
QuitInterfaceChangeNotifications();
SDL_SetAtomicInt(&interfaces_have_changed, 0);
if (interfaces) {
FreeNetworkInterfaces(interfaces, num_interfaces);
}
if (interface_rwlock) {
SDL_DestroyRWLock(interface_rwlock);
}
interfaces = NULL;
num_interfaces = 0;
interface_rwlock = NULL;
SDL_SetInitialized(&interface_init, false);
}
// asserts to catch that these shouldn't have ever been set if we never initialized interface_init...
SDL_assert(!interfaces);
SDL_assert(!interface_rwlock);
SDL_assert(num_interfaces == 0);
#ifdef SDL_PLATFORM_WINDOWS
WSACleanup();
#endif
@@ -770,41 +1289,9 @@ void NET_SimulateAddressResolutionLoss(int percent_loss)
SDL_SetAtomicInt(&resolver_percent_loss, SDL_clamp(percent_loss, 0, 100));
}
#ifdef SDL_PLATFORM_ANDROID
typedef struct EnumerateNetAddrTableData
{
NET_Address **retval;
int count;
int real_count;
} EnumerateNetAddrTableData;
static void SDLCALL EnumerateNetAddrTable(void *userdata, SDL_PropertiesID props, const char *name)
{
NET_Address *netaddr = SDL_GetPointerProperty(props, name, NULL);
if (netaddr) {
NET_RefAddress(netaddr);
EnumerateNetAddrTableData *data = (EnumerateNetAddrTableData *) userdata;
SDL_assert(data->real_count < data->count);
data->retval[data->real_count++] = netaddr;
}
}
static void SDLCALL CleanupNetAddrTable(void *userdata, void *value)
{
NET_UnrefAddress((NET_Address *) value);
}
static int SDLCALL CompareNetAddrQsort(const void *a, const void *b)
{
return NET_CompareAddresses(*(NET_Address **) a, *(NET_Address **) b);
}
#endif
NET_Address **NET_GetLocalAddresses(int *num_addresses)
{
int count = 0;
NET_Address **retval = NULL;
int dummy_addresses;
if (!num_addresses) {
num_addresses = &dummy_addresses;
@@ -812,209 +1299,20 @@ NET_Address **NET_GetLocalAddresses(int *num_addresses)
*num_addresses = 0;
#ifdef SDL_PLATFORM_WINDOWS
// !!! FIXME: maybe LoadLibrary(iphlpapi) on the first call, since most
// !!! FIXME: things won't ever use this.
NET_Address **retval = NULL;
// MSDN docs say start with a 15K buffer, which usually works on the first
// try, instead of trying to query for size, allocate, and then retry,
// since this tends to be more expensive.
ULONG buflen = 15 * 1024;
IP_ADAPTER_ADDRESSES *addrs = NULL;
ULONG rc;
do {
SDL_free(addrs);
addrs = (IP_ADAPTER_ADDRESSES *) SDL_malloc(buflen);
if (!addrs) {
return NULL;
}
const ULONG flags = GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
rc = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addrs, &buflen);
} while (rc == ERROR_BUFFER_OVERFLOW);
if (rc != NO_ERROR) {
SetSocketError("GetAdaptersAddresses failed", rc);
SDL_free(addrs);
return NULL;
}
for (IP_ADAPTER_ADDRESSES *i = addrs; i != NULL; i = i->Next) {
for (IP_ADAPTER_UNICAST_ADDRESS *j = i->FirstUnicastAddress; j != NULL; j = j->Next) {
count++;
}
}
retval = (NET_Address **) SDL_calloc(((size_t)count) + 1, sizeof (NET_Address *));
if (!retval) {
SDL_free(addrs);
return NULL;
}
count = 0;
for (IP_ADAPTER_ADDRESSES *i = addrs; i != NULL; i = i->Next) {
for (IP_ADAPTER_UNICAST_ADDRESS *j = i->FirstUnicastAddress; j != NULL; j = j->Next) {
NET_Address *addr = CreateSDLNetAddrFromSockAddr(j->Address.lpSockaddr, j->Address.iSockaddrLength);
if (addr) {
retval[count++] = addr;
if (InterfacesReady()) {
SDL_LockRWLockForReading(interface_rwlock);
const int total = num_interfaces;
retval = (NET_Address **) SDL_malloc((total + 1) * sizeof (NET_Address *));
if (retval) {
for (int i = 0; i < total; i++) {
retval[i] = NET_RefAddress(interfaces[i].address);
}
retval[total] = NULL;
*num_addresses = total;
}
}
SDL_free(addrs);
#elif defined(SDL_PLATFORM_ANDROID)
// Android has getifaddrs() in Android 24, but we still target 21, so do it the hard way.
const int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sock < 0) {
SetLastSocketError("Failed to create AF_NETLINK socket");
return NULL;
}
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
// Ask for the address information.
typedef struct reqstruct
{
struct nlmsghdr header;
struct ifaddrmsg msg;
} reqstruct;
reqstruct req;
SDL_zero(req);
req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
req.header.nlmsg_type = RTM_GETADDR;
req.header.nlmsg_len = NLMSG_LENGTH(sizeof (req.msg));
req.msg.ifa_family = AF_UNSPEC;
if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) {
SetLastSocketError("Failed to send request to AF_NETLINK socket");
close(sock);
return NULL;
}
// this can produce duplicate entries for various reasons; use an SDL_PropertiesID to keep a unique table.
const SDL_PropertiesID addr_table = SDL_CreateProperties();
if (!addr_table) {
close(sock);
return NULL;
}
Uint8 buffer[64 * 1024];
ssize_t br;
while ((br = recv(sock, buffer, sizeof (buffer), 0)) > 0) {
for (const struct nlmsghdr *header = (const struct nlmsghdr *) buffer; NLMSG_OK(header, (size_t) br); header = NLMSG_NEXT(header, br)) {
if (header->nlmsg_type == NLMSG_DONE) {
break; // we got it all.
} else if (header->nlmsg_type == NLMSG_ERROR) {
// uhoh.
NET_FreeLocalAddresses(retval);
retval = NULL;
break;
} else if (header->nlmsg_type == RTM_NEWADDR) {
const struct ifaddrmsg *msg = (const struct ifaddrmsg *) (NLMSG_DATA(header));
size_t payload_len = IFA_PAYLOAD(header);
for (const struct rtattr *attr = IFA_RTA(msg); RTA_OK(attr, payload_len); attr = RTA_NEXT(attr, payload_len)) {
if ((attr->rta_type != IFA_ADDRESS) && (attr->rta_type != IFA_LOCAL)) {
continue;
}
// this gives us the raw bytes of an address, but not the actual sockaddr_* layout, so we have to go with known protocols. :/
AddressStorage addrstorage;
SockLen addrlen = 0;
SDL_zero(addrstorage);
addrstorage.ss_family = msg->ifa_family;
if (addrstorage.ss_family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *) &addrstorage;
SDL_memcpy(&sa->sin_addr, RTA_DATA(attr), RTA_PAYLOAD(attr));
addrlen = sizeof (*sa);
} else if (addrstorage.ss_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &addrstorage;
SDL_memcpy(&sa6->sin6_addr, RTA_DATA(attr), RTA_PAYLOAD(attr));
addrlen = sizeof (*sa6);
} else {
continue; // unknown protocol family.
}
NET_Address *netaddr = CreateSDLNetAddrFromSockAddr((const struct sockaddr *) &addrstorage, addrlen);
if (!netaddr) {
continue;
}
const char *key = NET_GetAddressString(netaddr);
if (!key) {
NET_UnrefAddress(netaddr);
} else {
SDL_SetPointerPropertyWithCleanup(addr_table, key, netaddr, CleanupNetAddrTable, NULL);
count++;
}
}
}
}
}
close(sock);
retval = (NET_Address **) SDL_calloc(count + 1, sizeof (NET_Address *));
if (retval) {
EnumerateNetAddrTableData data = { retval, count, 0 };
SDL_EnumerateProperties(addr_table, EnumerateNetAddrTable, &data);
count = data.real_count;
SDL_qsort(retval, count, sizeof (*retval), CompareNetAddrQsort);
}
SDL_DestroyProperties(addr_table); // will unref all addresses still in the table, but we took a reference too.
#else
struct ifaddrs *ifaddr;
if (getifaddrs(&ifaddr) == -1) {
SDL_SetError("getifaddrs failed: %s", strerror(errno));
return NULL; // oh well.
}
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next) {
if (i->ifa_name != NULL) {
count++;
}
}
retval = (NET_Address **) SDL_calloc(count + 1, sizeof (NET_Address *));
if (!retval) {
if (ifaddr) {
freeifaddrs(ifaddr);
}
return NULL;
}
count = 0;
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next) {
if (i->ifa_name != NULL) {
NET_Address *addr = NULL;
// !!! FIXME: getifaddrs doesn't return the sockaddr length, so we have to go with known protocols. :/
if (i->ifa_addr->sa_family == AF_INET) {
addr = CreateSDLNetAddrFromSockAddr(i->ifa_addr, sizeof (struct sockaddr_in));
} else if (i->ifa_addr->sa_family == AF_INET6) {
addr = CreateSDLNetAddrFromSockAddr(i->ifa_addr, sizeof (struct sockaddr_in6));
}
if (addr) {
retval[count++] = addr;
}
}
}
if (ifaddr) {
freeifaddrs(ifaddr);
}
#endif
*num_addresses = count;
// try to shrink allocation.
void *ptr = SDL_realloc(retval, (((size_t) count) + 1) * sizeof (NET_Address *));
if (ptr) {
retval = (NET_Address **) ptr;
SDL_UnlockRWLock(interface_rwlock);
}
return retval;
@@ -1074,25 +1372,6 @@ struct NET_StreamSocket
Uint64 simulated_failure_until;
};
static int MakeSocketNonblocking(Socket handle)
{
#ifdef SDL_PLATFORM_WINDOWS
DWORD one = 1;
return ioctlsocket(handle, FIONBIO, &one);
#else
return fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
#endif
}
static bool WouldBlock(const int err)
{
#ifdef SDL_PLATFORM_WINDOWS
return (err == WSAEWOULDBLOCK) ? true : false;
#else
return ((err == EWOULDBLOCK) || (err == EAGAIN) || (err == EINPROGRESS)) ? true : false;
#endif
}
NET_StreamSocket *NET_CreateClient(NET_Address *addr, Uint16 port)
{
if (addr == NULL) {
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Simple DirectMedia Layer
# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
# Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
+1 -1
View File
@@ -25,7 +25,7 @@ BEGIN
VALUE "FileDescription", "SDL_net\0"
VALUE "FileVersion", "3, 0, 0, 0\0"
VALUE "InternalName", "SDL_net\0"
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
VALUE "LegalCopyright", "Copyright (C) 2026 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL3_net.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "3, 0, 0, 0\0"