From e5891b0a8d63f0005d7e6d9c8232b15f35a77c58 Mon Sep 17 00:00:00 2001 From: "K. S. Ernest (iFire) Lee" Date: Thu, 5 Dec 2024 12:10:16 -0800 Subject: [PATCH 1/3] Update build.yaml --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 033cc25a..774f9471 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -105,7 +105,7 @@ jobs: fail-fast: false matrix: precision: [double] - platform: [linuxbsd, windows, android, web] + platform: [linuxbsd, windows, web] target: [editor, template_release, template_debug] concurrency: From 9e83132aed72725bf218f22fa44d4d7db12e4bf8 Mon Sep 17 00:00:00 2001 From: "K. S. Ernest (iFire) Lee" Date: Thu, 5 Dec 2024 13:40:53 -0800 Subject: [PATCH 2/3] Build dev build. --- .vscode/tasks.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 17914ca3..4bc9baa1 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -15,7 +15,7 @@ } }, "command": [ - "scons werror=no compiledb=yes dev_build=no generate_bundle=no vulkan=no precision=double target=editor tests=yes debug_symbols=yes" + "scons dev_build=yes werror=no compiledb=yes dev_build=no generate_bundle=no vulkan=no precision=double target=editor tests=yes debug_symbols=yes" ], }, ] From 4e478984ab78aabfaebb97f6633efec8df3ebf16 Mon Sep 17 00:00:00 2001 From: "K. S. Ernest (iFire) Lee" Date: Thu, 5 Dec 2024 09:55:31 -0800 Subject: [PATCH 3/3] git subrepo pull (merge) --force --branch=groups-4.4 godot subrepo: subdir: "godot" merged: "92581f6ca4" upstream: origin: "https://github.com/V-Sekai/godot.git" branch: "groups-4.4" commit: "92581f6ca4" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "cce3d93" git subrepo pull (merge) --force --branch=groups-4.4 godot subrepo: subdir: "godot" merged: "4b7d039b0c" upstream: origin: "https://github.com/V-Sekai/godot.git" branch: "groups-4.4" commit: "4b7d039b0c" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "cce3d93" git subrepo pull (merge) --force godot subrepo: subdir: "godot" merged: "75727b08dc" upstream: origin: "https://github.com/V-Sekai/godot.git" branch: "groups-4.3" commit: "75727b08dc" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "cce3d93" --- godot/.gitrepo | 6 +- godot/COPYRIGHT.txt | 5 + godot/SConstruct | 2 - godot/core/config/engine.cpp | 3 + godot/core/os/os.cpp | 4 + godot/core/string/ustring.cpp | 63 +- godot/doc/classes/PackedFloat32Array.xml | 2 +- godot/doc/classes/PackedFloat64Array.xml | 2 +- godot/doc/classes/PackedInt32Array.xml | 2 +- godot/doc/classes/PackedInt64Array.xml | 2 +- godot/doc/classes/ShaderIncludeDB.xml | 33 + godot/doc/classes/SurfaceTool.xml | 2 +- .../d3d12/rendering_device_driver_d3d12.cpp | 10 + godot/drivers/gles3/storage/light_storage.cpp | 2 +- godot/editor/connections_dialog.cpp | 2 +- godot/editor/editor_inspector.cpp | 6 + godot/editor/editor_inspector.h | 2 + godot/editor/editor_node.cpp | 16 +- godot/editor/editor_properties.cpp | 10 + .../editor/editor_property_name_processor.cpp | 1 + .../editor/export/export_template_manager.cpp | 10 +- godot/editor/filesystem_dock.cpp | 52 +- godot/editor/filesystem_dock.h | 1 + godot/editor/gui/editor_file_dialog.cpp | 21 +- godot/editor/gui/editor_file_dialog.h | 2 + .../plugins/canvas_item_editor_plugin.cpp | 21 - .../plugins/gdextension_export_plugin.h | 1 + .../gizmos/reflection_probe_gizmo_plugin.cpp | 23 +- .../editor/project_manager/project_dialog.cpp | 24 +- godot/editor/themes/editor_fonts.cpp | 4 +- godot/modules/camera/config.py | 4 + godot/modules/csg/csg_shape.cpp | 20 +- .../audio_stream_interactive.cpp | 11 +- .../audio_stream_interactive.h | 2 +- .../audio_stream_synchronized.cpp | 12 + .../audio_stream_synchronized.h | 1 + godot/modules/mbedtls/crypto_mbedtls.cpp | 7 + godot/modules/openxr/SCsub | 6 +- .../raycast/raycast_occlusion_cull.cpp | 2 +- godot/modules/svg/SCsub | 25 +- godot/modules/svg/config.py | 10 - .../doc_classes/ResourceImporterLottie.xml | 125 - .../svg/editor/resource_importer_lottie.cpp | 262 - godot/modules/svg/register_types.cpp | 16 - godot/modules/webrtc/SCsub | 144 +- .../webrtc/webrtc_lib_data_channel.cpp | 200 - .../modules/webrtc/webrtc_lib_data_channel.h | 95 - .../webrtc/webrtc_lib_peer_connection.cpp | 303 - .../webrtc/webrtc_lib_peer_connection.h | 111 - .../modules/webrtc/webrtc_peer_connection.cpp | 7 - godot/platform/linuxbsd/detect.py | 7 +- .../EditorExportPlatformLinuxBSD.xml | 2 +- .../linuxbsd/export/export_plugin.cpp | 4 +- godot/platform/linuxbsd/os_linuxbsd.cpp | 2 +- .../linuxbsd/platform_linuxbsd_builders.py | 6 +- .../linuxbsd/wayland/wayland_thread.cpp | 6 +- godot/platform_methods.py | 3 +- godot/scene/gui/rich_text_label.cpp | 50 +- godot/scene/gui/rich_text_label.h | 2 + godot/scene/resources/3d/primitive_meshes.cpp | 125 +- godot/scene/resources/SCsub | 8 +- godot/scene/resources/audio_stream_wav.cpp | 44 +- godot/scene/resources/audio_stream_wav.h | 31 +- .../audio/effects/audio_effect_record.cpp | 6 + godot/servers/register_server_types.cpp | 2 + .../forward_mobile/render_forward_mobile.cpp | 15 +- .../scene_shader_forward_mobile.cpp | 8 +- .../scene_shader_forward_mobile.h | 20 +- .../renderer_rd/renderer_scene_render_rd.cpp | 11 + .../rendering/renderer_rd/shader_rd.cpp | 33 +- .../rendering/renderer_rd/shaders/SCsub | 10 +- .../shaders/canvas_uniforms_inc.glsl | 2 +- .../scene_forward_clustered.glsl | 12 +- .../forward_mobile/scene_forward_mobile.glsl | 29 +- .../scene_forward_mobile_inc.glsl | 55 +- .../shaders/scene_forward_lights_inc.glsl | 453 +- .../renderer_rd/storage_rd/light_storage.cpp | 2 +- .../renderer_rd/storage_rd/light_storage.h | 10 + godot/servers/rendering/rendering_device.cpp | 7 +- .../rendering/rendering_device_binds.cpp | 16 +- godot/servers/rendering/shader_include_db.cpp | 115 + .../rendering/shader_include_db.h} | 39 +- godot/tests/scene/test_audio_stream_wav.h | 27 +- godot/tests/servers/test_text_server.h | 8 +- godot/thirdparty/README.md | 91 +- godot/thirdparty/fonts/LICENSE.Vazirmatn.txt | 93 + .../fonts/NotoNaskhArabicUI_Bold.woff2 | Bin 53860 -> 0 bytes .../fonts/NotoNaskhArabicUI_Regular.woff2 | Bin 53352 -> 0 bytes godot/thirdparty/fonts/Vazirmatn_Bold.woff2 | Bin 0 -> 51184 bytes .../thirdparty/fonts/Vazirmatn_Regular.woff2 | Bin 0 -> 50596 bytes godot/thirdparty/libdatachannel/LICENSE | 373 - .../libdatachannel/deps/libjuice/LICENSE | 373 - .../deps/libjuice/include/juice/juice.h | 176 - .../libdatachannel/deps/libjuice/src/addr.c | 310 - .../libdatachannel/deps/libjuice/src/addr.h | 45 - .../libdatachannel/deps/libjuice/src/agent.c | 2553 --- .../libdatachannel/deps/libjuice/src/agent.h | 236 - .../libdatachannel/deps/libjuice/src/base64.c | 90 - .../libdatachannel/deps/libjuice/src/base64.h | 24 - .../libdatachannel/deps/libjuice/src/conn.c | 249 - .../libdatachannel/deps/libjuice/src/conn.h | 44 - .../deps/libjuice/src/conn_mux.c | 541 - .../deps/libjuice/src/conn_mux.h | 32 - .../deps/libjuice/src/conn_poll.c | 431 - .../deps/libjuice/src/conn_poll.h | 32 - .../deps/libjuice/src/conn_thread.c | 279 - .../deps/libjuice/src/conn_thread.h | 32 - .../deps/libjuice/src/const_time.c | 34 - .../deps/libjuice/src/const_time.h | 18 - .../libdatachannel/deps/libjuice/src/crc32.c | 38 - .../libdatachannel/deps/libjuice/src/crc32.h | 21 - .../libdatachannel/deps/libjuice/src/hash.c | 59 - .../libdatachannel/deps/libjuice/src/hash.h | 23 - .../libdatachannel/deps/libjuice/src/hmac.c | 43 - .../libdatachannel/deps/libjuice/src/hmac.h | 21 - .../libdatachannel/deps/libjuice/src/ice.c | 417 - .../libdatachannel/deps/libjuice/src/ice.h | 104 - .../libdatachannel/deps/libjuice/src/juice.c | 207 - .../libdatachannel/deps/libjuice/src/log.c | 143 - .../libdatachannel/deps/libjuice/src/log.h | 42 - .../deps/libjuice/src/picohash.h | 741 - .../libdatachannel/deps/libjuice/src/random.c | 126 - .../libdatachannel/deps/libjuice/src/random.h | 21 - .../libdatachannel/deps/libjuice/src/server.c | 1144 -- .../libdatachannel/deps/libjuice/src/server.h | 123 - .../libdatachannel/deps/libjuice/src/socket.h | 132 - .../libdatachannel/deps/libjuice/src/stun.c | 1236 -- .../libdatachannel/deps/libjuice/src/stun.h | 376 - .../libdatachannel/deps/libjuice/src/thread.h | 148 - .../deps/libjuice/src/timestamp.c | 45 - .../deps/libjuice/src/timestamp.h | 20 - .../libdatachannel/deps/libjuice/src/turn.c | 495 - .../libdatachannel/deps/libjuice/src/turn.h | 111 - .../libdatachannel/deps/libjuice/src/udp.c | 604 - .../libdatachannel/deps/libjuice/src/udp.h | 33 - .../libdatachannel/deps/plog/LICENSE | 21 - .../include/plog/Appenders/AndroidAppender.h | 47 - .../include/plog/Appenders/ArduinoAppender.h | 23 - .../plog/Appenders/ColorConsoleAppender.h | 108 - .../include/plog/Appenders/ConsoleAppender.h | 83 - .../plog/Appenders/DebugOutputAppender.h | 16 - .../include/plog/Appenders/DynamicAppender.h | 42 - .../include/plog/Appenders/EventLogAppender.h | 117 - .../plog/include/plog/Appenders/IAppender.h | 16 - .../plog/Appenders/RollingFileAppender.h | 148 - .../plog/Converters/NativeEOLConverter.h | 44 - .../include/plog/Converters/UTF8Converter.h | 28 - .../include/plog/Formatters/CsvFormatter.h | 57 - .../plog/Formatters/FuncMessageFormatter.h | 23 - .../plog/Formatters/MessageOnlyFormatter.h | 23 - .../include/plog/Formatters/TxtFormatter.h | 36 - .../deps/plog/include/plog/Helpers/AscDump.h | 40 - .../deps/plog/include/plog/Helpers/HexDump.h | 79 - .../deps/plog/include/plog/Helpers/PrintVar.h | 24 - .../deps/plog/include/plog/Init.h | 17 - .../plog/Initializers/ConsoleInitializer.h | 22 - .../Initializers/RollingFileInitializer.h | 80 - .../deps/plog/include/plog/Log.h | 242 - .../deps/plog/include/plog/Logger.h | 84 - .../deps/plog/include/plog/Record.h | 435 - .../deps/plog/include/plog/Severity.h | 61 - .../deps/plog/include/plog/Util.h | 616 - .../deps/plog/include/plog/WinApi.h | 175 - .../libdatachannel/deps/usrsctp/LICENSE.md | 27 - .../deps/usrsctp/usrsctplib/netinet/sctp.h | 676 - .../usrsctp/usrsctplib/netinet/sctp_asconf.c | 3531 ---- .../usrsctp/usrsctplib/netinet/sctp_asconf.h | 94 - .../usrsctp/usrsctplib/netinet/sctp_auth.c | 2302 --- .../usrsctp/usrsctplib/netinet/sctp_auth.h | 213 - .../usrsctplib/netinet/sctp_bsd_addr.c | 989 - .../usrsctplib/netinet/sctp_bsd_addr.h | 72 - .../usrsctp/usrsctplib/netinet/sctp_callout.c | 249 - .../usrsctp/usrsctplib/netinet/sctp_callout.h | 119 - .../usrsctplib/netinet/sctp_cc_functions.c | 2493 --- .../usrsctplib/netinet/sctp_constants.h | 1068 -- .../usrsctp/usrsctplib/netinet/sctp_crc32.c | 821 - .../usrsctp/usrsctplib/netinet/sctp_crc32.h | 56 - .../usrsctp/usrsctplib/netinet/sctp_header.h | 603 - .../usrsctp/usrsctplib/netinet/sctp_indata.c | 5793 ------ .../usrsctp/usrsctplib/netinet/sctp_indata.h | 121 - .../usrsctp/usrsctplib/netinet/sctp_input.c | 6486 ------- .../usrsctp/usrsctplib/netinet/sctp_input.h | 66 - .../usrsctplib/netinet/sctp_lock_userspace.h | 244 - .../deps/usrsctp/usrsctplib/netinet/sctp_os.h | 89 - .../usrsctplib/netinet/sctp_os_userspace.h | 1153 -- .../usrsctp/usrsctplib/netinet/sctp_output.c | 15088 ---------------- .../usrsctp/usrsctplib/netinet/sctp_output.h | 240 - .../usrsctp/usrsctplib/netinet/sctp_pcb.c | 8136 --------- .../usrsctp/usrsctplib/netinet/sctp_pcb.h | 881 - .../usrsctp/usrsctplib/netinet/sctp_peeloff.c | 302 - .../usrsctp/usrsctplib/netinet/sctp_peeloff.h | 70 - .../usrsctplib/netinet/sctp_process_lock.h | 693 - .../usrsctp/usrsctplib/netinet/sctp_sha1.c | 347 - .../usrsctp/usrsctplib/netinet/sctp_sha1.h | 94 - .../usrsctplib/netinet/sctp_ss_functions.c | 1128 -- .../usrsctp/usrsctplib/netinet/sctp_structs.h | 1296 -- .../usrsctp/usrsctplib/netinet/sctp_sysctl.c | 1669 -- .../usrsctp/usrsctplib/netinet/sctp_sysctl.h | 633 - .../usrsctp/usrsctplib/netinet/sctp_timer.c | 1641 -- .../usrsctp/usrsctplib/netinet/sctp_timer.h | 103 - .../usrsctp/usrsctplib/netinet/sctp_uio.h | 1358 -- .../usrsctplib/netinet/sctp_userspace.c | 425 - .../usrsctp/usrsctplib/netinet/sctp_usrreq.c | 9017 --------- .../usrsctp/usrsctplib/netinet/sctp_var.h | 458 - .../usrsctp/usrsctplib/netinet/sctputil.c | 8707 --------- .../usrsctp/usrsctplib/netinet/sctputil.h | 386 - .../usrsctplib/netinet6/sctp6_usrreq.c | 1750 -- .../usrsctp/usrsctplib/netinet6/sctp6_var.h | 87 - .../deps/usrsctp/usrsctplib/user_atomic.h | 315 - .../usrsctp/usrsctplib/user_environment.c | 384 - .../usrsctp/usrsctplib/user_environment.h | 123 - .../deps/usrsctp/usrsctplib/user_inpcb.h | 373 - .../deps/usrsctp/usrsctplib/user_ip6_var.h | 124 - .../deps/usrsctp/usrsctplib/user_ip_icmp.h | 225 - .../deps/usrsctp/usrsctplib/user_malloc.h | 203 - .../deps/usrsctp/usrsctplib/user_mbuf.c | 1589 -- .../deps/usrsctp/usrsctplib/user_mbuf.h | 412 - .../deps/usrsctp/usrsctplib/user_queue.h | 639 - .../usrsctp/usrsctplib/user_recv_thread.c | 1566 -- .../usrsctp/usrsctplib/user_recv_thread.h | 34 - .../deps/usrsctp/usrsctplib/user_route.h | 130 - .../deps/usrsctp/usrsctplib/user_socket.c | 3571 ---- .../deps/usrsctp/usrsctplib/user_socketvar.h | 527 - .../deps/usrsctp/usrsctplib/user_uma.h | 96 - .../deps/usrsctp/usrsctplib/usrsctp.h | 1329 -- .../include/rtc/aacrtppacketizer.hpp | 60 - .../include/rtc/av1packetizationhandler.hpp | 32 - .../include/rtc/av1rtppacketizer.hpp | 56 - .../libdatachannel/include/rtc/candidate.hpp | 77 - .../libdatachannel/include/rtc/channel.hpp | 61 - .../libdatachannel/include/rtc/common.hpp | 221 - .../include/rtc/configuration.hpp | 93 - .../include/rtc/datachannel.hpp | 80 - .../include/rtc/description.hpp | 324 - .../include/rtc/exception_wrapper_godot.hpp | 17 - .../libdatachannel/include/rtc/global.hpp | 59 - .../include/rtc/h264packetizationhandler.hpp | 32 - .../include/rtc/h264rtppacketizer.hpp | 54 - .../include/rtc/h265nalunit.hpp | 188 - .../include/rtc/h265packetizationhandler.hpp | 32 - .../include/rtc/h265rtppacketizer.hpp | 54 - .../include/rtc/mediachainablehandler.hpp | 48 - .../include/rtc/mediahandler.hpp | 42 - .../include/rtc/mediahandlerelement.hpp | 114 - .../include/rtc/mediahandlerrootelement.hpp | 36 - .../libdatachannel/include/rtc/message.hpp | 76 - .../libdatachannel/include/rtc/nalunit.hpp | 226 - .../include/rtc/opuspacketizationhandler.hpp | 32 - .../include/rtc/opusrtppacketizer.hpp | 50 - .../include/rtc/peerconnection.hpp | 135 - .../include/rtc/reliability.hpp | 28 - .../libdatachannel/include/rtc/rtc.h | 470 - .../libdatachannel/include/rtc/rtc.hpp | 43 - .../include/rtc/rtcpnackresponder.hpp | 85 - .../include/rtc/rtcpreceivingsession.hpp | 49 - .../include/rtc/rtcpsrreporter.hpp | 47 - .../libdatachannel/include/rtc/rtp.hpp | 379 - .../include/rtc/rtppacketizationconfig.hpp | 99 - .../include/rtc/rtppacketizer.hpp | 47 - .../libdatachannel/include/rtc/track.hpp | 59 - .../libdatachannel/include/rtc/utils.hpp | 159 - .../libdatachannel/include/rtc/websocket.hpp | 72 - .../include/rtc/websocketserver.hpp | 55 - .../patches/avoid_exceptions.patch | 4948 ----- .../patches/disable_logging.patch | 163 - .../patches/disable_media.patch | 2335 --- .../libdatachannel/patches/fix_mingw.patch | 43 - .../patches/mbedtls_optional_apis.patch | 46 - .../patches/virtual_destructor.patch | 39 - .../libdatachannel/src/candidate.cpp | 306 - .../thirdparty/libdatachannel/src/channel.cpp | 62 - .../libdatachannel/src/configuration.cpp | 170 - .../libdatachannel/src/datachannel.cpp | 57 - .../libdatachannel/src/description.cpp | 1345 -- .../src/exception_wrapper_godot.cpp | 95 - .../thirdparty/libdatachannel/src/global.cpp | 131 - .../libdatachannel/src/impl/certificate.cpp | 507 - .../libdatachannel/src/impl/certificate.hpp | 77 - .../libdatachannel/src/impl/channel.cpp | 96 - .../libdatachannel/src/impl/channel.hpp | 52 - .../libdatachannel/src/impl/datachannel.cpp | 369 - .../libdatachannel/src/impl/datachannel.hpp | 93 - .../libdatachannel/src/impl/dtlstransport.cpp | 1113 -- .../libdatachannel/src/impl/dtlstransport.hpp | 124 - .../libdatachannel/src/impl/http.hpp | 30 - .../src/impl/httpproxytransport.hpp | 50 - .../libdatachannel/src/impl/icetransport.cpp | 909 - .../libdatachannel/src/impl/icetransport.hpp | 115 - .../libdatachannel/src/impl/init.cpp | 187 - .../libdatachannel/src/impl/init.hpp | 56 - .../libdatachannel/src/impl/internals.hpp | 52 - .../libdatachannel/src/impl/logcounter.cpp | 40 - .../libdatachannel/src/impl/logcounter.hpp | 41 - .../src/impl/peerconnection.cpp | 1355 -- .../src/impl/peerconnection.hpp | 173 - .../src/impl/pollinterrupter.hpp | 44 - .../libdatachannel/src/impl/pollservice.hpp | 82 - .../libdatachannel/src/impl/processor.cpp | 42 - .../libdatachannel/src/impl/processor.hpp | 76 - .../libdatachannel/src/impl/queue.hpp | 129 - .../libdatachannel/src/impl/sctptransport.cpp | 1000 - .../libdatachannel/src/impl/sctptransport.hpp | 135 - .../libdatachannel/src/impl/sha.hpp | 25 - .../libdatachannel/src/impl/socket.hpp | 132 - .../libdatachannel/src/impl/tcpserver.hpp | 48 - .../libdatachannel/src/impl/tcptransport.hpp | 80 - .../libdatachannel/src/impl/threadpool.cpp | 97 - .../libdatachannel/src/impl/threadpool.hpp | 113 - .../libdatachannel/src/impl/tls.cpp | 231 - .../libdatachannel/src/impl/tls.hpp | 96 - .../libdatachannel/src/impl/tlstransport.hpp | 102 - .../libdatachannel/src/impl/track.hpp | 78 - .../libdatachannel/src/impl/transport.cpp | 85 - .../libdatachannel/src/impl/transport.hpp | 60 - .../libdatachannel/src/impl/utils.cpp | 175 - .../libdatachannel/src/impl/utils.hpp | 71 - .../src/impl/verifiedtlstransport.hpp | 29 - .../libdatachannel/src/impl/websocket.hpp | 93 - .../src/impl/websocketserver.hpp | 55 - .../libdatachannel/src/impl/wshandshake.hpp | 68 - .../libdatachannel/src/impl/wstransport.hpp | 87 - .../thirdparty/libdatachannel/src/message.cpp | 68 - .../libdatachannel/src/peerconnection.cpp | 471 - .../linuxbsd_headers/alsa/asoundlib.h | 4 + .../alsa/patches/freebsd_endian.diff | 16 + .../thirdparty/misc/patches/qoa-min-fix.patch | 53 - godot/thirdparty/misc/qoa.c | 4 + godot/thirdparty/misc/qoa.h | 24 +- godot/thirdparty/thorvg/inc/config.h | 2 +- godot/thirdparty/thorvg/inc/thorvg.h | 3 +- .../pr2740-renderer-crash-hotfix.patch | 45 + ...ert-tvgLines-bezier-precision-change.patch | 13 + .../src/loaders/lottie/rapidjson/allocators.h | 693 - .../lottie/rapidjson/cursorstreamwrapper.h | 78 - .../src/loaders/lottie/rapidjson/document.h | 3043 ---- .../loaders/lottie/rapidjson/encodedstream.h | 299 - .../src/loaders/lottie/rapidjson/encodings.h | 716 - .../src/loaders/lottie/rapidjson/error/en.h | 176 - .../loaders/lottie/rapidjson/error/error.h | 285 - .../loaders/lottie/rapidjson/filereadstream.h | 99 - .../lottie/rapidjson/filewritestream.h | 104 - .../thorvg/src/loaders/lottie/rapidjson/fwd.h | 151 - .../lottie/rapidjson/internal/biginteger.h | 297 - .../loaders/lottie/rapidjson/internal/clzll.h | 71 - .../loaders/lottie/rapidjson/internal/diyfp.h | 261 - .../loaders/lottie/rapidjson/internal/dtoa.h | 249 - .../lottie/rapidjson/internal/ieee754.h | 78 - .../loaders/lottie/rapidjson/internal/itoa.h | 308 - .../loaders/lottie/rapidjson/internal/meta.h | 186 - .../loaders/lottie/rapidjson/internal/pow10.h | 55 - .../loaders/lottie/rapidjson/internal/regex.h | 739 - .../loaders/lottie/rapidjson/internal/stack.h | 232 - .../lottie/rapidjson/internal/strfunc.h | 83 - .../lottie/rapidjson/internal/strtod.h | 293 - .../loaders/lottie/rapidjson/internal/swap.h | 46 - .../loaders/lottie/rapidjson/istreamwrapper.h | 128 - .../loaders/lottie/rapidjson/memorybuffer.h | 70 - .../loaders/lottie/rapidjson/memorystream.h | 71 - .../lottie/rapidjson/msinttypes/inttypes.h | 316 - .../lottie/rapidjson/msinttypes/stdint.h | 300 - .../loaders/lottie/rapidjson/ostreamwrapper.h | 81 - .../src/loaders/lottie/rapidjson/pointer.h | 1470 -- .../loaders/lottie/rapidjson/prettywriter.h | 277 - .../src/loaders/lottie/rapidjson/rapidjson.h | 742 - .../src/loaders/lottie/rapidjson/reader.h | 2246 --- .../src/loaders/lottie/rapidjson/schema.h | 3262 ---- .../src/loaders/lottie/rapidjson/stream.h | 223 - .../loaders/lottie/rapidjson/stringbuffer.h | 121 - .../thorvg/src/loaders/lottie/rapidjson/uri.h | 481 - .../src/loaders/lottie/rapidjson/writer.h | 710 - .../thorvg/src/loaders/lottie/thorvg_lottie.h | 94 - .../src/loaders/lottie/tvgLottieAnimation.cpp | 88 - .../src/loaders/lottie/tvgLottieBuilder.cpp | 1434 -- .../src/loaders/lottie/tvgLottieBuilder.h | 134 - .../src/loaders/lottie/tvgLottieCommon.h | 98 - .../loaders/lottie/tvgLottieExpressions.cpp | 1423 -- .../src/loaders/lottie/tvgLottieExpressions.h | 168 - .../loaders/lottie/tvgLottieInterpolator.cpp | 140 - .../loaders/lottie/tvgLottieInterpolator.h | 45 - .../src/loaders/lottie/tvgLottieLoader.cpp | 422 - .../src/loaders/lottie/tvgLottieLoader.h | 84 - .../src/loaders/lottie/tvgLottieModel.cpp | 500 - .../src/loaders/lottie/tvgLottieModel.h | 899 - .../src/loaders/lottie/tvgLottieModifier.cpp | 395 - .../src/loaders/lottie/tvgLottieModifier.h | 71 - .../src/loaders/lottie/tvgLottieParser.cpp | 1511 -- .../src/loaders/lottie/tvgLottieParser.h | 125 - .../loaders/lottie/tvgLottieParserHandler.cpp | 235 - .../loaders/lottie/tvgLottieParserHandler.h | 200 - .../src/loaders/lottie/tvgLottieProperty.h | 838 - .../loaders/lottie/tvgLottieRenderPooler.h | 58 - .../thorvg/src/loaders/svg/tvgSvgLoader.cpp | 28 +- .../src/renderer/sw_engine/tvgSwCommon.h | 8 +- .../renderer/sw_engine/tvgSwPostEffect.cpp | 307 +- .../src/renderer/sw_engine/tvgSwRaster.cpp | 39 +- .../src/renderer/sw_engine/tvgSwRasterC.h | 32 + .../src/renderer/sw_engine/tvgSwRenderer.cpp | 23 +- .../src/renderer/sw_engine/tvgSwRenderer.h | 2 +- .../thorvg/src/renderer/tvgRender.h | 37 +- .../thorvg/src/renderer/tvgSaver.cpp | 1 + .../thorvg/src/renderer/tvgScene.cpp | 12 +- .../thirdparty/thorvg/src/renderer/tvgScene.h | 3 +- godot/thirdparty/thorvg/update-thorvg.sh | 6 +- godot/thirdparty/ufbx/ufbx.c | 1898 +- godot/thirdparty/ufbx/ufbx.h | 120 +- 405 files changed, 2861 insertions(+), 162080 deletions(-) create mode 100644 godot/doc/classes/ShaderIncludeDB.xml delete mode 100644 godot/modules/svg/doc_classes/ResourceImporterLottie.xml delete mode 100644 godot/modules/svg/editor/resource_importer_lottie.cpp delete mode 100644 godot/modules/webrtc/webrtc_lib_data_channel.cpp delete mode 100644 godot/modules/webrtc/webrtc_lib_data_channel.h delete mode 100644 godot/modules/webrtc/webrtc_lib_peer_connection.cpp delete mode 100644 godot/modules/webrtc/webrtc_lib_peer_connection.h create mode 100644 godot/servers/rendering/shader_include_db.cpp rename godot/{modules/svg/editor/resource_importer_lottie.h => servers/rendering/shader_include_db.h} (56%) create mode 100644 godot/thirdparty/fonts/LICENSE.Vazirmatn.txt delete mode 100644 godot/thirdparty/fonts/NotoNaskhArabicUI_Bold.woff2 delete mode 100644 godot/thirdparty/fonts/NotoNaskhArabicUI_Regular.woff2 create mode 100644 godot/thirdparty/fonts/Vazirmatn_Bold.woff2 create mode 100644 godot/thirdparty/fonts/Vazirmatn_Regular.woff2 delete mode 100644 godot/thirdparty/libdatachannel/LICENSE delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/LICENSE delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/include/juice/juice.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/addr.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/addr.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/agent.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/agent.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/base64.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/base64.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/hash.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/hash.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/ice.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/ice.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/juice.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/log.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/log.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/picohash.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/random.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/random.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/server.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/server.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/socket.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/stun.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/stun.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/thread.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/turn.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/turn.h delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/udp.c delete mode 100644 godot/thirdparty/libdatachannel/deps/libjuice/src/udp.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/LICENSE delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/AndroidAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ArduinoAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ColorConsoleAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ConsoleAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DebugOutputAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DynamicAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/EventLogAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/IAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/RollingFileAppender.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/NativeEOLConverter.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/UTF8Converter.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/CsvFormatter.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/FuncMessageFormatter.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/MessageOnlyFormatter.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/TxtFormatter.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/AscDump.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/HexDump.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/PrintVar.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Init.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/ConsoleInitializer.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/RollingFileInitializer.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Log.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Logger.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Record.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Severity.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/Util.h delete mode 100644 godot/thirdparty/libdatachannel/deps/plog/include/plog/WinApi.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/LICENSE.md delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_cc_functions.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_constants.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_header.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_lock_userspace.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os_userspace.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_process_lock.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_ss_functions.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_structs.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_uio.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_userspace.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_usrreq.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_var.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_usrreq.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_var.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_atomic.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_inpcb.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip6_var.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip_icmp.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_malloc.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_queue.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_route.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socket.c delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socketvar.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_uma.h delete mode 100644 godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/usrsctp.h delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/aacrtppacketizer.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/av1packetizationhandler.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/av1rtppacketizer.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/candidate.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/channel.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/common.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/configuration.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/datachannel.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/description.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/exception_wrapper_godot.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/global.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/h264packetizationhandler.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/h264rtppacketizer.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/h265nalunit.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/h265packetizationhandler.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/h265rtppacketizer.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/mediachainablehandler.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/mediahandler.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/mediahandlerrootelement.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/message.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/nalunit.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/opuspacketizationhandler.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/opusrtppacketizer.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/peerconnection.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/reliability.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtc.h delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtc.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtcpnackresponder.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtcpreceivingsession.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtcpsrreporter.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtp.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtppacketizationconfig.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/track.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/utils.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/websocket.hpp delete mode 100644 godot/thirdparty/libdatachannel/include/rtc/websocketserver.hpp delete mode 100644 godot/thirdparty/libdatachannel/patches/avoid_exceptions.patch delete mode 100644 godot/thirdparty/libdatachannel/patches/disable_logging.patch delete mode 100644 godot/thirdparty/libdatachannel/patches/disable_media.patch delete mode 100644 godot/thirdparty/libdatachannel/patches/fix_mingw.patch delete mode 100644 godot/thirdparty/libdatachannel/patches/mbedtls_optional_apis.patch delete mode 100644 godot/thirdparty/libdatachannel/patches/virtual_destructor.patch delete mode 100644 godot/thirdparty/libdatachannel/src/candidate.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/channel.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/configuration.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/datachannel.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/description.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/global.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/certificate.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/certificate.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/channel.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/channel.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/datachannel.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/datachannel.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/dtlstransport.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/dtlstransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/http.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/httpproxytransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/icetransport.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/icetransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/init.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/init.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/internals.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/logcounter.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/logcounter.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/peerconnection.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/peerconnection.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/pollinterrupter.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/pollservice.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/processor.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/processor.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/queue.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/sctptransport.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/sctptransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/sha.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/socket.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/tcpserver.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/tcptransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/threadpool.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/threadpool.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/tls.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/tls.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/tlstransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/track.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/transport.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/transport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/utils.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/utils.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/verifiedtlstransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/websocket.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/websocketserver.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/wshandshake.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/impl/wstransport.hpp delete mode 100644 godot/thirdparty/libdatachannel/src/message.cpp delete mode 100644 godot/thirdparty/libdatachannel/src/peerconnection.cpp create mode 100644 godot/thirdparty/linuxbsd_headers/alsa/patches/freebsd_endian.diff delete mode 100644 godot/thirdparty/misc/patches/qoa-min-fix.patch create mode 100644 godot/thirdparty/misc/qoa.c create mode 100644 godot/thirdparty/thorvg/patches/pr2740-renderer-crash-hotfix.patch create mode 100644 godot/thirdparty/thorvg/patches/revert-tvgLines-bezier-precision-change.patch delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/allocators.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/cursorstreamwrapper.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/document.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodedstream.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodings.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/en.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/error.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filereadstream.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filewritestream.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/fwd.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/biginteger.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/clzll.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/diyfp.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/dtoa.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/ieee754.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/itoa.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/meta.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/pow10.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/regex.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/stack.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strfunc.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strtod.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/swap.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/istreamwrapper.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorybuffer.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorystream.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/inttypes.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/stdint.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/ostreamwrapper.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/pointer.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/prettywriter.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/rapidjson.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/reader.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/schema.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stream.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stringbuffer.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/uri.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/writer.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/thorvg_lottie.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieAnimation.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieCommon.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.cpp delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieProperty.h delete mode 100644 godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieRenderPooler.h diff --git a/godot/.gitrepo b/godot/.gitrepo index dd98344f..238310fd 100644 --- a/godot/.gitrepo +++ b/godot/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = https://github.com/V-Sekai/godot.git - branch = groups-4.4 - commit = 44d2bc3ab61be9576a941f9c5931db4426215af4 - parent = 671983d2cb7b4c5ad5e3c70fc81624058be03227 + branch = groups-4.3 + commit = 75727b08dc2c675f5912562e89aa80bca91de269 + parent = 53928cca22d1f63cdf3062282dfbeac8eb98cabf method = merge cmdver = 0.4.9 diff --git a/godot/COPYRIGHT.txt b/godot/COPYRIGHT.txt index 0498f335..d2d9794b 100644 --- a/godot/COPYRIGHT.txt +++ b/godot/COPYRIGHT.txt @@ -247,6 +247,11 @@ Comment: Noto Sans font Copyright: 2012, Google Inc. License: OFL-1.1 +Files: ./thirdparty/fonts/Vazirmatn*.woff2 +Comment: Vazirmatn font +Copyright: 2015, The Vazirmatn Project Authors. +License: OFL-1.1 + Files: ./thirdparty/freetype/ Comment: The FreeType Project Copyright: 1996-2023, David Turner, Robert Wilhelm, and Werner Lemberg. diff --git a/godot/SConstruct b/godot/SConstruct index c168db40..15598740 100644 --- a/godot/SConstruct +++ b/godot/SConstruct @@ -215,7 +215,6 @@ opts.Add(BoolVariable("threads", "Enable threading support", True)) # Components opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True)) opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double"))) -opts.Add(BoolVariable("libdatachannel", "Enable the built-in libdatachannel webrtc implementation", True)) opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True)) opts.Add(BoolVariable("brotli", "Enable Brotli for decompresson and WOFF2 fonts support", True)) opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver on supported platforms", False)) @@ -286,7 +285,6 @@ opts.Add(BoolVariable("builtin_glslang", "Use the built-in glslang library", Tru opts.Add(BoolVariable("builtin_graphite", "Use the built-in Graphite library", True)) opts.Add(BoolVariable("builtin_harfbuzz", "Use the built-in HarfBuzz library", True)) opts.Add(BoolVariable("builtin_icu4c", "Use the built-in ICU library", True)) -opts.Add(BoolVariable("builtin_libdatachannel", "Use the built-in libdatachannel library", True)) opts.Add(BoolVariable("builtin_libogg", "Use the built-in libogg library", True)) opts.Add(BoolVariable("builtin_libpng", "Use the built-in libpng library", True)) opts.Add(BoolVariable("builtin_libtheora", "Use the built-in libtheora library", True)) diff --git a/godot/core/config/engine.cpp b/godot/core/config/engine.cpp index aac048e9..250f39b0 100644 --- a/godot/core/config/engine.cpp +++ b/godot/core/config/engine.cpp @@ -248,6 +248,9 @@ String Engine::get_architecture_name() const { return "ppc"; #endif +#elif defined(__loongarch64) + return "loongarch64"; + #elif defined(__wasm__) #if defined(__wasm64__) return "wasm64"; diff --git a/godot/core/os/os.cpp b/godot/core/os/os.cpp index 4a833645..ff713ab3 100644 --- a/godot/core/os/os.cpp +++ b/godot/core/os/os.cpp @@ -518,6 +518,10 @@ bool OS::has_feature(const String &p_feature) { if (p_feature == "wasm") { return true; } +#elif defined(__loongarch64) + if (p_feature == "loongarch64") { + return true; + } #endif #if defined(IOS_SIMULATOR) diff --git a/godot/core/string/ustring.cpp b/godot/core/string/ustring.cpp index 0e553a56..9238e74a 100644 --- a/godot/core/string/ustring.cpp +++ b/godot/core/string/ustring.cpp @@ -65,6 +65,15 @@ const char16_t Char16String::_null = 0; const char32_t String::_null = 0; const char32_t String::_replacement_char = 0xfffd; +// strlen equivalent function for char32_t * arguments. +_FORCE_INLINE_ size_t strlen(const char32_t *p_str) { + const char32_t *ptr = p_str; + while (*ptr != 0) { + ++ptr; + } + return ptr - p_str; +} + bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) { const String &s = p_s; int beg = CLAMP(p_col, 0, s.length()); @@ -424,11 +433,7 @@ void String::copy_from(const char32_t *p_cstr) { return; } - int len = 0; - const char32_t *ptr = p_cstr; - while (*(ptr++) != 0) { - len++; - } + const int len = strlen(p_cstr); if (len == 0) { resize(0); @@ -629,12 +634,7 @@ String &String::operator+=(char32_t p_char) { bool String::operator==(const char *p_str) const { // compare Latin-1 encoded c-string - int len = 0; - const char *aux = p_str; - - while (*(aux++) != 0) { - len++; - } + int len = strlen(p_str); if (length() != len) { return false; @@ -668,12 +668,7 @@ bool String::operator==(const wchar_t *p_str) const { } bool String::operator==(const char32_t *p_str) const { - int len = 0; - const char32_t *aux = p_str; - - while (*(aux++) != 0) { - len++; - } + const int len = strlen(p_str); if (length() != len) { return false; @@ -1109,17 +1104,21 @@ String String::_camelcase_to_underscore() const { String new_string; int start_index = 0; - for (int i = 1; i < size(); i++) { - bool is_prev_upper = is_unicode_upper_case(cstr[i - 1]); - bool is_prev_lower = is_unicode_lower_case(cstr[i - 1]); - bool is_prev_digit = is_digit(cstr[i - 1]); + if (length() == 0) { + return *this; + } - bool is_curr_upper = is_unicode_upper_case(cstr[i]); - bool is_curr_lower = is_unicode_lower_case(cstr[i]); - bool is_curr_digit = is_digit(cstr[i]); + bool is_prev_upper = is_unicode_upper_case(cstr[0]); + bool is_prev_lower = is_unicode_lower_case(cstr[0]); + bool is_prev_digit = is_digit(cstr[0]); + + for (int i = 1; i < length(); i++) { + const bool is_curr_upper = is_unicode_upper_case(cstr[i]); + const bool is_curr_lower = is_unicode_lower_case(cstr[i]); + const bool is_curr_digit = is_digit(cstr[i]); bool is_next_lower = false; - if (i + 1 < size()) { + if (i + 1 < length()) { is_next_lower = is_unicode_lower_case(cstr[i + 1]); } @@ -1132,6 +1131,10 @@ String String::_camelcase_to_underscore() const { new_string += substr(start_index, i - start_index) + "_"; start_index = i; } + + is_prev_upper = is_curr_upper; + is_prev_lower = is_curr_lower; + is_prev_digit = is_curr_digit; } new_string += substr(start_index, size() - start_index); @@ -5286,7 +5289,7 @@ bool String::is_valid_html_color() const { } // Changes made to the set of invalid filename characters must also be reflected in the String documentation for is_valid_filename. -static const char *invalid_filename_characters = ": / \\ ? * \" | % < >"; +static const char *invalid_filename_characters[] = { ":", "/", "\\", "?", "*", "\"", "|", "%", "<", ">" }; bool String::is_valid_filename() const { String stripped = strip_edges(); @@ -5298,8 +5301,7 @@ bool String::is_valid_filename() const { return false; } - Vector chars = String(invalid_filename_characters).split(" "); - for (const String &ch : chars) { + for (const char *ch : invalid_filename_characters) { if (contains(ch)) { return false; } @@ -5308,10 +5310,9 @@ bool String::is_valid_filename() const { } String String::validate_filename() const { - Vector chars = String(invalid_filename_characters).split(" "); String name = strip_edges(); - for (int i = 0; i < chars.size(); i++) { - name = name.replace(chars[i], "_"); + for (const char *ch : invalid_filename_characters) { + name = name.replace(ch, "_"); } return name; } diff --git a/godot/doc/classes/PackedFloat32Array.xml b/godot/doc/classes/PackedFloat32Array.xml index d421993b..237b659a 100644 --- a/godot/doc/classes/PackedFloat32Array.xml +++ b/godot/doc/classes/PackedFloat32Array.xml @@ -192,7 +192,7 @@ - Returns a copy of the data converted to a [PackedByteArray], where each element have been encoded as 4 bytes. + Returns a copy of the data converted to a [PackedByteArray], where each element has been encoded as 4 bytes. The size of the new array will be [code]float32_array.size() * 4[/code]. diff --git a/godot/doc/classes/PackedFloat64Array.xml b/godot/doc/classes/PackedFloat64Array.xml index 4622d632..56cc08d8 100644 --- a/godot/doc/classes/PackedFloat64Array.xml +++ b/godot/doc/classes/PackedFloat64Array.xml @@ -193,7 +193,7 @@ - Returns a copy of the data converted to a [PackedByteArray], where each element have been encoded as 8 bytes. + Returns a copy of the data converted to a [PackedByteArray], where each element has been encoded as 8 bytes. The size of the new array will be [code]float64_array.size() * 8[/code]. diff --git a/godot/doc/classes/PackedInt32Array.xml b/godot/doc/classes/PackedInt32Array.xml index 3a3596b2..5bb2ea97 100644 --- a/godot/doc/classes/PackedInt32Array.xml +++ b/godot/doc/classes/PackedInt32Array.xml @@ -186,7 +186,7 @@ - Returns a copy of the data converted to a [PackedByteArray], where each element have been encoded as 4 bytes. + Returns a copy of the data converted to a [PackedByteArray], where each element has been encoded as 4 bytes. The size of the new array will be [code]int32_array.size() * 4[/code]. diff --git a/godot/doc/classes/PackedInt64Array.xml b/godot/doc/classes/PackedInt64Array.xml index b82d0de3..2ed85489 100644 --- a/godot/doc/classes/PackedInt64Array.xml +++ b/godot/doc/classes/PackedInt64Array.xml @@ -187,7 +187,7 @@ - Returns a copy of the data converted to a [PackedByteArray], where each element have been encoded as 8 bytes. + Returns a copy of the data converted to a [PackedByteArray], where each element has been encoded as 8 bytes. The size of the new array will be [code]int64_array.size() * 8[/code]. diff --git a/godot/doc/classes/ShaderIncludeDB.xml b/godot/doc/classes/ShaderIncludeDB.xml new file mode 100644 index 00000000..a431eabf --- /dev/null +++ b/godot/doc/classes/ShaderIncludeDB.xml @@ -0,0 +1,33 @@ + + + + Internal database of built in shader include files. + + + This object contains shader fragments from Godot's internal shaders. These can be used when access to internal uniform buffers and/or internal functions is required for instance when composing compositor effects or compute shaders. Only fragments for the current rendering device are loaded. + + + + + + + + + Returns the code for the built-in shader fragment. You can also access this in your shader code through [code]#include "filename"[/code]. + + + + + + + Returns [code]true[/code] if an include file with this name exists. + + + + + + Returns a list of built-in include files that are currently registered. + + + + diff --git a/godot/doc/classes/SurfaceTool.xml b/godot/doc/classes/SurfaceTool.xml index 9265e6b3..258d6875 100644 --- a/godot/doc/classes/SurfaceTool.xml +++ b/godot/doc/classes/SurfaceTool.xml @@ -147,7 +147,7 @@ - Generates a tangent vector for each vertex. Requires that each vertex have UVs and normals set already (see [method generate_normals]). + Generates a tangent vector for each vertex. Requires that each vertex already has UVs and normals set (see [method generate_normals]). diff --git a/godot/drivers/d3d12/rendering_device_driver_d3d12.cpp b/godot/drivers/d3d12/rendering_device_driver_d3d12.cpp index b72a1932..f78233b9 100644 --- a/godot/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/godot/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -6144,6 +6144,16 @@ uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) { switch (p_limit) { case LIMIT_MAX_BOUND_UNIFORM_SETS: return safe_unbounded; + case LIMIT_MAX_TEXTURE_ARRAY_LAYERS: + return D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + case LIMIT_MAX_TEXTURE_SIZE_1D: + return D3D12_REQ_TEXTURE1D_U_DIMENSION; + case LIMIT_MAX_TEXTURE_SIZE_2D: + return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case LIMIT_MAX_TEXTURE_SIZE_3D: + return D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + case LIMIT_MAX_TEXTURE_SIZE_CUBE: + return D3D12_REQ_TEXTURECUBE_DIMENSION; case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE: return device_limits.max_srvs_per_shader_stage; case LIMIT_MAX_UNIFORM_BUFFER_SIZE: diff --git a/godot/drivers/gles3/storage/light_storage.cpp b/godot/drivers/gles3/storage/light_storage.cpp index 9b81430d..886918a2 100644 --- a/godot/drivers/gles3/storage/light_storage.cpp +++ b/godot/drivers/gles3/storage/light_storage.cpp @@ -1405,7 +1405,7 @@ bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, old_shadow = old_key & SHADOW_INDEX_MASK; // Only re-allocate if a better option is available, and enough time has passed. - should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); + should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (tick - shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick > shadow_atlas_realloc_tolerance_msec); should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version; if (!should_realloc) { diff --git a/godot/editor/connections_dialog.cpp b/godot/editor/connections_dialog.cpp index d76c324b..b96c715b 100644 --- a/godot/editor/connections_dialog.cpp +++ b/godot/editor/connections_dialog.cpp @@ -907,7 +907,7 @@ ConnectDialog::~ConnectDialog() { Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const { // If it's not a doc tooltip, fallback to the default one. - if (p_text.contains("::")) { + if (p_text.is_empty() || p_text.contains("::")) { return nullptr; } diff --git a/godot/editor/editor_inspector.cpp b/godot/editor/editor_inspector.cpp index 1e9c661b..f936a06e 100644 --- a/godot/editor/editor_inspector.cpp +++ b/godot/editor/editor_inspector.cpp @@ -69,6 +69,12 @@ bool EditorInspector::_property_path_matches(const String &p_property_path, cons return false; } +String EditorProperty::get_tooltip_string(const String &p_string) const { + // Trim to 100 characters to prevent the tooltip from being too long. + constexpr int TOOLTIP_MAX_LENGTH = 100; + return p_string.left(TOOLTIP_MAX_LENGTH).strip_edges() + String((p_string.length() > TOOLTIP_MAX_LENGTH) ? "..." : ""); +} + Size2 EditorProperty::get_minimum_size() const { Size2 ms; Ref font = get_theme_font(SceneStringName(font), SNAME("Tree")); diff --git a/godot/editor/editor_inspector.h b/godot/editor/editor_inspector.h index 2e4633cc..e87d90dc 100644 --- a/godot/editor/editor_inspector.h +++ b/godot/editor/editor_inspector.h @@ -160,6 +160,8 @@ class EditorProperty : public Container { public: void emit_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field = StringName(), bool p_changing = false); + String get_tooltip_string(const String &p_string) const; + virtual Size2 get_minimum_size() const override; void set_label(const String &p_label); diff --git a/godot/editor/editor_node.cpp b/godot/editor/editor_node.cpp index 222696a6..0dd05d4e 100644 --- a/godot/editor/editor_node.cpp +++ b/godot/editor/editor_node.cpp @@ -1427,7 +1427,7 @@ void EditorNode::save_resource_as(const Ref &p_resource, const String if (p_resource->get_path().is_resource_file()) { file->set_current_file(p_resource->get_path().get_file()); } else { - if (extensions.size()) { + if (!preferred.is_empty()) { String resource_name_snake_case = p_resource->get_class().to_snake_case(); file->set_current_file("new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower()); } else { @@ -1436,18 +1436,15 @@ void EditorNode::save_resource_as(const Ref &p_resource, const String } } else if (!p_resource->get_path().is_empty()) { file->set_current_path(p_resource->get_path()); - if (extensions.size()) { - String ext = p_resource->get_path().get_extension().to_lower(); + if (!extensions.is_empty()) { + const String ext = p_resource->get_path().get_extension().to_lower(); if (extensions.find(ext) == nullptr) { file->set_current_path(p_resource->get_path().replacen("." + ext, "." + extensions.front()->get())); } } - } else if (preferred.size()) { - String existing; - if (extensions.size()) { - String resource_name_snake_case = p_resource->get_class().to_snake_case(); - existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower(); - } + } else if (!preferred.is_empty()) { + const String resource_name_snake_case = p_resource->get_class().to_snake_case(); + const String existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower(); file->set_current_path(existing); } file->set_title(TTR("Save Resource As...")); @@ -7173,6 +7170,7 @@ EditorNode::EditorNode() { main_menu = memnew(MenuBar); main_menu->set_mouse_filter(Control::MOUSE_FILTER_STOP); title_bar->add_child(main_menu); + main_menu->set_v_size_flags(Control::SIZE_SHRINK_CENTER); main_menu->set_theme_type_variation("MainMenuBar"); main_menu->set_start_index(0); // Main menu, add to the start of global menu. main_menu->set_prefer_global_menu(global_menu); diff --git a/godot/editor/editor_properties.cpp b/godot/editor/editor_properties.cpp index e6c94458..c54c9743 100644 --- a/godot/editor/editor_properties.cpp +++ b/godot/editor/editor_properties.cpp @@ -91,6 +91,10 @@ void EditorPropertyText::_text_changed(const String &p_string) { return; } + // Set tooltip so that the full text is displayed in a tooltip if hovered. + // This is useful when using a narrow inspector, as the text can be trimmed otherwise. + text->set_tooltip_text(get_tooltip_string(text->get_text())); + if (string_name) { emit_changed(get_edited_property(), StringName(p_string)); } else { @@ -104,6 +108,7 @@ void EditorPropertyText::update_property() { if (text->get_text() != s) { int caret = text->get_caret_column(); text->set_text(s); + text->set_tooltip_text(get_tooltip_string(s)); text->set_caret_column(caret); } text->set_editable(!is_read_only()); @@ -150,10 +155,14 @@ void EditorPropertyMultilineText::_set_read_only(bool p_read_only) { void EditorPropertyMultilineText::_big_text_changed() { text->set_text(big_text->get_text()); + // Set tooltip so that the full text is displayed in a tooltip if hovered. + // This is useful when using a narrow inspector, as the text can be trimmed otherwise. + text->set_tooltip_text(get_tooltip_string(big_text->get_text())); emit_changed(get_edited_property(), big_text->get_text(), "", true); } void EditorPropertyMultilineText::_text_changed() { + text->set_tooltip_text(get_tooltip_string(text->get_text())); emit_changed(get_edited_property(), text->get_text(), "", true); } @@ -182,6 +191,7 @@ void EditorPropertyMultilineText::update_property() { String t = get_edited_property_value(); if (text->get_text() != t) { text->set_text(t); + text->set_tooltip_text(get_tooltip_string(t)); if (big_text && big_text->is_visible_in_tree()) { big_text->set_text(t); } diff --git a/godot/editor/editor_property_name_processor.cpp b/godot/editor/editor_property_name_processor.cpp index ca8854f7..3560174e 100644 --- a/godot/editor/editor_property_name_processor.cpp +++ b/godot/editor/editor_property_name_processor.cpp @@ -235,6 +235,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["linuxbsd"] = "Linux/*BSD"; capitalize_string_remaps["lod"] = "LOD"; capitalize_string_remaps["lods"] = "LODs"; + capitalize_string_remaps["loongarch64"] = "loongarch64"; capitalize_string_remaps["lowpass"] = "Low-pass"; capitalize_string_remaps["macos"] = "macOS"; capitalize_string_remaps["mb"] = "(MB)"; // Unit. diff --git a/godot/editor/export/export_template_manager.cpp b/godot/editor/export/export_template_manager.cpp index a90c16f6..1e1999dd 100644 --- a/godot/editor/export/export_template_manager.cpp +++ b/godot/editor/export/export_template_manager.cpp @@ -437,6 +437,13 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ } String file = String::utf8(fname); + + // Skip the __MACOSX directory created by macOS's built-in file zipper. + if (file.begins_with("__MACOSX")) { + ret = unzGoToNextFile(pkg); + continue; + } + if (file.ends_with("version.txt")) { Vector uncomp_data; uncomp_data.resize(info.uncompressed_size); @@ -512,7 +519,8 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ String file = file_path.get_file(); - if (file.size() == 0) { + // Skip the __MACOSX directory created by macOS's built-in file zipper. + if (file.is_empty() || file.begins_with("__MACOSX")) { ret = unzGoToNextFile(pkg); continue; } diff --git a/godot/editor/filesystem_dock.cpp b/godot/editor/filesystem_dock.cpp index f68dc717..2fdf96cf 100644 --- a/godot/editor/filesystem_dock.cpp +++ b/godot/editor/filesystem_dock.cpp @@ -245,6 +245,8 @@ void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory } subdirectory_item->set_selectable(0, true); subdirectory_item->set_metadata(0, lpath); + folder_map[lpath] = subdirectory_item; + if (!p_select_in_favorites && (current_path == lpath || ((display_mode != DISPLAY_MODE_TREE_ONLY) && current_path.get_base_dir() == lpath))) { subdirectory_item->select(0); // Keep select an item when re-created a tree @@ -371,6 +373,7 @@ void FileSystemDock::_update_tree(const Vector &p_uncollapsed_paths, boo tree_update_id++; updating_tree = true; TreeItem *root = tree->create_item(); + folder_map.clear(); // Handles the favorites. favorites_item = tree->create_item(root); @@ -702,19 +705,21 @@ void FileSystemDock::_set_current_path_line_edit_text(const String &p_path) { } void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_favorites) { + bool is_directory = false; if (p_path == "Favorites") { current_path = p_path; } else { String target_path = p_path; // If the path is a file, do not only go to the directory in the tree, also select the file in the file list. if (target_path.ends_with("/")) { - target_path = target_path.substr(0, target_path.length() - 1); + target_path = target_path.trim_suffix("/"); } Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists(p_path)) { current_path = target_path; } else if (da->dir_exists(p_path)) { current_path = target_path + "/"; + is_directory = true; } else { ERR_FAIL_MSG(vformat("Cannot navigate to '%s' as it has not been found in the file system!", p_path)); } @@ -723,17 +728,56 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa _set_current_path_line_edit_text(current_path); _push_to_history(); - _update_tree(get_uncollapsed_paths(), false, p_select_in_favorites, true); + const String file_name = is_directory ? p_path.trim_suffix("/").get_file() + "/" : p_path.get_file(); + bool found = false; + + TreeItem **base_dir_ptr; + { + const String base_dir = current_path.get_base_dir(); + if (base_dir == "res://") { + base_dir_ptr = folder_map.getptr(base_dir); + } else if (is_directory) { + base_dir_ptr = folder_map.getptr(base_dir.get_base_dir() + "/"); + } else { + base_dir_ptr = folder_map.getptr(base_dir + "/"); + } + } + + if (base_dir_ptr) { + TreeItem *directory = *base_dir_ptr; + { + TreeItem *entry = directory->get_first_child(); + while (entry) { + if (entry->get_metadata(0).operator String().ends_with(file_name)) { + tree->deselect_all(); + entry->select(0); + found = true; + break; + } + entry = entry->get_next(); + } + } + + while (directory) { + directory->set_collapsed(false); + directory = directory->get_parent(); + } + } + + if (!found) { + return; + } + + tree->ensure_cursor_is_visible(); if (display_mode != DISPLAY_MODE_TREE_ONLY) { _update_file_list(false); // Reset the scroll for a directory. - if (p_path.ends_with("/")) { + if (is_directory) { files->get_v_scroll_bar()->set_value(0); } } - String file_name = p_path.get_file(); if (!file_name.is_empty()) { for (int i = 0; i < files->get_item_count(); i++) { if (files->get_item_text(i) == file_name) { diff --git a/godot/editor/filesystem_dock.h b/godot/editor/filesystem_dock.h index 73462df3..7b10d8b3 100644 --- a/godot/editor/filesystem_dock.h +++ b/godot/editor/filesystem_dock.h @@ -133,6 +133,7 @@ class FileSystemDock : public VBoxContainer { CONVERT_BASE_ID = 1000, }; + HashMap folder_map; HashMap folder_colors; Dictionary assigned_folder_colors; diff --git a/godot/editor/gui/editor_file_dialog.cpp b/godot/editor/gui/editor_file_dialog.cpp index 6f257f49..8ece6f5d 100644 --- a/godot/editor/gui/editor_file_dialog.cpp +++ b/godot/editor/gui/editor_file_dialog.cpp @@ -44,7 +44,6 @@ #include "scene/gui/check_box.h" #include "scene/gui/grid_container.h" #include "scene/gui/label.h" -#include "scene/gui/margin_container.h" #include "scene/gui/option_button.h" #include "scene/gui/separator.h" #include "scene/gui/split_container.h" @@ -1400,11 +1399,8 @@ void EditorFileDialog::set_file_mode(FileMode p_mode) { item_list->set_select_mode(ItemList::SELECT_SINGLE); } - if (can_create_dir) { - makedir->show(); - } else { - makedir->hide(); - } + makedir_sep->set_visible(can_create_dir); + makedir->set_visible(can_create_dir); } EditorFileDialog::FileMode EditorFileDialog::get_file_mode() const { @@ -1571,6 +1567,8 @@ void EditorFileDialog::_select_drive(int p_idx) { void EditorFileDialog::_update_drives(bool p_select) { int dc = dir_access->get_drive_count(); if (dc == 0 || access != ACCESS_FILESYSTEM) { + shortcuts_container->hide(); + drives_container->hide(); drives->hide(); } else { drives->clear(); @@ -1579,6 +1577,8 @@ void EditorFileDialog::_update_drives(bool p_select) { dp->remove_child(drives); } dp = dir_access->drives_are_shortcuts() ? shortcuts_container : drives_container; + shortcuts_container->set_visible(dir_access->drives_are_shortcuts()); + drives_container->set_visible(!dir_access->drives_are_shortcuts()); dp->add_child(drives); drives->show(); @@ -1768,6 +1768,9 @@ void EditorFileDialog::_update_favorites() { recent->deselect_all(); } } + + fav_up->set_disabled(current_favorite < 1); + fav_down->set_disabled(current_favorite == -1 || favorited_paths.size() - 1 <= current_favorite); } void EditorFileDialog::_favorite_pressed() { @@ -2354,7 +2357,8 @@ EditorFileDialog::EditorFileDialog() { drives->connect(SceneStringName(item_selected), callable_mp(this, &EditorFileDialog::_select_drive)); pathhb->add_child(drives); - pathhb->add_child(memnew(VSeparator)); + makedir_sep = memnew(VSeparator); + pathhb->add_child(makedir_sep); makedir = memnew(Button); makedir->set_theme_type_variation("FlatButton"); @@ -2473,7 +2477,8 @@ EditorFileDialog::EditorFileDialog() { lower_hb->add_child(memnew(VSeparator)); file_sort_button = memnew(MenuButton); - file_sort_button->set_flat(true); + file_sort_button->set_flat(false); + file_sort_button->set_theme_type_variation("FlatMenuButton"); file_sort_button->set_tooltip_text(TTR("Sort files")); show_search_filter_button = memnew(Button); diff --git a/godot/editor/gui/editor_file_dialog.h b/godot/editor/gui/editor_file_dialog.h index a151f2b3..8a07a209 100644 --- a/godot/editor/gui/editor_file_dialog.h +++ b/godot/editor/gui/editor_file_dialog.h @@ -44,6 +44,7 @@ class MenuButton; class OptionButton; class PopupMenu; class TextureRect; +class VSeparator; class EditorFileDialog : public ConfirmationDialog { GDCLASS(EditorFileDialog, ConfirmationDialog); @@ -89,6 +90,7 @@ class EditorFileDialog : public ConfirmationDialog { ConfirmationDialog *makedialog = nullptr; LineEdit *makedirname = nullptr; + VSeparator *makedir_sep = nullptr; Button *makedir = nullptr; Access access = ACCESS_RESOURCES; diff --git a/godot/editor/plugins/canvas_item_editor_plugin.cpp b/godot/editor/plugins/canvas_item_editor_plugin.cpp index c132b7ba..5b948d9b 100644 --- a/godot/editor/plugins/canvas_item_editor_plugin.cpp +++ b/godot/editor/plugins/canvas_item_editor_plugin.cpp @@ -32,7 +32,6 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/io/resource_importer.h" #include "core/os/keyboard.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_main_screen.h" @@ -48,7 +47,6 @@ #include "editor/scene_tree_dock.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" -#include "scene/2d/animated_sprite_2d.h" #include "scene/2d/audio_stream_player_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/2d/skeleton_2d.h" @@ -63,7 +61,6 @@ #include "scene/gui/view_panner.h" #include "scene/main/canvas_layer.h" #include "scene/main/window.h" -#include "scene/resources/atlas_texture.h" #include "scene/resources/packed_scene.h" #include "scene/resources/style_box_texture.h" @@ -5923,23 +5920,6 @@ void CanvasItemEditorViewport::_create_texture_node(Node *p_parent, Node *p_chil Vector2(0, texture_size.height) }; undo_redo->add_do_property(p_child, "polygon", list); - } else if (Object::cast_to(p_child)) { - Dictionary meta = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path); - Ref frames; - frames.instantiate(); - frames->set_animation_speed(SceneStringName(default_), meta.get("fps", 5)); - Size2i sprite_size = meta["sprite_size"]; - for (int i = 0; i < (int)meta["frame_count"]; i++) { - int x = i % (int)meta["columns"] * sprite_size.width; - int y = i / (int)meta["columns"] * sprite_size.height; - Ref atlas_texture; - atlas_texture.instantiate(); - atlas_texture->set_atlas(texture); - atlas_texture->set_region(Rect2(x, y, sprite_size.width, sprite_size.height)); - frames->add_frame(SceneStringName(default_), atlas_texture); - } - undo_redo->add_do_property(p_child, SceneStringName(autoplay), SceneStringName(default_)); - undo_redo->add_do_property(p_child, "sprite_frames", frames); } // Compute the global position @@ -6345,7 +6325,6 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it texture_node_types.push_back("GPUParticles2D"); texture_node_types.push_back("Polygon2D"); texture_node_types.push_back("TouchScreenButton"); - texture_node_types.push_back("AnimatedSprite2D"); // Control texture_node_types.push_back("TextureRect"); texture_node_types.push_back("TextureButton"); diff --git a/godot/editor/plugins/gdextension_export_plugin.h b/godot/editor/plugins/gdextension_export_plugin.h index c8ed05c6..9189441c 100644 --- a/godot/editor/plugins/gdextension_export_plugin.h +++ b/godot/editor/plugins/gdextension_export_plugin.h @@ -73,6 +73,7 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p all_archs.insert("ppc32"); all_archs.insert("ppc64"); all_archs.insert("wasm32"); + all_archs.insert("loongarch64"); all_archs.insert("universal"); HashSet archs; diff --git a/godot/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/godot/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp index 85b84262..d74c4344 100644 --- a/godot/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp +++ b/godot/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp @@ -47,7 +47,7 @@ ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { gizmo_color.a = 0.5; create_material("reflection_internal_material", gizmo_color); - gizmo_color.a = 0.1; + gizmo_color.a = 0.025; create_material("reflection_probe_solid_material", gizmo_color); create_icon_material("reflection_probe_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoReflectionProbe"), EditorStringName(EditorIcons))); @@ -165,22 +165,17 @@ void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { aabb.position = -size / 2; aabb.size = size; - for (int i = 0; i < 8; i++) { - Vector3 ep = aabb.get_endpoint(i); - internal_lines.push_back(probe->get_origin_offset()); - internal_lines.push_back(ep); - } - Vector handles = helper->box_get_handles(probe->get_size()); - for (int i = 0; i < 3; i++) { - Vector3 orig_handle = probe->get_origin_offset(); - orig_handle[i] -= 0.25; - lines.push_back(orig_handle); - handles.push_back(orig_handle); + if (probe->get_origin_offset() != Vector3(0.0, 0.0, 0.0)) { + for (int i = 0; i < 3; i++) { + Vector3 orig_handle = probe->get_origin_offset(); + orig_handle[i] -= 0.25; + lines.push_back(orig_handle); - orig_handle[i] += 0.5; - lines.push_back(orig_handle); + orig_handle[i] += 0.5; + lines.push_back(orig_handle); + } } Ref material = get_material("reflection_probe_material", p_gizmo); diff --git a/godot/editor/project_manager/project_dialog.cpp b/godot/editor/project_manager/project_dialog.cpp index 01dc9229..82e2bda0 100644 --- a/godot/editor/project_manager/project_dialog.cpp +++ b/godot/editor/project_manager/project_dialog.cpp @@ -132,6 +132,13 @@ void ProjectDialog::_validate_path() { ERR_FAIL_COND_MSG(ret != UNZ_OK, "Failed to get current file info."); String name = String::utf8(fname); + + // Skip the __MACOSX directory created by macOS's built-in file zipper. + if (name.begins_with("__MACOSX")) { + ret = unzGoToNextFile(pkg); + continue; + } + if (name.get_file() == "project.godot") { break; // ret == UNZ_OK. } @@ -604,6 +611,13 @@ void ProjectDialog::ok_pressed() { ERR_FAIL_COND_MSG(ret != UNZ_OK, "Failed to get current file info."); String name = String::utf8(fname); + + // Skip the __MACOSX directory created by macOS's built-in file zipper. + if (name.begins_with("__MACOSX")) { + ret = unzGoToNextFile(pkg); + continue; + } + if (name.get_file() == "project.godot") { zip_root = name.get_base_dir(); break; @@ -636,7 +650,15 @@ void ProjectDialog::ok_pressed() { ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); ERR_FAIL_COND_MSG(ret != UNZ_OK, "Failed to get current file info."); - String rel_path = String::utf8(fname).trim_prefix(zip_root); + String name = String::utf8(fname); + + // Skip the __MACOSX directory created by macOS's built-in file zipper. + if (name.begins_with("__MACOSX")) { + ret = unzGoToNextFile(pkg); + continue; + } + + String rel_path = name.trim_prefix(zip_root); if (rel_path.is_empty()) { // Root. } else if (rel_path.ends_with("/")) { // Directory. Ref da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); diff --git a/godot/editor/themes/editor_fonts.cpp b/godot/editor/themes/editor_fonts.cpp index da35ed33..8ae48892 100644 --- a/godot/editor/themes/editor_fonts.cpp +++ b/godot/editor/themes/editor_fonts.cpp @@ -169,7 +169,7 @@ void editor_register_fonts(const Ref &p_theme) { } TypedArray fallbacks; - Ref arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); + Ref arabic_font = load_internal_font(_font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); Ref bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); Ref devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); Ref georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); @@ -192,7 +192,7 @@ void editor_register_fonts(const Ref &p_theme) { Ref default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, font_allow_msdf); TypedArray fallbacks_bold; - Ref arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); + Ref arabic_font_bold = load_internal_font(_font_Vazirmatn_Bold, _font_Vazirmatn_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); Ref bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); Ref devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); Ref georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); diff --git a/godot/modules/camera/config.py b/godot/modules/camera/config.py index 7b368d21..fa229ef2 100644 --- a/godot/modules/camera/config.py +++ b/godot/modules/camera/config.py @@ -1,4 +1,8 @@ def can_build(env, platform): + import sys + + if sys.platform.startswith("freebsd"): + return False return platform == "macos" or platform == "windows" or platform == "linuxbsd" diff --git a/godot/modules/csg/csg_shape.cpp b/godot/modules/csg/csg_shape.cpp index eed5a767..c30c7b8b 100644 --- a/godot/modules/csg/csg_shape.cpp +++ b/godot/modules/csg/csg_shape.cpp @@ -1294,14 +1294,22 @@ CSGBrush *CSGSphere3D::_build_brush() { const double longitude_step = Math_TAU / radial_segments; int face = 0; for (int i = 0; i < rings; i++) { - double latitude0 = latitude_step * i + Math_TAU / 4; - double cos0 = Math::cos(latitude0); - double sin0 = Math::sin(latitude0); + double cos0 = 0; + double sin0 = 1; + if (i > 0) { + double latitude0 = latitude_step * i + Math_TAU / 4; + cos0 = Math::cos(latitude0); + sin0 = Math::sin(latitude0); + } double v0 = double(i) / rings; - double latitude1 = latitude_step * (i + 1) + Math_TAU / 4; - double cos1 = Math::cos(latitude1); - double sin1 = Math::sin(latitude1); + double cos1 = 0; + double sin1 = -1; + if (i < rings - 1) { + double latitude1 = latitude_step * (i + 1) + Math_TAU / 4; + cos1 = Math::cos(latitude1); + sin1 = Math::sin(latitude1); + } double v1 = double(i + 1) / rings; for (int j = 0; j < radial_segments; j++) { diff --git a/godot/modules/interactive_music/audio_stream_interactive.cpp b/godot/modules/interactive_music/audio_stream_interactive.cpp index 8656be98..995fa150 100644 --- a/godot/modules/interactive_music/audio_stream_interactive.cpp +++ b/godot/modules/interactive_music/audio_stream_interactive.cpp @@ -691,9 +691,14 @@ void AudioStreamPlaybackInteractive::_queue(int p_to_clip_index, bool p_is_auto_ src_fade_wait = beat_sec - remainder; } break; case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BAR: { - float bar_sec = beat_sec * from_state.stream->get_bar_beats(); - float remainder = Math::fmod(current_pos, bar_sec); - src_fade_wait = bar_sec - remainder; + if (from_state.stream->get_bar_beats() > 0) { + float bar_sec = beat_sec * from_state.stream->get_bar_beats(); + float remainder = Math::fmod(current_pos, bar_sec); + src_fade_wait = bar_sec - remainder; + } else { + // Stream does not have a number of beats per bar - avoid NaN, and play immediately. + src_fade_wait = 0; + } } break; case AudioStreamInteractive::TRANSITION_FROM_TIME_END: { float end = from_state.stream->get_beat_count() > 0 ? float(from_state.stream->get_beat_count() * beat_sec) : from_state.stream->get_length(); diff --git a/godot/modules/interactive_music/audio_stream_interactive.h b/godot/modules/interactive_music/audio_stream_interactive.h index 12d3ce8a..9710a7fc 100644 --- a/godot/modules/interactive_music/audio_stream_interactive.h +++ b/godot/modules/interactive_music/audio_stream_interactive.h @@ -100,7 +100,7 @@ class AudioStreamInteractive : public AudioStream { TransitionFromTime from_time = TRANSITION_FROM_TIME_NEXT_BEAT; TransitionToTime to_time = TRANSITION_TO_TIME_START; FadeMode fade_mode = FADE_AUTOMATIC; - int fade_beats = 1; + float fade_beats = 1; bool use_filler_clip = false; int filler_clip = 0; bool hold_previous = false; diff --git a/godot/modules/interactive_music/audio_stream_synchronized.cpp b/godot/modules/interactive_music/audio_stream_synchronized.cpp index e38a57ba..ad67e778 100644 --- a/godot/modules/interactive_music/audio_stream_synchronized.cpp +++ b/godot/modules/interactive_music/audio_stream_synchronized.cpp @@ -99,6 +99,18 @@ int AudioStreamSynchronized::get_beat_count() const { return max_beats; } +int AudioStreamSynchronized::get_bar_beats() const { + for (int i = 0; i < stream_count; i++) { + if (audio_streams[i].is_valid()) { + int bar_beats = audio_streams[i]->get_bar_beats(); + if (bar_beats != 0) { + return bar_beats; + } + } + } + return 0; +} + bool AudioStreamSynchronized::has_loop() const { for (int i = 0; i < stream_count; i++) { if (audio_streams[i].is_valid()) { diff --git a/godot/modules/interactive_music/audio_stream_synchronized.h b/godot/modules/interactive_music/audio_stream_synchronized.h index a2d8c554..83798a13 100644 --- a/godot/modules/interactive_music/audio_stream_synchronized.h +++ b/godot/modules/interactive_music/audio_stream_synchronized.h @@ -54,6 +54,7 @@ class AudioStreamSynchronized : public AudioStream { public: virtual double get_bpm() const override; virtual int get_beat_count() const override; + virtual int get_bar_beats() const override; virtual bool has_loop() const override; void set_stream_count(int p_count); int get_stream_count() const; diff --git a/godot/modules/mbedtls/crypto_mbedtls.cpp b/godot/modules/mbedtls/crypto_mbedtls.cpp index b1479bbf..be7aaef9 100644 --- a/godot/modules/mbedtls/crypto_mbedtls.cpp +++ b/godot/modules/mbedtls/crypto_mbedtls.cpp @@ -411,7 +411,14 @@ Ref CryptoMbedTLS::generate_self_signed_certificate(Ref= 3 mbedtls_x509write_crt_set_serial_raw(&crt, rand_serial, sizeof(rand_serial)); +#else + mbedtls_mpi serial; + mbedtls_mpi_init(&serial); + ERR_FAIL_COND_V(mbedtls_mpi_read_binary(&serial, rand_serial, sizeof(rand_serial)), nullptr); + mbedtls_x509write_crt_set_serial(&crt, &serial); +#endif mbedtls_x509write_crt_set_validity(&crt, p_not_before.utf8().get_data(), p_not_after.utf8().get_data()); mbedtls_x509write_crt_set_basic_constraints(&crt, 1, -1); diff --git a/godot/modules/openxr/SCsub b/godot/modules/openxr/SCsub index 48c87bcd..edfe0bbf 100644 --- a/godot/modules/openxr/SCsub +++ b/godot/modules/openxr/SCsub @@ -1,6 +1,8 @@ #!/usr/bin/env python from misc.utility.scons_hints import * +import sys + Import("env") Import("env_modules") @@ -29,7 +31,9 @@ elif env["platform"] == "linuxbsd": env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_EGL"]) # FIXME: Review what needs to be set for Android and macOS. - env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) + # FreeBSD uses non-standard getenv functions. + if not sys.platform.startswith("freebsd"): + env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) elif env["platform"] == "windows": env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"]) elif env["platform"] == "macos": diff --git a/godot/modules/raycast/raycast_occlusion_cull.cpp b/godot/modules/raycast/raycast_occlusion_cull.cpp index b136d545..fb2d0023 100644 --- a/godot/modules/raycast/raycast_occlusion_cull.cpp +++ b/godot/modules/raycast/raycast_occlusion_cull.cpp @@ -366,7 +366,7 @@ void RaycastOcclusionCull::Scenario::_transform_vertices_thread(uint32_t p_threa } void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, float *p_write, const Transform3D &p_xform, int p_from, int p_to) { - float *floats_w = p_write; + float *floats_w = p_write + 3 * p_from; for (int i = p_from; i < p_to; i++) { const Vector3 p = p_xform.xform(p_read[i]); floats_w[0] = p.x; diff --git a/godot/modules/svg/SCsub b/godot/modules/svg/SCsub index 4d03c225..83321cf4 100644 --- a/godot/modules/svg/SCsub +++ b/godot/modules/svg/SCsub @@ -59,20 +59,6 @@ thirdparty_sources = [ "src/renderer/sw_engine/tvgSwStroke.cpp", ] -if env.editor_build: - thirdparty_sources += [ - "src/renderer/tvgAnimation.cpp", - # Lottie loader - "src/loaders/lottie/tvgLottieAnimation.cpp", - "src/loaders/lottie/tvgLottieBuilder.cpp", - "src/loaders/lottie/tvgLottieInterpolator.cpp", - "src/loaders/lottie/tvgLottieLoader.cpp", - "src/loaders/lottie/tvgLottieModel.cpp", - "src/loaders/lottie/tvgLottieModifier.cpp", - "src/loaders/lottie/tvgLottieParser.cpp", - "src/loaders/lottie/tvgLottieParserHandler.cpp", - ] - if env["module_webp_enabled"]: thirdparty_sources += ["src/loaders/external_webp/tvgWebpLoader.cpp"] env_svg.Append(CPPDEFINES=["THORVG_WEBP_LOADER_SUPPORT"]) @@ -84,9 +70,6 @@ env_svg.Prepend(CPPPATH=[thirdparty_dir + "inc"]) # Enable ThorVG static object linking. env_svg.Append(CPPDEFINES=["TVG_STATIC"]) -if env.editor_build: - env_svg.Append(CPPDEFINES=["THORVG_LOTTIE_LOADER_SUPPORT", "LOTTIE_ENABLED"]) - env_thirdparty = env_svg.Clone() env_thirdparty.disable_warnings() env_thirdparty.Prepend( @@ -100,9 +83,6 @@ env_thirdparty.Prepend( thirdparty_dir + "src/loaders/jpg", ] ) - -if env.editor_build: - env_thirdparty.Prepend(CPPPATH=[thirdparty_dir + "src/loaders/lottie"]) if env["builtin_libpng"]: env_thirdparty.Prepend(CPPPATH=["#thirdparty/libpng"]) if env["module_webp_enabled"]: @@ -117,10 +97,7 @@ env.modules_sources += thirdparty_obj module_obj = [] -env_svg.add_source_files(module_obj, ["register_types.cpp", "image_loader_svg.cpp"]) -if env.editor_build: - env_svg.add_source_files(module_obj, "editor/*.cpp") - +env_svg.add_source_files(module_obj, "*.cpp") env.modules_sources += module_obj # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/godot/modules/svg/config.py b/godot/modules/svg/config.py index dce6679d..d22f9454 100644 --- a/godot/modules/svg/config.py +++ b/godot/modules/svg/config.py @@ -4,13 +4,3 @@ def can_build(env, platform): def configure(env): pass - - -def get_doc_classes(): - return [ - "ResourceImporterLottie", - ] - - -def get_doc_path(): - return "doc_classes" diff --git a/godot/modules/svg/doc_classes/ResourceImporterLottie.xml b/godot/modules/svg/doc_classes/ResourceImporterLottie.xml deleted file mode 100644 index 1f7735b9..00000000 --- a/godot/modules/svg/doc_classes/ResourceImporterLottie.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - Import a Lottie animation as a sprite sheet. - - - This imports a Lottie animation to a [CompressedTexture2D]. See also [ResourceImporterTexture]. - [b]Note:[/b] Both JSON and dotLottie (extra resources are ignored) are supported. Only files with the [code].lottie[/code] extension are recognized. You will have to rename the JSON file extension to [code].lottie[/code] to import it. - - - - - - Controls how color channels should be used in the imported texture. - [b]sRGB Friendly:[/b] Prevents the RG color format from being used, as it does not support sRGB color. - [b]Optimized:[/b] Allows the RG color format to be used if the texture does not use the blue channel. This reduces memory usage if the texture's blue channel can be discarded (all pixels must have a blue value of [code]0[/code]). - - - Controls how VRAM compression should be performed for HDR images. - [b]Disabled:[/b] Never use VRAM compression for HDR textures, regardless of whether they're opaque or transparent. Instead, the texture is converted to RGBE9995 (9-bits per channel + 5-bit exponent = 32 bits per pixel) to reduce memory usage compared to a half-float or single-precision float image format. - [b]Opaque Only:[/b] Only uses VRAM compression for opaque HDR textures. This is due to a limitation of HDR formats, as there is no VRAM-compressed HDR format that supports transparency at the same time. - [b]Always:[/b] Force VRAM compression even for HDR textures with an alpha channel. To perform this, the alpha channel is discarded on import. - [b]Note:[/b] Only effective on Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) images. - - - If [code]true[/code], uses BPTC compression on desktop platforms and ASTC compression on mobile platforms. When using BPTC, BC7 is used for SDR textures and BC6H is used for HDR textures. - If [code]false[/code], uses the faster but lower-quality S3TC compression on desktop platforms and ETC2 on mobile/web platforms. When using S3TC, DXT1 (BC1) is used for opaque textures and DXT5 (BC3) is used for transparent or normal map (RGTC) textures. - BPTC and ASTC support VRAM compression for HDR textures, but S3TC and ETC2 do not (see [member compress/hdr_compression]). - - - The quality to use when using the [b]Lossy[/b] compression mode. Higher values result in better quality, at the cost of larger file sizes. Lossy quality does not affect memory usage of the imported texture, only its file size on disk. - - - The compression mode to use. Each compression mode provides a different tradeoff: - [b]Lossless[/b]: Original quality, high memory usage, high size on disk, fast import. - [b]Lossy:[/b] Reduced quality, high memory usage, low size on disk, fast import. - [b]VRAM Compressed:[/b] Reduced quality, low memory usage, low size on disk, slowest import. Only use for textures in 3D scenes, not for 2D elements. - [b]VRAM Uncompressed:[/b] Original quality, high memory usage, highest size on disk, fastest import. - [b]Basis Universal:[/b] Reduced quality, low memory usage, lowest size on disk, slow import. Only use for textures in 3D scenes, not for 2D elements. - See [url=$DOCS_URL/tutorials/assets_pipeline/importing_images.html#compress-mode]Compress mode[/url] in the manual for more details. - - - When using a texture as normal map, only the red and green channels are required. Given regular texture compression algorithms produce artifacts that don't look that nice in normal maps, the RGTC compression format is the best fit for this data. Forcing this option to Enable will make Godot import the image as RGTC compressed. By default, it's set to Detect. This means that if the texture is ever detected to be used as a normal map, it will be changed to Enable and reimported automatically. - Note that RGTC compression affects the resulting normal map image. You will have to adjust custom shaders that use the normal map's blue channel to take this into account. Built-in material shaders already ignore the blue channel in a normal map (regardless of the actual normal map's contents). - - - This changes the [member compress/mode] option that is used when a texture is detected as being used in 3D. - Changing this import option only has an effect if a texture is detected as being used in 3D. Changing this to [b]Disabled[/b] then reimporting will not change the existing compress mode on a texture (if it's detected to be used in 3D), but choosing [b]VRAM Compressed[/b] or [b]Basis Universal[/b] will. - - - If [code]true[/code], converts the imported image's colors to match [member EditorSettings.interface/theme/icon_and_font_color]. This assumes the image uses the exact same colors as [url=$DOCS_URL/contributing/development/editor/creating_icons.html]Godot's own color palette for editor icons[/url], with the source file designed for a dark editor theme. This should be enabled for editor plugin icons and custom class icons, but should be left disabled otherwise. - [b]Note:[/b] Only available for SVG images. - - - If [code]true[/code], scales the imported image to match [member EditorSettings.interface/editor/custom_display_scale]. This should be enabled for editor plugin icons and custom class icons, but should be left disabled otherwise. - [b]Note:[/b] Only available for SVG images. - - - The start of the Lottie animation in the range [code]0.0[/code] to [code]1.0[/code]. - - - The number of columns of the sprite sheet. - - - The end of the Lottie animation in the range [code]0.0[/code] to [code]1.0[/code]. Less than [member lottie/begin] will be considered as [member lottie/begin]. - - - The frame rate the Lottie should be rendered at. Higher values result in a larger image. - - - The scale the Lottie should be rendered at, with [code]1.0[/code] being the original design size. Higher values result in a larger image. - - - If set to a value greater than [code]0[/code], the size of the imported Lottie texture is limited on import to a value smaller than or equal to the value specified here. - [b]Note:[/b] Importing large Lottie textures in editor is slow, this option ensures import speed and ignores [member lottie/scale]. - - - If [code]true[/code], smaller versions of the texture are generated on import. For example, a 64×64 texture will generate 6 mipmaps (32×32, 16×16, 8×8, 4×4, 2×2, 1×1). This has several benefits: - - Textures will not become grainy in the distance (in 3D), or if scaled down due to [Camera2D] zoom or [CanvasItem] scale (in 2D). - - Performance will improve if the texture is displayed in the distance, since sampling smaller versions of the original texture is faster and requires less memory bandwidth. - The downside of mipmaps is that they increase memory usage by roughly 33%. - It's recommended to enable mipmaps in 3D. However, in 2D, this should only be enabled if your project visibly benefits from having mipmaps enabled. If the camera never zooms out significantly, there won't be a benefit to enabling mipmaps but memory usage will increase. - - - Unimplemented. This currently has no effect when changed. - - - If [code]true[/code], puts pixels of the same surrounding color in transition from transparent to opaque areas. For textures displayed with bilinear filtering, this helps to reduce the outline effect when exporting images from an image editor. - It's recommended to leave this enabled (as it is by default), unless this causes issues for a particular image. - - - Some HDR images you can find online may be broken and contain sRGB color data (instead of linear color data). It is advised not to use those files. If you absolutely have to, enabling [member process/hdr_as_srgb] will make them look correct. - [b]Warning:[/b] Enabling [member process/hdr_as_srgb] on well-formatted HDR images will cause the resulting image to look too dark, so leave this on [code]false[/code] if unsure. - - - If [code]true[/code], clamps exposure in the imported high dynamic range images using a smart clamping formula (without introducing [i]visible[/i] clipping). - Some HDR panorama images you can find online may contain extremely bright pixels, due to being taken from real life sources without any clipping. - While these HDR panorama images are accurate to real life, this can cause the radiance map generated by Godot to contain sparkles when used as a background sky. This can be seen in material reflections (even on rough materials in extreme cases). Enabling [member process/hdr_clamp_exposure] can resolve this. - - - If [code]true[/code], convert the normal map from Y- (DirectX-style) to Y+ (OpenGL-style) by inverting its green color channel. This is the normal map convention expected by Godot. - More information about normal maps (including a coordinate order table for popular engines) can be found [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details]here[/url]. - - - An alternative to fixing darkened borders with [member process/fix_alpha_border] is to use premultiplied alpha. By enabling this option, the texture will be converted to this format. A premultiplied alpha texture requires specific materials to be displayed correctly: - - In 2D, a [CanvasItemMaterial] will need to be created and configured to use the [constant CanvasItemMaterial.BLEND_MODE_PREMULT_ALPHA] blend mode on [CanvasItem]s that use this texture. In custom [code]@canvas_item[/code] shaders, [code]render_mode blend_premul_alpha;[/code] should be used. - - In 3D, a [BaseMaterial3D] will need to be created and configured to use the [constant BaseMaterial3D.BLEND_MODE_PREMULT_ALPHA] blend mode on materials that use this texture. In custom [code]spatial[/code] shaders, [code]render_mode blend_premul_alpha;[/code] should be used. - - - If set to a value greater than [code]0[/code], the size of the texture is limited on import to a value smaller than or equal to the value specified here. For non-square textures, the size limit affects the longer dimension, with the shorter dimension scaled to preserve aspect ratio. Resizing is performed using cubic interpolation. - This can be used to reduce memory usage without affecting the source images, or avoid issues with textures not displaying on mobile/web platforms (as these usually can't display textures larger than 4096×4096). - - - The color channel to consider as a roughness map in this texture. Only effective if Roughness > Src Normal is not empty. - - - The path to the texture to consider as a normal map for roughness filtering on import. Specifying this can help decrease specular aliasing slightly in 3D. - Roughness filtering on import is only used in 3D rendering, not 2D. - - - The scale the SVG should be rendered at, with [code]1.0[/code] being the original design size. Higher values result in a larger image. Note that unlike font oversampling, this affects the size the SVG is rendered at in 2D. See also [member editor/scale_with_editor_scale]. - [b]Note:[/b] Only available for SVG images. - - - diff --git a/godot/modules/svg/editor/resource_importer_lottie.cpp b/godot/modules/svg/editor/resource_importer_lottie.cpp deleted file mode 100644 index c7153be9..00000000 --- a/godot/modules/svg/editor/resource_importer_lottie.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************/ -/* resource_importer_lottie.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "resource_importer_lottie.h" - -#include "core/io/dir_access.h" -#include "modules/zip/zip_reader.h" - -#include - -Ref read_lottie_json(const String &p_path) { - Error err = OK; - Ref lottie_json; - lottie_json.instantiate(); - String lottie_str = FileAccess::get_file_as_string(p_path, &err); - if (err == OK) { - err = lottie_json->parse(lottie_str, true); - } - if (err != OK) { - Ref zip_reader; - zip_reader.instantiate(); - err = zip_reader->open(p_path); - ERR_FAIL_COND_V_MSG(err != OK, nullptr, vformat("Failed to open dotLottie: %s.", error_names[err])); - String manifest_str; - PackedByteArray manifest_data = zip_reader->read_file("manifest.json", true); - err = manifest_str.parse_utf8(reinterpret_cast(manifest_data.ptr()), manifest_data.size()); - ERR_FAIL_COND_V_MSG(err != OK, nullptr, vformat("Failed to parse dotLottie manifest: %s.", error_names[err])); - Ref manifest; - manifest.instantiate(); - err = manifest->parse(manifest_str, true); - ERR_FAIL_COND_V_MSG(err != OK, nullptr, vformat("Failed to parse dotLottie manifest: %s.", error_names[err])); - Array animations = ((Dictionary)manifest->get_data())["animations"]; - String anim_file; - for (Dictionary anim : animations) { - String file = "animations/" + (String)(anim["id"]) + ".json"; - if (zip_reader->file_exists(file, true)) { - anim_file = file; - break; - } - } - ERR_FAIL_COND_V_MSG(anim_file.is_empty(), nullptr, "Animations in dotLottie manifest don't exist."); - PackedByteArray lottie_data = zip_reader->read_file(anim_file, true); - lottie_str.clear(); - err = lottie_str.parse_utf8(reinterpret_cast(lottie_data.ptr()), lottie_data.size()); - ERR_FAIL_COND_V_MSG(err != OK, nullptr, vformat("Failed to parse lottie animation %s: %s.", anim_file, error_names[err])); - err = lottie_json->parse(lottie_str, true); - ERR_FAIL_COND_V_MSG(err != OK, nullptr, vformat("Failed to parse lottie animation %s: %s.", anim_file, error_names[err])); - } - return lottie_json; -} - -Ref lottie_to_sprite_sheet(Ref p_json, float p_begin, float p_end, float p_fps, int p_columns, float p_scale, int p_size_limit, Size2i *r_sprite_size, int *r_columns, int *r_frame_count) { - std::unique_ptr sw_canvas = tvg::SwCanvas::gen(); - std::unique_ptr animation = tvg::Animation::gen(); - tvg::Picture *picture = animation->picture(); - tvg::Result res = sw_canvas->push(tvg::cast(picture)); - ERR_FAIL_COND_V(res != tvg::Result::Success, Ref()); - - String lottie_str = p_json->get_parsed_text(); - if (lottie_str.is_empty()) { - // Set p_sort_keys to false, otherwise ThorVG can't load it. - lottie_str = JSON::stringify(p_json->get_data(), "", false); - } - - res = picture->load(lottie_str.utf8(), lottie_str.utf8().size(), "lottie", true); - ERR_FAIL_COND_V_MSG(res != tvg::Result::Success, Ref(), "Failed to load Lottie."); - - float origin_width, origin_height; - picture->size(&origin_width, &origin_height); - - p_end = CLAMP(p_end, p_begin, 1); - int total_frame_count = animation->totalFrame(); - int frame_count = MAX(1, animation->duration() * CLAMP(p_end - p_begin, 0, 1) * p_fps); - int sheet_columns = p_columns <= 0 ? Math::ceil(Math::sqrt((float)frame_count)) : p_columns; - int sheet_rows = Math::ceil(((float)frame_count) / sheet_columns); - Vector2 texture_size = Vector2(origin_width * sheet_columns * p_scale, origin_height * sheet_rows * p_scale); - - const uint32_t max_dimension = 16384; - if (p_size_limit <= 0) { - p_size_limit = max_dimension; - } - if (texture_size[texture_size.max_axis_index()] > p_size_limit) { - p_scale = p_size_limit / MAX(origin_width * sheet_columns, origin_height * sheet_rows); - } - uint32_t width = MAX(1, Math::round(origin_width * p_scale)); - uint32_t height = MAX(1, Math::round(origin_height * p_scale)); - picture->size(width, height); - - uint32_t *buffer = (uint32_t *)memalloc(sizeof(uint32_t) * width * height); - memset(buffer, 0, sizeof(uint32_t) * width * height); - - sw_canvas->sync(); - res = sw_canvas->target(buffer, width, width, height, tvg::SwCanvas::ARGB8888S); - if (res != tvg::Result::Success) { - memfree(buffer); - ERR_FAIL_V_MSG(Ref(), "Couldn't set target on ThorVG canvas."); - } - - Ref image = Image::create_empty(width * sheet_columns, height * sheet_rows, false, Image::FORMAT_RGBA8); - - for (int row = 0; row < sheet_rows; row++) { - for (int column = 0; column < sheet_columns; column++) { - if (row * sheet_columns + column >= frame_count) { - break; - } - float progress = ((float)(row * sheet_columns + column)) / frame_count; - float current_frame = total_frame_count * (p_begin + (p_end - p_begin) * progress); - - animation->frame(current_frame); - res = sw_canvas->update(picture); - if (res != tvg::Result::Success) { - memfree(buffer); - ERR_FAIL_V_MSG(Ref(), "Couldn't update ThorVG pictures on canvas."); - } - res = sw_canvas->draw(); - if (res != tvg::Result::Success) { - WARN_PRINT_ONCE("Couldn't draw ThorVG pictures on canvas."); - } - res = sw_canvas->sync(); - if (res != tvg::Result::Success) { - memfree(buffer); - ERR_FAIL_V_MSG(Ref(), "Couldn't sync ThorVG canvas."); - } - - for (uint32_t y = 0; y < height; y++) { - for (uint32_t x = 0; x < width; x++) { - uint32_t n = buffer[y * width + x]; - Color color; - color.set_r8((n >> 16) & 0xff); - color.set_g8((n >> 8) & 0xff); - color.set_b8(n & 0xff); - color.set_a8((n >> 24) & 0xff); - image->set_pixel(x + width * column, y + height * row, color); - } - } - sw_canvas->clear(false); - } - } - memfree(buffer); - if (r_sprite_size) { - *r_sprite_size = Size2i(width, height); - } - if (r_columns) { - *r_columns = sheet_columns; - } - if (r_frame_count) { - *r_frame_count = frame_count; - } - return image; -} - -String ResourceImporterLottie::get_importer_name() const { - return "lottie_compressed_texture_2d"; -} - -String ResourceImporterLottie::get_visible_name() const { - return "CompressedTexture2D"; -} - -int ResourceImporterLottie::get_preset_count() const { - return 1; -} - -String ResourceImporterLottie::get_preset_name(int p_idx) const { - return p_idx == 0 ? importer_ctex->get_preset_name(ResourceImporterTexture::PRESET_2D) : ""; -} - -void ResourceImporterLottie::get_import_options(const String &p_path, List *r_options, int p_preset) const { - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "lottie/size_limit", PROPERTY_HINT_RANGE, "0,4096,1,or_greater"), 2048)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lottie/scale", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater"), 1)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lottie/begin", PROPERTY_HINT_RANGE, "0,1,0.001"), 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lottie/end", PROPERTY_HINT_RANGE, "0,1,0.001"), 1)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lottie/fps", PROPERTY_HINT_RANGE, "0,60,0.1,or_greater"), 30)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "lottie/columns", PROPERTY_HINT_RANGE, "0,16,1,or_greater"), 0)); - if (r_options->is_empty()) { - return; - } - importer_ctex->get_import_options(p_path, r_options, p_preset); -} - -bool ResourceImporterLottie::get_option_visibility(const String &p_path, const String &p_option, const HashMap &p_options) const { - return importer_ctex->get_option_visibility(p_path, p_option, p_options); -} - -void ResourceImporterLottie::get_recognized_extensions(List *p_extensions) const { - p_extensions->push_back("lottie"); -} - -String ResourceImporterLottie::get_save_extension() const { - return importer_ctex->get_save_extension(); -} - -String ResourceImporterLottie::get_resource_type() const { - return importer_ctex->get_resource_type(); -} - -Error ResourceImporterLottie::import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap &p_options, List *r_platform_variants, List *r_gen_files, Variant *r_metadata) { - Error err = OK; - Ref lottie_json = read_lottie_json(p_source_file); - - ERR_FAIL_COND_V(lottie_json.is_null(), ERR_INVALID_DATA); - - const int size_limit = p_options["lottie/size_limit"]; - const float scale = p_options["lottie/scale"]; - const float begin = p_options["lottie/begin"]; - const float end = p_options["lottie/end"]; - const float fps = p_options["lottie/fps"]; - const int columns = p_options["lottie/columns"]; - - Size2i sprite_size; - int column_r; - int frame_count; - Ref image = lottie_to_sprite_sheet(lottie_json, begin, end, fps, columns, scale, size_limit, &sprite_size, &column_r, &frame_count); - ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_DATA); - String tmp_image = p_save_path + ".tmp.png"; - err = image->save_png(tmp_image); - if (err == OK) { - err = importer_ctex->import(p_source_id, tmp_image, p_save_path, p_options, r_platform_variants, r_gen_files, r_metadata); - Ref d = DirAccess::create(DirAccess::ACCESS_RESOURCES); - err = d->remove(tmp_image); - if (r_metadata) { - Dictionary meta; - meta["sprite_size"] = sprite_size; - meta["columns"] = column_r; - meta["frame_count"] = frame_count; - meta["fps"] = fps; - *r_metadata = meta; - } - } - return err; -} - -ResourceImporterLottie::ResourceImporterLottie() { - importer_ctex.instantiate(); -} diff --git a/godot/modules/svg/register_types.cpp b/godot/modules/svg/register_types.cpp index 9dd6593d..82d816d8 100644 --- a/godot/modules/svg/register_types.cpp +++ b/godot/modules/svg/register_types.cpp @@ -31,9 +31,6 @@ #include "register_types.h" #include "image_loader_svg.h" -#ifdef TOOLS_ENABLED -#include "editor/resource_importer_lottie.h" -#endif // TOOLS_ENABLED #include @@ -58,18 +55,6 @@ void initialize_svg_module(ModuleInitializationLevel p_level) { image_loader_svg.instantiate(); ImageLoader::add_image_format_loader(image_loader_svg); - -#ifdef TOOLS_ENABLED - Ref resource_importer_lottie; - resource_importer_lottie.instantiate(); - ResourceFormatImporter::get_singleton()->add_importer(resource_importer_lottie); - - ClassDB::APIType prev_api = ClassDB::get_current_api(); - ClassDB::set_current_api(ClassDB::API_EDITOR); - // Required to document import options in the class reference. - GDREGISTER_CLASS(ResourceImporterLottie); - ClassDB::set_current_api(prev_api); -#endif // TOOLS_ENABLED } void uninitialize_svg_module(ModuleInitializationLevel p_level) { @@ -84,6 +69,5 @@ void uninitialize_svg_module(ModuleInitializationLevel p_level) { ImageLoader::remove_image_format_loader(image_loader_svg); image_loader_svg.unref(); - tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/godot/modules/webrtc/SCsub b/godot/modules/webrtc/SCsub index c908f4b3..0c5f2c9d 100644 --- a/godot/modules/webrtc/SCsub +++ b/godot/modules/webrtc/SCsub @@ -6,150 +6,8 @@ Import("env_modules") env_webrtc = env_modules.Clone() -thirdparty_obj = [] - if env["platform"] == "web": # Our JavaScript/C++ interface. env.AddJSLibraries(["library_godot_webrtc.js"]) -elif env["builtin_libdatachannel"] and env["libdatachannel"]: - # Thirdparty source files - thirdparty_dir = "#thirdparty/libdatachannel/" - thirdparty_sources = [ - "deps/libjuice/src/addr.c", - "deps/libjuice/src/agent.c", - "deps/libjuice/src/base64.c", - "deps/libjuice/src/conn.c", - "deps/libjuice/src/conn_mux.c", - "deps/libjuice/src/conn_poll.c", - "deps/libjuice/src/conn_thread.c", - "deps/libjuice/src/const_time.c", - "deps/libjuice/src/crc32.c", - "deps/libjuice/src/hash.c", - "deps/libjuice/src/hmac.c", - "deps/libjuice/src/ice.c", - "deps/libjuice/src/juice.c", - "deps/libjuice/src/log.c", - "deps/libjuice/src/random.c", - "deps/libjuice/src/server.c", - "deps/libjuice/src/stun.c", - "deps/libjuice/src/timestamp.c", - "deps/libjuice/src/turn.c", - "deps/libjuice/src/udp.c", - "deps/usrsctp/usrsctplib/netinet/sctputil.c", - "deps/usrsctp/usrsctplib/netinet/sctp_asconf.c", - "deps/usrsctp/usrsctplib/netinet/sctp_auth.c", - "deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.c", - "deps/usrsctp/usrsctplib/netinet/sctp_callout.c", - "deps/usrsctp/usrsctplib/netinet/sctp_cc_functions.c", - "deps/usrsctp/usrsctplib/netinet/sctp_crc32.c", - "deps/usrsctp/usrsctplib/netinet/sctp_indata.c", - "deps/usrsctp/usrsctplib/netinet/sctp_input.c", - "deps/usrsctp/usrsctplib/netinet/sctp_output.c", - "deps/usrsctp/usrsctplib/netinet/sctp_pcb.c", - "deps/usrsctp/usrsctplib/netinet/sctp_peeloff.c", - "deps/usrsctp/usrsctplib/netinet/sctp_sha1.c", - "deps/usrsctp/usrsctplib/netinet/sctp_ss_functions.c", - "deps/usrsctp/usrsctplib/netinet/sctp_sysctl.c", - "deps/usrsctp/usrsctplib/netinet/sctp_timer.c", - "deps/usrsctp/usrsctplib/netinet/sctp_userspace.c", - "deps/usrsctp/usrsctplib/netinet/sctp_usrreq.c", - "deps/usrsctp/usrsctplib/netinet6/sctp6_usrreq.c", - "deps/usrsctp/usrsctplib/user_environment.c", - "deps/usrsctp/usrsctplib/user_mbuf.c", - "deps/usrsctp/usrsctplib/user_recv_thread.c", - "deps/usrsctp/usrsctplib/user_socket.c", - "src/candidate.cpp", - "src/channel.cpp", - "src/configuration.cpp", - "src/datachannel.cpp", - "src/description.cpp", - "src/global.cpp", - "src/exception_wrapper_godot.cpp", - "src/impl/certificate.cpp", - "src/impl/channel.cpp", - "src/impl/datachannel.cpp", - "src/impl/dtlstransport.cpp", - "src/impl/icetransport.cpp", - "src/impl/init.cpp", - "src/impl/logcounter.cpp", - "src/impl/peerconnection.cpp", - "src/impl/processor.cpp", - "src/impl/sctptransport.cpp", - "src/impl/threadpool.cpp", - "src/impl/tls.cpp", - "src/impl/transport.cpp", - "src/impl/utils.cpp", - "src/message.cpp", - "src/peerconnection.cpp", - ] - thirdparty_sources = [thirdparty_dir + s for s in thirdparty_sources] - - thirdparty_includes = [ - "include", - "include/rtc", - "src", - "deps/usrsctp/usrsctplib", - "deps/plog/include", - "deps/libjuice/include", - "deps/libjuice/include/juice", - ] - thirdparty_includes = [thirdparty_dir + s for s in thirdparty_includes] - - env_webrtc.Prepend(CPPPATH=thirdparty_includes) - if env["builtin_mbedtls"]: - env_webrtc.Prepend(CPPPATH=["#thirdparty/mbedtls/include"]) - env_webrtc.Append( - CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')] - ) - env_webrtc.Depends(thirdparty_obj, "#thirdparty/mbedtls/include/godot_module_mbedtls_config.h") - - env_webrtc.Append(CPPDEFINES=["HAVE_CONFIG_H"]) - if env["arch"] in ["x86_64", "x86_32"]: - env_webrtc.Append(CPPDEFINES=["HAVE_X86", "HAVE_CISC"]) - else: - env_webrtc.Append(CPPDEFINES=["HAVE_RISC"]) - - if env["platform"] == "windows": - env_webrtc.Append(CPPDEFINES=["HAVE_WINSOCK2_H", "HAVE_WINDOWS_H", "WIN32_LEAN_AND_MEAN", "NOMINMAX"]) - else: - env_webrtc.Append(CPPDEFINES=["HAVE_NETINET_IN_H", "HAVE_ARPA_INET_H", "HAVE_SYS_SOCKET_H", "HAVE_UNISTD_H"]) - - env_webrtc.Append( - CPPDEFINES=[ - "RTC_STATIC", - "RTC_ENABLE_WEBSOCKET=0", - "RTC_ENABLE_MEDIA=0", - "USE_GNUTLS=0", - "USE_NICE=0", - "RTC_SYSTEM_SRTP=0", - "MBEDTLS", - "GCM", - "USE_MBEDTLS", - "USE_NICE=0", - "RTC_SYSTEM_JUICE=0" "USE_NETTLE=0", - "JUICE_STATIC", - "SCTP_PROCESS_LEVEL_LOCKS", - "SCTP_SIMPLE_ALLOCATOR", - "__Userspace__", - ] - ) - if env["target"] == "template_release": - # Debug logging takes 100KB. May be better to check for env.debug_features - env_webrtc.Append(CPPDEFINES=["GODOT_JUICE_DISABLE_LOG", "GODOT_PLOG_DISABLE_LOG"]) - - env_thirdparty = env_webrtc.Clone() - env_thirdparty.disable_warnings() - env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) - env.modules_sources += thirdparty_obj - -if env["platform"] != "web" and env["libdatachannel"]: - env_webrtc.Append(CPPDEFINES=["ENABLE_LIBDATACHANNEL"]) - -module_obj = [] - -env_webrtc.add_source_files(module_obj, "*.cpp") -env.modules_sources += module_obj - -# Needed to force rebuilding the module files when the thirdparty library is updated. -env.Depends(module_obj, thirdparty_obj) +env_webrtc.add_source_files(env.modules_sources, "*.cpp") diff --git a/godot/modules/webrtc/webrtc_lib_data_channel.cpp b/godot/modules/webrtc/webrtc_lib_data_channel.cpp deleted file mode 100644 index 1eaa3899..00000000 --- a/godot/modules/webrtc/webrtc_lib_data_channel.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/**************************************************************************/ -/* webrtc_lib_data_channel.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifdef ENABLE_LIBDATACHANNEL - -#include "webrtc_lib_data_channel.h" -#include "rtc/exception_wrapper_godot.hpp" - -#include -#include -#include - -// DataChannel -void WebRTCLibDataChannel::bind_channel(std::shared_ptr p_channel, bool p_negotiated) { - ERR_FAIL_COND(!p_channel); - - channel = p_channel; - negotiated = p_negotiated; - - // Binding this should be fine as long as we call close when going out of scope. - p_channel->onMessage([this](auto message) { - if (std::holds_alternative(message)) { - rtc::string str = std::get(message); - queue_packet(reinterpret_cast(str.c_str()), str.size(), WRITE_MODE_TEXT); - } else if (std::holds_alternative(message)) { - rtc::binary bin = std::get(message); - queue_packet(reinterpret_cast(&bin[0]), bin.size(), WRITE_MODE_BINARY); - } else { - ERR_PRINT("Message parsing bug. Unknown message type."); - } - }); - p_channel->onOpen([this]() { - channel_state = STATE_OPEN; - }); - p_channel->onClosed([this]() { - channel_state = STATE_CLOSED; - }); - p_channel->onError([](auto error) { - ERR_PRINT("Channel Error: " + String(std::string(error).c_str())); - }); -} - -void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size, WriteMode p_message_type) { - MutexLock lock(mutex); - - Vector packet; - packet.resize(size + 1); - packet.ptrw()[0] = (uint8_t)p_message_type; - memcpy(packet.ptrw() + 1, data, size); - - if (packet_queue_head != 0) { - for (int i = packet_queue_head; i < packet_queue.size(); i++) { - packet_queue.set(i, packet_queue[i - packet_queue_head]); - } - packet_queue.resize(packet_queue.size() - packet_queue_head + 1); - packet_queue.set(packet_queue.size() - 1, packet); - packet_queue_head = 0; - } else { - packet_queue.push_back(packet); - } -} - -void WebRTCLibDataChannel::set_write_mode(WriteMode p_mode) { - ERR_FAIL_COND(p_mode != WRITE_MODE_TEXT && p_mode != WRITE_MODE_BINARY); - write_mode = p_mode; -} - -WebRTCDataChannel::WriteMode WebRTCLibDataChannel::get_write_mode() const { - return write_mode; -} - -bool WebRTCLibDataChannel::was_string_packet() const { - return current_packet.ptr()[0] == (uint8_t)WRITE_MODE_TEXT; -} - -WebRTCDataChannel::ChannelState WebRTCLibDataChannel::get_ready_state() const { - ERR_FAIL_COND_V(!channel, STATE_CLOSED); - return channel_state; -} - -String WebRTCLibDataChannel::get_label() const { - ERR_FAIL_COND_V(!channel, ""); - return channel->label().c_str(); -} - -bool WebRTCLibDataChannel::is_ordered() const { - ERR_FAIL_COND_V(!channel, false); - return channel->reliability().unordered == false; -} - -int32_t WebRTCLibDataChannel::get_id() const { - ERR_FAIL_COND_V(!channel, -1); - return channel->id().value_or(-1); -} - -int32_t WebRTCLibDataChannel::get_max_packet_life_time() const { - ERR_FAIL_COND_V(!channel, 0); - return channel->reliability().type == rtc::Reliability::Type::Timed ? std::get(channel->reliability().rexmit).count() : -1; -} - -int32_t WebRTCLibDataChannel::get_max_retransmits() const { - ERR_FAIL_COND_V(!channel, 0); - return channel->reliability().type == rtc::Reliability::Type::Rexmit ? std::get(channel->reliability().rexmit) : -1; -} - -String WebRTCLibDataChannel::get_protocol() const { - ERR_FAIL_COND_V(!channel, ""); - return channel->protocol().c_str(); -} - -bool WebRTCLibDataChannel::is_negotiated() const { - ERR_FAIL_COND_V(!channel, false); - return negotiated; -} - -int32_t WebRTCLibDataChannel::get_buffered_amount() const { - ERR_FAIL_COND_V(!channel, 0); - return channel->bufferedAmount(); -} - -Error WebRTCLibDataChannel::poll() { - return OK; -} - -void WebRTCLibDataChannel::close() { - LibDataChannelExceptionWrapper::close_data_channel(channel); -} - -Error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int &r_len) { - MutexLock lock(mutex); - - ERR_FAIL_COND_V(packet_queue_head >= packet_queue.size(), ERR_UNAVAILABLE); - - // Update current packet and pop queue - current_packet = packet_queue[packet_queue_head]; - packet_queue.set(packet_queue_head, Vector()); - packet_queue_head++; - - // Set out buffer and size (buffer will be gone at next get_packet or close) - *r_buffer = current_packet.ptrw() + 1; - r_len = current_packet.size() - 1; - - return OK; -} - -Error WebRTCLibDataChannel::put_packet(const uint8_t *p_buffer, int p_len) { - ERR_FAIL_COND_V(!channel, FAILED); - ERR_FAIL_COND_V(channel->isClosed(), FAILED); - std::string error; - // Only text and binary modes exist for now, so we made it a boolean. - if (!LibDataChannelExceptionWrapper::put_packet(channel, p_buffer, p_len, write_mode == WRITE_MODE_TEXT, error)) { - ERR_FAIL_V_MSG(FAILED, error.c_str()); - } - return OK; -} - -int32_t WebRTCLibDataChannel::get_available_packet_count() const { - return packet_queue.size() - packet_queue_head; -} - -int32_t WebRTCLibDataChannel::get_max_packet_size() const { - return 16384; // See RFC-8831 section 6.6: https://datatracker.ietf.org/doc/rfc8831/ -} - -WebRTCLibDataChannel::WebRTCLibDataChannel() { -} - -WebRTCLibDataChannel::~WebRTCLibDataChannel() { - close(); - channel = nullptr; -} - -#endif // ENABLE_LIBDATACHANNEL diff --git a/godot/modules/webrtc/webrtc_lib_data_channel.h b/godot/modules/webrtc/webrtc_lib_data_channel.h deleted file mode 100644 index 7a5525d5..00000000 --- a/godot/modules/webrtc/webrtc_lib_data_channel.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************/ -/* webrtc_lib_data_channel.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef WEBRTC_LIB_DATA_CHANNEL_H -#define WEBRTC_LIB_DATA_CHANNEL_H - -#ifdef ENABLE_LIBDATACHANNEL -#include - -#include "core/os/mutex.h" -#include "core/templates/vector.h" -#include "webrtc_data_channel.h" - -#include "rtc/rtc.hpp" - -class WebRTCLibDataChannel : public WebRTCDataChannel { - GDCLASS(WebRTCLibDataChannel, WebRTCDataChannel); - -private: - Mutex mutex; - int packet_queue_head = 0; - Vector> packet_queue; - Vector current_packet; - std::shared_ptr channel = nullptr; - - WriteMode write_mode = WRITE_MODE_BINARY; - ChannelState channel_state = STATE_CONNECTING; - bool negotiated = false; - - void queue_packet(const uint8_t *data, uint32_t size, WriteMode p_message_type); - -protected: - static void _bind_methods() {} - -public: - /* PacketPeer */ - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual int32_t get_available_packet_count() const override; - virtual int32_t get_max_packet_size() const override; - - /* WebRTCDataChannel */ - Error poll() override; - void close() override; - - void set_write_mode(WriteMode p_mode) override; - WriteMode get_write_mode() const override; - bool was_string_packet() const override; - - ChannelState get_ready_state() const override; - String get_label() const override; - bool is_ordered() const override; - int32_t get_id() const override; - int32_t get_max_packet_life_time() const override; - int32_t get_max_retransmits() const override; - String get_protocol() const override; - bool is_negotiated() const override; - int32_t get_buffered_amount() const override; - - void bind_channel(std::shared_ptr p_channel, bool p_negotiated); - - WebRTCLibDataChannel(); - ~WebRTCLibDataChannel(); -}; - -#endif // ENABLE_LIBDATACHANNEL - -#endif // WEBRTC_LIB_DATA_CHANNEL_H diff --git a/godot/modules/webrtc/webrtc_lib_peer_connection.cpp b/godot/modules/webrtc/webrtc_lib_peer_connection.cpp deleted file mode 100644 index c2358ac5..00000000 --- a/godot/modules/webrtc/webrtc_lib_peer_connection.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/**************************************************************************/ -/* webrtc_lib_peer_connection.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifdef ENABLE_LIBDATACHANNEL - -#include "webrtc_lib_peer_connection.h" -#include "rtc/exception_wrapper_godot.hpp" -#include "webrtc_lib_data_channel.h" - -Error WebRTCLibPeerConnection::_parse_ice_server(rtc::Configuration &r_config, Dictionary p_server) { - ERR_FAIL_COND_V(!p_server.has("urls"), ERR_INVALID_PARAMETER); - - // Parse mandatory URL - Array urls; - Variant urls_var = p_server["urls"]; - if (urls_var.get_type() == Variant::STRING) { - urls.push_back(urls_var); - } else if (urls_var.get_type() == Variant::ARRAY) { - urls = urls_var; - } else { - ERR_FAIL_V(ERR_INVALID_PARAMETER); - } - // Parse credentials (only meaningful for TURN, only support password) - String username; - String credential; - if (p_server.has("username") && p_server["username"].get_type() == Variant::STRING) { - username = p_server["username"]; - } - if (p_server.has("credential") && p_server["credential"].get_type() == Variant::STRING) { - credential = p_server["credential"]; - } - for (int i = 0; i < urls.size(); i++) { - rtc::IceServer srv(urls[i].operator String().utf8().get_data()); - srv.username = username.utf8().get_data(); - srv.password = credential.utf8().get_data(); - r_config.iceServers.push_back(srv); - } - return OK; -} - -Error WebRTCLibPeerConnection::_parse_channel_config(rtc::DataChannelInit &r_config, const Dictionary &p_dict) { - Variant nil; - Variant v; - if (p_dict.has("negotiated")) { - r_config.negotiated = p_dict["negotiated"].operator bool(); - } - if (p_dict.has("id")) { - r_config.id = uint16_t(p_dict["id"].operator int32_t()); - } - // If negotiated it must have an ID, and ID only makes sense when negotiated. - ERR_FAIL_COND_V(r_config.negotiated != r_config.id.has_value(), ERR_INVALID_PARAMETER); - // Channels cannot be both time-constrained and retry-constrained. - ERR_FAIL_COND_V(p_dict.has("maxPacketLifeTime") && p_dict.has("maxRetransmits"), ERR_INVALID_PARAMETER); - if (p_dict.has("maxPacketLifeTime")) { - r_config.reliability.type = rtc::Reliability::Type::Timed; - r_config.reliability.rexmit = std::chrono::milliseconds(p_dict["maxPacketLifeTime"].operator int32_t()); - } else if (p_dict.has("maxRetransmits")) { - r_config.reliability.type = rtc::Reliability::Type::Rexmit; - r_config.reliability.rexmit = p_dict["maxRetransmits"].operator int32_t(); - } - if (p_dict.has("ordered") && p_dict["ordered"].operator bool() == false) { - r_config.reliability.unordered = true; - } - if (p_dict.has("protocol")) { - r_config.protocol = p_dict["protocol"].operator String().utf8().get_data(); - } - return OK; -} - -WebRTCPeerConnection::ConnectionState WebRTCLibPeerConnection::get_connection_state() const { - ERR_FAIL_COND_V(peer_connection == nullptr, STATE_CLOSED); - - rtc::PeerConnection::State state = peer_connection->state(); - switch (state) { - case rtc::PeerConnection::State::New: - return STATE_NEW; - case rtc::PeerConnection::State::Connecting: - return STATE_CONNECTING; - case rtc::PeerConnection::State::Connected: - return STATE_CONNECTED; - case rtc::PeerConnection::State::Disconnected: - return STATE_DISCONNECTED; - case rtc::PeerConnection::State::Failed: - return STATE_FAILED; - default: - return STATE_CLOSED; - } -} - -WebRTCLibPeerConnection::GatheringState WebRTCLibPeerConnection::get_gathering_state() const { - ERR_FAIL_COND_V(peer_connection == nullptr, GATHERING_STATE_NEW); - - rtc::PeerConnection::GatheringState state = peer_connection->gatheringState(); - switch (state) { - case rtc::PeerConnection::GatheringState::New: - return GATHERING_STATE_NEW; - case rtc::PeerConnection::GatheringState::InProgress: - return GATHERING_STATE_GATHERING; - case rtc::PeerConnection::GatheringState::Complete: - return GATHERING_STATE_COMPLETE; - default: - return GATHERING_STATE_NEW; - } -} - -WebRTCLibPeerConnection::SignalingState WebRTCLibPeerConnection::get_signaling_state() const { - ERR_FAIL_COND_V(peer_connection == nullptr, SIGNALING_STATE_CLOSED); - - rtc::PeerConnection::SignalingState state = peer_connection->signalingState(); - switch (state) { - case rtc::PeerConnection::SignalingState::Stable: - return SIGNALING_STATE_STABLE; - case rtc::PeerConnection::SignalingState::HaveLocalOffer: - return SIGNALING_STATE_HAVE_LOCAL_OFFER; - case rtc::PeerConnection::SignalingState::HaveRemoteOffer: - return SIGNALING_STATE_HAVE_REMOTE_OFFER; - case rtc::PeerConnection::SignalingState::HaveLocalPranswer: - return SIGNALING_STATE_HAVE_LOCAL_PRANSWER; - case rtc::PeerConnection::SignalingState::HaveRemotePranswer: - return SIGNALING_STATE_HAVE_REMOTE_PRANSWER; - default: - return SIGNALING_STATE_CLOSED; - } -} - -Error WebRTCLibPeerConnection::initialize(Dictionary p_config) { - rtc::Configuration config = {}; - if (p_config.has("iceServers") && p_config["iceServers"].get_type() == Variant::ARRAY) { - Array servers = p_config["iceServers"]; - for (int i = 0; i < servers.size(); i++) { - ERR_FAIL_COND_V(servers[i].get_type() != Variant::DICTIONARY, ERR_INVALID_PARAMETER); - Dictionary server = servers[i]; - Error err = _parse_ice_server(config, server); - ERR_FAIL_COND_V(err != OK, FAILED); - } - } - return _create_pc(config); -} - -Ref WebRTCLibPeerConnection::create_data_channel(String p_channel, Dictionary p_channel_config) { - ERR_FAIL_COND_V(!peer_connection, nullptr); - - // Read config from dictionary - rtc::DataChannelInit config; - - Error err = _parse_channel_config(config, p_channel_config); - ERR_FAIL_COND_V(err != OK, nullptr); - - std::string error; - std::shared_ptr ch = LibDataChannelExceptionWrapper::create_data_channel(peer_connection, p_channel.utf8().get_data(), config, error); - ERR_FAIL_COND_V_MSG(ch == nullptr, nullptr, vformat("Failed to create peer connection. %s", error.c_str())); - - Ref out; - out.instantiate(); - // Bind the library data channel to our object. - bool negotiated = ch->id().has_value(); - out->bind_channel(ch, negotiated); - return out; -} - -Error WebRTCLibPeerConnection::create_offer() { - ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED); - ERR_FAIL_COND_V(get_connection_state() != STATE_NEW, FAILED); - std::string error; - if (!LibDataChannelExceptionWrapper::create_offer(peer_connection, error)) { - ERR_FAIL_V_MSG(FAILED, error.c_str()); - } - return OK; -} - -Error WebRTCLibPeerConnection::set_remote_description(String p_type, String p_sdp) { - ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED); - std::string error; - if (!LibDataChannelExceptionWrapper::set_remote_description(peer_connection, p_type.utf8().get_data(), p_sdp.utf8().get_data(), error)) { - ERR_FAIL_V_MSG(FAILED, error.c_str()); - } - return OK; -} - -Error WebRTCLibPeerConnection::set_local_description(String p_type, String p_sdp) { - ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED); - // XXX Library quirk. It doesn't seem possible to create offers/answers without setting the local description. - // Ignore this call for now to avoid crash (it's already set automatically!). - // peer_connection->setLocalDescription(p_type == String("offer") ? rtc::Description::Type::Offer : rtc::Description::Type::Answer); - return OK; -} - -Error WebRTCLibPeerConnection::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { - ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED); - std::string error; - if (!LibDataChannelExceptionWrapper::add_ice_candidate(peer_connection, sdpMidName.utf8().get_data(), sdpName.utf8().get_data(), error)) { - ERR_FAIL_V_MSG(FAILED, error.c_str()); - } - return OK; -} - -Error WebRTCLibPeerConnection::poll() { - ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED); - - { - MutexLock lock(mutex_signal_queue); - // Vector is missing swap() - Vector tmp = signal_queue_processing; - signal_queue_processing = signal_queue; - signal_queue = tmp; - } - QueuedSignal *signal_ptr = signal_queue_processing.ptrw(); - for (int i = 0; i < signal_queue_processing.size(); i++) { - signal_ptr[i].emit(this); - } - signal_queue_processing.clear(); - return OK; -} - -void WebRTCLibPeerConnection::close() { - if (peer_connection != nullptr) { - LibDataChannelExceptionWrapper::close_peer_connection(peer_connection); - } - - MutexLock lock(mutex_signal_queue); - signal_queue.clear(); -} - -Error WebRTCLibPeerConnection::_create_pc(rtc::Configuration &r_config) { - // Prevents libdatachannel from automatically creating offers. - r_config.disableAutoNegotiation = true; - - std::string error; - peer_connection = LibDataChannelExceptionWrapper::create_peer_connection(r_config, error); - ERR_FAIL_COND_V_MSG(!peer_connection, FAILED, vformat("Failed to create peer connection. %s", error.c_str())); - - // Binding this should be fine as long as we call close when going out of scope. - peer_connection->onLocalDescription([this](rtc::Description description) { - String type = description.type() == rtc::Description::Type::Offer ? "offer" : "answer"; - queue_signal("session_description_created", 2, type, String(std::string(description).c_str())); - }); - peer_connection->onLocalCandidate([this](rtc::Candidate candidate) { - queue_signal("ice_candidate_created", 3, String(candidate.mid().c_str()), 0, String(candidate.candidate().c_str())); - }); - peer_connection->onDataChannel([this](std::shared_ptr channel) { - Ref new_data_channel; - new_data_channel.instantiate(); - new_data_channel->bind_channel(channel, false); - queue_signal("data_channel_received", 1, new_data_channel); - }); - /* - peer_connection->onStateChange([](rtc::PeerConnection::State state) { - std::cout << "[State: " << state << "]" << std::endl; - }); - - peer_connection->onGatheringStateChange([](rtc::PeerConnection::GatheringState state) { - std::cout << "[Gathering State: " << state << "]" << std::endl; - }); - */ - return OK; -} - -WebRTCLibPeerConnection::WebRTCLibPeerConnection() { -#ifdef DEBUG_ENABLED - static bool debug_initialized = (rtc::InitLogger(rtc::LogLevel::Debug), true); - (void)debug_initialized; -#endif - initialize(Dictionary()); -} - -WebRTCLibPeerConnection::~WebRTCLibPeerConnection() { - close(); -} - -void WebRTCLibPeerConnection::queue_signal(String p_name, int p_argc, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) { - MutexLock lock(mutex_signal_queue); - const Variant argv[3] = { p_arg1, p_arg2, p_arg3 }; - signal_queue.push_back(QueuedSignal(p_name, p_argc, argv)); -} - -#endif // ENABLE_LIBDATACHANNEL diff --git a/godot/modules/webrtc/webrtc_lib_peer_connection.h b/godot/modules/webrtc/webrtc_lib_peer_connection.h deleted file mode 100644 index ba92412c..00000000 --- a/godot/modules/webrtc/webrtc_lib_peer_connection.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************/ -/* webrtc_lib_peer_connection.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef WEBRTC_LIB_PEER_CONNECTION_H -#define WEBRTC_LIB_PEER_CONNECTION_H - -#ifdef ENABLE_LIBDATACHANNEL - -#include "core/os/mutex.h" -#include "core/templates/vector.h" -#include "webrtc_peer_connection.h" - -#include "rtc/rtc.hpp" - -class WebRTCLibPeerConnection : public WebRTCPeerConnection { - GDCLASS(WebRTCLibPeerConnection, WebRTCPeerConnection); - -private: - std::shared_ptr peer_connection = nullptr; - - Error _create_pc(rtc::Configuration &r_config); - Error _parse_ice_server(rtc::Configuration &r_config, Dictionary p_server); - Error _parse_channel_config(rtc::DataChannelInit &r_config, const Dictionary &p_dict); - -protected: - static void _bind_methods() {} - -public: - ConnectionState get_connection_state() const override; - GatheringState get_gathering_state() const override; - SignalingState get_signaling_state() const override; - - Error initialize(Dictionary p_config) override; - Ref create_data_channel(String p_channel, Dictionary p_channel_config) override; - Error create_offer() override; - Error set_remote_description(String type, String sdp) override; - Error set_local_description(String type, String sdp) override; - Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override; - Error poll() override; - void close() override; - - WebRTCLibPeerConnection(); - ~WebRTCLibPeerConnection(); - -private: - struct QueuedSignal { - private: - String method; - Variant argv[3]; - int argc = 0; - - public: - QueuedSignal() {} - QueuedSignal(String p_method, int p_argc, const Variant *p_argv) { - method = p_method; - argc = p_argc; - for (int i = 0; i < argc; i++) { - argv[i] = p_argv[i]; - } - } - - void emit(Object *p_object) { - if (argc == 0) { - p_object->emit_signal(method); - } else if (argc == 1) { - p_object->emit_signal(method, argv[0]); - } else if (argc == 2) { - p_object->emit_signal(method, argv[0], argv[1]); - } else if (argc == 3) { - p_object->emit_signal(method, argv[0], argv[1], argv[2]); - } - } - }; - - Mutex mutex_signal_queue; - Vector signal_queue; - Vector signal_queue_processing; - - void queue_signal(String p_name, int p_argc, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant()); -}; - -#endif // ENABLE_LIBDATACHANNEL - -#endif // WEBRTC_LIB_PEER_CONNECTION_H diff --git a/godot/modules/webrtc/webrtc_peer_connection.cpp b/godot/modules/webrtc/webrtc_peer_connection.cpp index 865b2daf..69be873f 100644 --- a/godot/modules/webrtc/webrtc_peer_connection.cpp +++ b/godot/modules/webrtc/webrtc_peer_connection.cpp @@ -35,9 +35,6 @@ #endif #include "webrtc_peer_connection_extension.h" -#if defined(ENABLE_LIBDATACHANNEL) -#include "webrtc_lib_peer_connection.h" -#endif StringName WebRTCPeerConnection::default_extension; @@ -51,12 +48,8 @@ WebRTCPeerConnection *WebRTCPeerConnection::create(bool p_notify_postinitialize) return static_cast(ClassDB::creator(p_notify_postinitialize)); #else if (default_extension == StringName()) { -#if defined(ENABLE_LIBDATACHANNEL) - return memnew(WebRTCLibPeerConnection); -#else WARN_PRINT_ONCE("No default WebRTC extension configured."); return static_cast(ClassDB::creator(p_notify_postinitialize)); -#endif } Object *obj = nullptr; if (p_notify_postinitialize) { diff --git a/godot/platform/linuxbsd/detect.py b/godot/platform/linuxbsd/detect.py index 769c1492..6c9f3368 100644 --- a/godot/platform/linuxbsd/detect.py +++ b/godot/platform/linuxbsd/detect.py @@ -73,7 +73,7 @@ def get_flags(): def configure(env: "SConsEnvironment"): # Validate arch. - supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"] + supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "loongarch64"] validate_arch(env["arch"], get_name(), supported_arches) ## Build type @@ -278,11 +278,6 @@ def configure(env: "SConsEnvironment"): if not env["builtin_libwebp"]: env.ParseConfig("pkg-config libwebp --cflags --libs") - if not env["builtin_libdatachannel"]: - # libdatachannel does not provide a pkgconfig config yet. - # Goes directly into /usr/lib64 based on example RPM file in Fedora 39. - env.Append(LIBS=["datachannel"]) - if not env["builtin_mbedtls"]: # mbedTLS only provides a pkgconfig file since 3.6.0, but we still support 2.28.x, # so fallback to manually specifying LIBS if it fails. diff --git a/godot/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml b/godot/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml index a44c8620..7b509506 100644 --- a/godot/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml +++ b/godot/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml @@ -11,7 +11,7 @@ Application executable architecture. - Supported architectures: [code]x86_32[/code], [code]x86_64[/code], [code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]ppc64[/code], and [code]ppc32[/code]. + Supported architectures: [code]x86_32[/code], [code]x86_64[/code], [code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]ppc64[/code], [code]ppc32[/code], and [code]loongarch64[/code]. Official export templates include [code]x86_32[/code] and [code]x86_64[/code] binaries only. diff --git a/godot/platform/linuxbsd/export/export_plugin.cpp b/godot/platform/linuxbsd/export/export_plugin.cpp index 69ba742f..7cd77dd5 100644 --- a/godot/platform/linuxbsd/export/export_plugin.cpp +++ b/godot/platform/linuxbsd/export/export_plugin.cpp @@ -180,7 +180,7 @@ bool EditorExportPlatformLinuxBSD::get_export_option_visibility(const EditorExpo void EditorExportPlatformLinuxBSD::get_export_options(List *r_options) const { EditorExportPlatformPC::get_export_options(r_options); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32,loongarch64"), "x86_64")); String run_script = "#!/usr/bin/env bash\n" "export DISPLAY=:0\n" @@ -282,6 +282,8 @@ String EditorExportPlatformLinuxBSD::_get_exe_arch(const String &p_path) const { return "arm64"; case 0x00f3: return "rv64"; + case 0x0102: + return "loongarch64"; default: return "unknown"; } diff --git a/godot/platform/linuxbsd/os_linuxbsd.cpp b/godot/platform/linuxbsd/os_linuxbsd.cpp index b309e8d8..9fba97d5 100644 --- a/godot/platform/linuxbsd/os_linuxbsd.cpp +++ b/godot/platform/linuxbsd/os_linuxbsd.cpp @@ -184,7 +184,7 @@ String OS_LinuxBSD::get_processor_name() const { while (!f->eof_reached()) { const String line = f->get_line(); - if (line.contains("model name")) { + if (line.to_lower().contains("model name")) { return line.split(":")[1].strip_edges(); } } diff --git a/godot/platform/linuxbsd/platform_linuxbsd_builders.py b/godot/platform/linuxbsd/platform_linuxbsd_builders.py index 46fa1947..1298a416 100644 --- a/godot/platform/linuxbsd/platform_linuxbsd_builders.py +++ b/godot/platform/linuxbsd/platform_linuxbsd_builders.py @@ -5,6 +5,6 @@ def make_debug_linuxbsd(target, source, env): dst = str(target[0]) - os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst)) - os.system("strip --strip-debug --strip-unneeded {0}".format(dst)) - os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst)) + os.system('objcopy --only-keep-debug "{0}" "{0}.debugsymbols"'.format(dst)) + os.system('strip --strip-debug --strip-unneeded "{0}"'.format(dst)) + os.system('objcopy --add-gnu-debuglink="{0}.debugsymbols" "{0}"'.format(dst)) diff --git a/godot/platform/linuxbsd/wayland/wayland_thread.cpp b/godot/platform/linuxbsd/wayland/wayland_thread.cpp index f1aac4f0..8e3dc755 100644 --- a/godot/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/godot/platform/linuxbsd/wayland/wayland_thread.cpp @@ -32,8 +32,12 @@ #ifdef WAYLAND_ENABLED -// FIXME: Does this cause issues with *BSDs? +#ifdef __FreeBSD__ +#include +#else +// Assume Linux. #include +#endif // For the actual polling thread. #include diff --git a/godot/platform_methods.py b/godot/platform_methods.py index 201df3c0..c8646a40 100644 --- a/godot/platform_methods.py +++ b/godot/platform_methods.py @@ -16,7 +16,7 @@ } # CPU architecture options. -architectures = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"] +architectures = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32", "loongarch64"] architecture_aliases = { "x86": "x86_32", "x64": "x86_64", @@ -31,6 +31,7 @@ "ppcle": "ppc32", "ppc": "ppc32", "ppc64le": "ppc64", + "loong64": "loongarch64", } diff --git a/godot/scene/gui/rich_text_label.cpp b/godot/scene/gui/rich_text_label.cpp index 155824db..ea0b8cd8 100644 --- a/godot/scene/gui/rich_text_label.cpp +++ b/godot/scene/gui/rich_text_label.cpp @@ -364,7 +364,8 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Reflines[p_line]; MutexLock lock(l.text_buf->get_mutex()); - l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size) + l.prefix_width; + l.indent = _find_margin(l.from, p_base_font, p_base_font_size) + l.prefix_width; + l.offset.x = l.indent; l.text_buf->set_width(p_width - l.offset.x); PackedFloat32Array tab_stops = _find_tab_stops(l.from); @@ -501,7 +502,8 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref } // Add indent. - l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size) + l.prefix_width; + l.indent = _find_margin(l.from, p_base_font, p_base_font_size) + l.prefix_width; + l.offset.x = l.indent; l.text_buf->set_width(p_width - l.offset.x); l.text_buf->set_alignment(_find_alignment(l.from)); l.text_buf->set_direction(_find_direction(l.from)); @@ -625,8 +627,8 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref t_char_count += cell_ch; remaining_characters -= cell_ch; - table->columns[column].min_width = MAX(table->columns[column].min_width, ceil(frame->lines[i].text_buf->get_size().x)); - table->columns[column].max_width = MAX(table->columns[column].max_width, ceil(frame->lines[i].text_buf->get_non_wrapped_size().x)); + table->columns[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].indent + ceil(frame->lines[i].text_buf->get_size().x)); + table->columns[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].indent + ceil(frame->lines[i].text_buf->get_non_wrapped_size().x)); } idx++; } @@ -977,6 +979,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o if (frame->lines.size() != 0 && row < row_count) { Vector2 coff = frame->lines[0].offset; + coff.x -= frame->lines[0].indent; if (rtl) { coff.x = rect.size.width - table->columns[col].width - coff.x; } @@ -2548,6 +2551,10 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref &p_base_font, int float margin = 0.0; while (item) { + if (item->type == ITEM_FRAME) { + break; + } + if (item->type == ITEM_INDENT) { Ref font = p_base_font; int font_size = p_base_font_size; @@ -4295,7 +4302,6 @@ void RichTextLabel::append_text(const String &p_bbcode) { parsing_bbcode.store(true); int pos = 0; - int indent_level = 0; bool in_bold = false; bool in_italics = false; @@ -4377,7 +4383,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { in_italics = false; } if ((tag_stack.front()->get() == "indent") || (tag_stack.front()->get() == "ol") || (tag_stack.front()->get() == "ul")) { - indent_level--; + current_frame->indent_level--; } if (!tag_ok) { @@ -4650,44 +4656,44 @@ void RichTextLabel::append_text(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "ul") { - indent_level++; - push_list(indent_level, LIST_DOTS, false); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_DOTS, false); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag.begins_with("ul bullet=")) { String bullet = _get_tag_value(tag); - indent_level++; - push_list(indent_level, LIST_DOTS, false, bullet); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_DOTS, false, bullet); pos = brk_end + 1; tag_stack.push_front("ul"); } else if ((tag == "ol") || (tag == "ol type=1")) { - indent_level++; - push_list(indent_level, LIST_NUMBERS, false); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_NUMBERS, false); pos = brk_end + 1; tag_stack.push_front("ol"); } else if (tag == "ol type=a") { - indent_level++; - push_list(indent_level, LIST_LETTERS, false); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_LETTERS, false); pos = brk_end + 1; tag_stack.push_front("ol"); } else if (tag == "ol type=A") { - indent_level++; - push_list(indent_level, LIST_LETTERS, true); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_LETTERS, true); pos = brk_end + 1; tag_stack.push_front("ol"); } else if (tag == "ol type=i") { - indent_level++; - push_list(indent_level, LIST_ROMAN, false); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_ROMAN, false); pos = brk_end + 1; tag_stack.push_front("ol"); } else if (tag == "ol type=I") { - indent_level++; - push_list(indent_level, LIST_ROMAN, true); + current_frame->indent_level++; + push_list(current_frame->indent_level, LIST_ROMAN, true); pos = brk_end + 1; tag_stack.push_front("ol"); } else if (tag == "indent") { - indent_level++; - push_indent(indent_level); + current_frame->indent_level++; + push_indent(current_frame->indent_level); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag.begins_with("lang=")) { diff --git a/godot/scene/gui/rich_text_label.h b/godot/scene/gui/rich_text_label.h index 00b3280a..d9aac546 100644 --- a/godot/scene/gui/rich_text_label.h +++ b/godot/scene/gui/rich_text_label.h @@ -153,6 +153,7 @@ class RichTextLabel : public Control { Color dc_ol_color; Vector2 offset; + float indent = 0.0; int char_offset = 0; int char_count = 0; @@ -205,6 +206,7 @@ class RichTextLabel : public Control { Size2 min_size_over = Size2(-1, -1); Size2 max_size_over = Size2(-1, -1); Rect2 padding; + int indent_level = 0; ItemFrame() { type = ITEM_FRAME; diff --git a/godot/scene/resources/3d/primitive_meshes.cpp b/godot/scene/resources/3d/primitive_meshes.cpp index 4d04ae77..29588879 100644 --- a/godot/scene/resources/3d/primitive_meshes.cpp +++ b/godot/scene/resources/3d/primitive_meshes.cpp @@ -443,15 +443,25 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa v = j; v /= (rings + 1); - w = sin(0.5 * Math_PI * v); - y = radius * cos(0.5 * Math_PI * v); + if (j == (rings + 1)) { + w = 1.0; + y = 0.0; + } else { + w = sin(0.5 * Math_PI * v); + y = cos(0.5 * Math_PI * v) * radius; + } for (i = 0; i <= radial_segments; i++) { u = i; u /= radial_segments; - x = -sin(u * Math_TAU); - z = cos(u * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); + } Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, 0.5 * height - radius, 0.0)); @@ -492,8 +502,13 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa u = i; u /= radial_segments; - x = -sin(u * Math_TAU); - z = cos(u * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); + } Vector3 p = Vector3(x * radius, y, -z * radius); points.push_back(p); @@ -527,24 +542,33 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa v = j; v /= (rings + 1); - v += 1.0; - w = sin(0.5 * Math_PI * v); - y = radius * cos(0.5 * Math_PI * v); + if (j == (rings + 1)) { + w = 0.0; + y = -radius; + } else { + w = cos(0.5 * Math_PI * v); + y = -sin(0.5 * Math_PI * v) * radius; + } for (i = 0; i <= radial_segments; i++) { u = i; u /= radial_segments; - x = -sin(u * Math_TAU); - z = cos(u * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); + } Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0)); normals.push_back(p.normalized()); ADD_TANGENT(-z, 0.0, -x, 1.0) - uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird))); + uvs.push_back(Vector2(u, twothirds + v * onethird)); if (p_add_uv2) { - uv2s.push_back(Vector2(u * radial_h, radial_v + height_v + ((v - 1.0) * radial_v))); + uv2s.push_back(Vector2(u * radial_h, radial_v + height_v + v * radial_v)); } point++; @@ -1074,8 +1098,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto u = i; u /= radial_segments; - x = sin(u * Math_TAU); - z = cos(u * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); + } Vector3 p = Vector3(x * radius, y, z * radius); points.push_back(p); @@ -1126,8 +1155,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto float r = i; r /= radial_segments; - x = sin(r * Math_TAU); - z = cos(r * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); + } u = ((x + 1.0) * 0.25); v = 0.5 + ((z + 1.0) * 0.25); @@ -1168,8 +1202,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto float r = i; r /= radial_segments; - x = sin(r * Math_TAU); - z = cos(r * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); + } u = 0.5 + ((x + 1.0) * 0.25); v = 1.0 - ((z + 1.0) * 0.25); @@ -1934,15 +1973,25 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int float w; v /= (rings + 1); - w = sin(Math_PI * v); - y = scale * cos(Math_PI * v); + if (j == (rings + 1)) { + w = 0.0; + y = -scale; + } else { + w = sin(Math_PI * v); + y = scale * cos(Math_PI * v); + } for (i = 0; i <= radial_segments; i++) { float u = i; u /= radial_segments; - x = sin(u * Math_TAU); - z = cos(u * Math_TAU); + if (i == radial_segments) { + x = 0.0; + z = 1.0; + } else { + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); + } if (is_hemisphere && y < 0.0) { points.push_back(Vector3(x * radius * w, 0.0, z * radius * w)); @@ -2144,13 +2193,13 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const { float inci = float(i) / rings; float angi = inci * Math_TAU; - Vector2 normali = Vector2(-Math::sin(angi), -Math::cos(angi)); + Vector2 normali = (i == rings) ? Vector2(0.0, -1.0) : Vector2(-Math::sin(angi), -Math::cos(angi)); for (int j = 0; j <= ring_segments; j++) { float incj = float(j) / ring_segments; float angj = incj * Math_TAU; - Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj)); + Vector2 normalj = (j == ring_segments) ? Vector2(-1.0, 0.0) : Vector2(-Math::cos(angj), Math::sin(angj)); Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0); float offset_h = 0.5 * (1.0 - normalj.x) * delta_h; @@ -2159,7 +2208,7 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const { points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x)); normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x)); - ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0); + ADD_TANGENT(normali.y, 0.0, -normali.x, 1.0); uvs.push_back(Vector2(inci, incj)); if (_add_uv2) { uv2s.push_back(Vector2(offset_h + inci * adj_h, incj * height_v)); @@ -2434,8 +2483,12 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { if (curve.is_valid() && curve->get_point_count() > 0) { r *= curve->sample_baked(v); } - float x = sin(u * Math_TAU); - float z = cos(u * Math_TAU); + float x = 0.0; + float z = 1.0; + if (i < radial_steps) { + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); + } Vector3 p = Vector3(x * r, y, z * r); points.push_back(p); @@ -2503,8 +2556,12 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { float r = i; r /= radial_steps; - float x = sin(r * Math_TAU); - float z = cos(r * Math_TAU); + float x = 0.0; + float z = 1.0; + if (i < radial_steps) { + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); + } float u = ((x + 1.0) * 0.25); float v = 0.5 + ((z + 1.0) * 0.25); @@ -2568,8 +2625,12 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { float r = i; r /= radial_steps; - float x = sin(r * Math_TAU); - float z = cos(r * Math_TAU); + float x = 0.0; + float z = 1.0; + if (i < radial_steps) { + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); + } float u = 0.5 + ((x + 1.0) * 0.25); float v = 1.0 - ((z + 1.0) * 0.25); diff --git a/godot/scene/resources/SCsub b/godot/scene/resources/SCsub index 46f6251b..ae2a9b8c 100644 --- a/godot/scene/resources/SCsub +++ b/godot/scene/resources/SCsub @@ -7,7 +7,13 @@ Import("env") thirdparty_obj = [] -thirdparty_sources = "#thirdparty/misc/mikktspace.c" +thirdparty_dir = "#thirdparty/misc/" +thirdparty_sources = [ + "mikktspace.c", + "qoa.c" +] + +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_thirdparty = env.Clone() env_thirdparty.disable_warnings() diff --git a/godot/scene/resources/audio_stream_wav.cpp b/godot/scene/resources/audio_stream_wav.cpp index cea9af72..15e3f0f8 100644 --- a/godot/scene/resources/audio_stream_wav.cpp +++ b/godot/scene/resources/audio_stream_wav.cpp @@ -1142,13 +1142,13 @@ Ref AudioStreamWAV::load_from_buffer(const Vector &p_fi is16 = false; } - Vector pcm_data; + Vector dst_data; AudioStreamWAV::Format dst_format; if (compression == 1) { dst_format = AudioStreamWAV::FORMAT_IMA_ADPCM; if (format_channels == 1) { - _compress_ima_adpcm(data, pcm_data); + _compress_ima_adpcm(data, dst_data); } else { //byte interleave Vector left; @@ -1170,9 +1170,9 @@ Ref AudioStreamWAV::load_from_buffer(const Vector &p_fi _compress_ima_adpcm(right, bright); int dl = bleft.size(); - pcm_data.resize(dl * 2); + dst_data.resize(dl * 2); - uint8_t *w = pcm_data.ptrw(); + uint8_t *w = dst_data.ptrw(); const uint8_t *rl = bleft.ptr(); const uint8_t *rr = bright.ptr(); @@ -1182,16 +1182,24 @@ Ref AudioStreamWAV::load_from_buffer(const Vector &p_fi } } + } else if (compression == 2) { + dst_format = AudioStreamWAV::FORMAT_QOA; + + qoa_desc desc = {}; + desc.samplerate = rate; + desc.samples = frames; + desc.channels = format_channels; + + _compress_qoa(data, dst_data, &desc); } else { dst_format = is16 ? AudioStreamWAV::FORMAT_16_BITS : AudioStreamWAV::FORMAT_8_BITS; - bool enforce16 = is16 || compression == 2; - pcm_data.resize(data.size() * (enforce16 ? 2 : 1)); + dst_data.resize(data.size() * (is16 ? 2 : 1)); { - uint8_t *w = pcm_data.ptrw(); + uint8_t *w = dst_data.ptrw(); int ds = data.size(); for (int i = 0; i < ds; i++) { - if (enforce16) { + if (is16) { int16_t v = CLAMP(data[i] * 32768, -32768, 32767); encode_uint16(v, &w[i * 2]); } else { @@ -1202,26 +1210,6 @@ Ref AudioStreamWAV::load_from_buffer(const Vector &p_fi } } - Vector dst_data; - if (compression == 2) { - dst_format = AudioStreamWAV::FORMAT_QOA; - qoa_desc desc = {}; - uint32_t qoa_len = 0; - - desc.samplerate = rate; - desc.samples = frames; - desc.channels = format_channels; - - void *encoded = qoa_encode((short *)pcm_data.ptr(), &desc, &qoa_len); - if (encoded) { - dst_data.resize(qoa_len); - memcpy(dst_data.ptrw(), encoded, qoa_len); - QOA_FREE(encoded); - } - } else { - dst_data = pcm_data; - } - Ref sample; sample.instantiate(); sample->set_data(dst_data); diff --git a/godot/scene/resources/audio_stream_wav.h b/godot/scene/resources/audio_stream_wav.h index 269ab1e0..e36d33cf 100644 --- a/godot/scene/resources/audio_stream_wav.h +++ b/godot/scene/resources/audio_stream_wav.h @@ -31,9 +31,6 @@ #ifndef AUDIO_STREAM_WAV_H #define AUDIO_STREAM_WAV_H -#define QOA_IMPLEMENTATION -#define QOA_NO_STDIO - #include "servers/audio/audio_stream.h" #include "thirdparty/misc/qoa.h" @@ -273,6 +270,34 @@ class AudioStreamWAV : public AudioStream { } } + static void _compress_qoa(const Vector &p_data, Vector &dst_data, qoa_desc *p_desc) { + uint32_t frames_len = (p_desc->samples + QOA_FRAME_LEN - 1) / QOA_FRAME_LEN * (QOA_LMS_LEN * 4 * p_desc->channels + 8); + uint32_t slices_len = (p_desc->samples + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN * 8 * p_desc->channels; + dst_data.resize(8 + frames_len + slices_len); + + for (uint32_t c = 0; c < p_desc->channels; c++) { + memset(p_desc->lms[c].history, 0, sizeof(p_desc->lms[c].history)); + memset(p_desc->lms[c].weights, 0, sizeof(p_desc->lms[c].weights)); + p_desc->lms[c].weights[2] = -(1 << 13); + p_desc->lms[c].weights[3] = (1 << 14); + } + + LocalVector data16; + data16.resize(QOA_FRAME_LEN * p_desc->channels); + + uint8_t *dst_ptr = dst_data.ptrw(); + dst_ptr += qoa_encode_header(p_desc, dst_data.ptrw()); + + uint32_t frame_len = QOA_FRAME_LEN; + for (uint32_t s = 0; s < p_desc->samples; s += frame_len) { + frame_len = MIN(frame_len, p_desc->samples - s); + for (uint32_t i = 0; i < frame_len * p_desc->channels; i++) { + data16[i] = CLAMP(p_data[s * p_desc->channels + i] * 32767.0, -32768, 32767); + } + dst_ptr += qoa_encode_frame(data16.ptr(), p_desc, frame_len, dst_ptr); + } + } + AudioStreamWAV(); ~AudioStreamWAV(); }; diff --git a/godot/servers/audio/effects/audio_effect_record.cpp b/godot/servers/audio/effects/audio_effect_record.cpp index f82a6fa3..b6bc5d00 100644 --- a/godot/servers/audio/effects/audio_effect_record.cpp +++ b/godot/servers/audio/effects/audio_effect_record.cpp @@ -250,6 +250,12 @@ Ref AudioEffectRecord::get_recording() const { w[i * 2 + 0] = rl[i]; w[i * 2 + 1] = rr[i]; } + } else if (dst_format == AudioStreamWAV::FORMAT_QOA) { + qoa_desc desc = {}; + desc.samples = current_instance->recording_data.size() / 2; + desc.samplerate = AudioServer::get_singleton()->get_mix_rate(); + desc.channels = 2; + AudioStreamWAV::_compress_qoa(current_instance->recording_data, dst_data, &desc); } else { ERR_PRINT("Format not implemented."); } diff --git a/godot/servers/register_server_types.cpp b/godot/servers/register_server_types.cpp index 417f1e67..453c7b24 100644 --- a/godot/servers/register_server_types.cpp +++ b/godot/servers/register_server_types.cpp @@ -71,6 +71,7 @@ #include "rendering/renderer_rd/uniform_set_cache_rd.h" #include "rendering/rendering_device.h" #include "rendering/rendering_device_binds.h" +#include "rendering/shader_include_db.h" #include "rendering/storage/render_data.h" #include "rendering/storage/render_scene_buffers.h" #include "rendering/storage/render_scene_data.h" @@ -212,6 +213,7 @@ void register_server_types() { } GDREGISTER_ABSTRACT_CLASS(RenderingDevice); + GDREGISTER_CLASS(ShaderIncludeDB); GDREGISTER_CLASS(RDTextureFormat); GDREGISTER_CLASS(RDTextureView); GDREGISTER_CLASS(RDAttachmentFormat); diff --git a/godot/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/godot/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index e93b7f03..e2d67965 100644 --- a/godot/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/godot/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1005,13 +1005,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color { base_specialization.use_directional_soft_shadows = p_render_data->directional_light_count > 0 ? p_render_data->directional_light_soft_shadows : false; base_specialization.directional_lights = p_render_data->directional_light_count; + base_specialization.directional_light_blend_splits = light_storage->get_directional_light_blend_splits(p_render_data->directional_light_count); if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) { base_specialization.disable_fog = true; - } - - if (p_render_data->environment.is_valid() && environment_get_fog_mode(p_render_data->environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH) { - base_specialization.use_depth_fog = true; + base_specialization.use_fog_aerial_perspective = false; + base_specialization.use_fog_sun_scatter = false; + base_specialization.use_fog_height_density = false; + base_specialization.use_depth_fog = false; + } else { + base_specialization.disable_fog = false; + base_specialization.use_fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment) > 0.0; + base_specialization.use_fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment) > 0.001; + base_specialization.use_fog_height_density = abs(environment_get_fog_height_density(p_render_data->environment)) >= 0.0001; + base_specialization.use_depth_fog = p_render_data->environment.is_valid() && environment_get_fog_mode(p_render_data->environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH; } base_specialization.scene_use_ambient_cubemap = use_ambient_cubemap; diff --git a/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 4525b50b..6274dd76 100644 --- a/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -238,6 +238,7 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli "SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0, "SPEC PACKED #1:", p_pipeline_key.shader_specialization.packed_1, "SPEC PACKED #2:", p_pipeline_key.shader_specialization.packed_2, + "SPEC PACKED #3:", p_pipeline_key.shader_specialization.packed_3, "RENDER PASS:", p_pipeline_key.render_pass, "WIREFRAME:", p_pipeline_key.wireframe); #endif @@ -328,7 +329,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli specialization_constants.push_back(sc); sc.constant_id = 2; - sc.float_value = p_pipeline_key.shader_specialization.packed_2; + sc.int_value = p_pipeline_key.shader_specialization.packed_2; + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + specialization_constants.push_back(sc); + + sc.constant_id = 3; + sc.float_value = p_pipeline_key.shader_specialization.packed_3; sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; specialization_constants.push_back(sc); diff --git a/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index e2549d1f..a40c5446 100644 --- a/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/godot/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -67,6 +67,9 @@ class SceneShaderForwardMobile { uint32_t projector_use_mipmaps : 1; uint32_t disable_fog : 1; uint32_t use_depth_fog : 1; + uint32_t use_fog_aerial_perspective : 1; + uint32_t use_fog_sun_scatter : 1; + uint32_t use_fog_height_density : 1; uint32_t use_lightmap_bicubic_filter : 1; uint32_t multimesh : 1; uint32_t multimesh_format_2d : 1; @@ -75,7 +78,7 @@ class SceneShaderForwardMobile { uint32_t scene_use_ambient_cubemap : 1; uint32_t scene_use_reflection_cubemap : 1; uint32_t scene_roughness_limiter_enabled : 1; - uint32_t padding : 5; + uint32_t padding_0 : 2; uint32_t soft_shadow_samples : 6; uint32_t penumbra_shadow_samples : 6; }; @@ -97,9 +100,18 @@ class SceneShaderForwardMobile { uint32_t packed_1; }; + union { + struct { + uint32_t directional_light_blend_splits : 8; + uint32_t padding_1 : 24; + }; + + uint32_t packed_2; + }; + union { float luminance_multiplier; - float packed_2; + float packed_3; }; }; @@ -111,6 +123,10 @@ class SceneShaderForwardMobile { uint32_t packed_0; }; + + uint32_t padding_1; + uint32_t padding_2; + uint32_t padding_3; }; struct ShaderData : public RendererRD::MaterialStorage::ShaderData { diff --git a/godot/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/godot/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 7ef42aa7..23685473 100644 --- a/godot/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/godot/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -35,9 +35,13 @@ #include "core/os/os.h" #include "renderer_compositor_rd.h" #include "servers/rendering/renderer_rd/environment/fog.h" +#include "servers/rendering/renderer_rd/shaders/decal_data_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/light_data_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/scene_data_inc.glsl.gen.h" #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" #include "servers/rendering/rendering_server_default.h" +#include "servers/rendering/shader_include_db.h" #include "servers/rendering/storage/camera_attributes_storage.h" void get_vogel_disk(float *r_kernel, int p_sample_count) { @@ -1452,6 +1456,13 @@ void RendererSceneRenderRD::init() { /* Forward ID */ forward_id_storage = create_forward_id_storage(); + /* Register the include files we make available by default to our users */ + { + ShaderIncludeDB::register_built_in_include_file("godot/decal_data_inc.glsl", decal_data_inc_shader_glsl); + ShaderIncludeDB::register_built_in_include_file("godot/light_data_inc.glsl", light_data_inc_shader_glsl); + ShaderIncludeDB::register_built_in_include_file("godot/scene_data_inc.glsl", scene_data_inc_shader_glsl); + } + /* SKY SHADER */ sky.init(); diff --git a/godot/servers/rendering/renderer_rd/shader_rd.cpp b/godot/servers/rendering/renderer_rd/shader_rd.cpp index 6234cdde..fb89c11a 100644 --- a/godot/servers/rendering/renderer_rd/shader_rd.cpp +++ b/godot/servers/rendering/renderer_rd/shader_rd.cpp @@ -37,6 +37,7 @@ #include "core/version.h" #include "renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" +#include "servers/rendering/shader_include_db.h" #include "thirdparty/misc/smolv.h" #define ENABLE_SHADER_CACHE 1 @@ -46,7 +47,8 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { String text; - for (int i = 0; i < lines.size(); i++) { + int line_count = lines.size(); + for (int i = 0; i < line_count; i++) { const String &l = lines[i]; bool push_chunk = false; @@ -78,6 +80,35 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { chunk.type = StageTemplate::Chunk::TYPE_CODE; push_chunk = true; chunk.code = l.replace_first("#CODE", String()).replace(":", "").strip_edges().to_upper(); + } else if (l.begins_with("#include ")) { + String include_file = l.replace("#include ", "").strip_edges(); + if (include_file[0] == '"') { + int end_pos = include_file.find_char('"', 1); + if (end_pos >= 0) { + include_file = include_file.substr(1, end_pos - 1); + + String include_code = ShaderIncludeDB::get_built_in_include_file(include_file); + if (!include_code.is_empty()) { + // Add these lines into our parse list so we parse them as well. + Vector include_lines = include_code.split("\n"); + + for (int j = include_lines.size() - 1; j >= 0; j--) { + lines.insert(i + 1, include_lines[j]); + } + + line_count = lines.size(); + } else { + // Add it in as is. + text += l + "\n"; + } + } else { + // Add it in as is. + text += l + "\n"; + } + } else { + // Add it in as is. + text += l + "\n"; + } } else { text += l + "\n"; } diff --git a/godot/servers/rendering/renderer_rd/shaders/SCsub b/godot/servers/rendering/renderer_rd/shaders/SCsub index e102b839..f1b67103 100644 --- a/godot/servers/rendering/renderer_rd/shaders/SCsub +++ b/godot/servers/rendering/renderer_rd/shaders/SCsub @@ -4,16 +4,20 @@ from misc.utility.scons_hints import * Import("env") if "RD_GLSL" in env["BUILDERS"]: - # find all include files + # find just the include files gl_include_files = [str(f) for f in Glob("*_inc.glsl")] - # find all shader code(all glsl files excluding our include files) + # find all shader code (all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] # make sure we recompile shaders if include files change env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"]) - # compile shaders + # compile include files + for glsl_file in gl_include_files: + env.GLSL_HEADER(glsl_file) + + # compile RD shader for glsl_file in glsl_files: env.RD_GLSL(glsl_file) diff --git a/godot/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/godot/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index da582ec1..f5a806fb 100644 --- a/godot/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/godot/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -37,7 +37,7 @@ struct InstanceData { #endif vec2 color_texture_pixel_size; - uint lights[4]; + uvec4 lights; }; //1 means enabled, 2+ means trails in use diff --git a/godot/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/godot/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 1e1b6d89..52b3d5d1 100644 --- a/godot/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/godot/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -2369,11 +2369,7 @@ void fragment_shader(in SceneData scene_data) { continue; // Statically baked light and object uses lightmap, skip } - float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count); - - shadow = blur_shadow(shadow); - - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -2441,11 +2437,7 @@ void fragment_shader(in SceneData scene_data) { continue; // Statically baked light and object uses lightmap, skip } - float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count); - - shadow = blur_shadow(shadow); - - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 0cb34557..144b994a 100644 --- a/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -768,7 +768,7 @@ layout(location = 0) out mediump vec4 frag_color; vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data_block.data.fog_light_color; - if (scene_data_block.data.fog_aerial_perspective > 0.0) { + if (sc_use_fog_aerial_perspective()) { vec3 sky_fog_color = vec3(0.0); vec3 cube_view = scene_data_block.data.radiance_inverse_xform * vertex; // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred @@ -784,7 +784,7 @@ vec4 fog_process(vec3 vertex) { fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective); } - if (scene_data_block.data.fog_sun_scatter > 0.001) { + if (sc_use_fog_sun_scatter()) { vec4 sun_scatter = vec4(0.0); float sun_total = 0.0; vec3 view = normalize(vertex); @@ -806,7 +806,7 @@ vec4 fog_process(vec3 vertex) { fog_amount = 1 - exp(min(0.0, -length(vertex) * scene_data_block.data.fog_density)); } - if (abs(scene_data_block.data.fog_height_density) >= 0.0001) { + if (sc_use_fog_height_density()) { float y = (scene_data_block.data.inv_view_matrix * vec4(vertex, 1.0)).y; float y_dist = y - scene_data_block.data.fog_height; @@ -1497,9 +1497,11 @@ void main() { pssm_coord /= pssm_coord.w; - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor + (1.0 - blur_factor) * float(directional_lights.data[i].blend_splits)), pssm_coord, scene_data.taa_frame_count); + bool blend_split = sc_directional_light_blend_split(i); + float blend_split_weight = blend_split ? 1.0f : 0.0f; + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor + (1.0 - blur_factor) * blend_split_weight), pssm_coord, scene_data.taa_frame_count); - if (directional_lights.data[i].blend_splits) { + if (blend_split) { float pssm_blend; float blur_factor2; @@ -1531,7 +1533,7 @@ void main() { pssm_coord /= pssm_coord.w; - float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor2 + (1.0 - blur_factor2) * float(directional_lights.data[i].blend_splits)), pssm_coord, scene_data.taa_frame_count); + float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * (blur_factor2 + (1.0 - blur_factor2) * blend_split_weight), pssm_coord, scene_data.taa_frame_count); shadow = mix(shadow, shadow2, pssm_blend); } @@ -1622,13 +1624,7 @@ void main() { uvec2 omni_indices = instances.data[draw_call.instance_index].omni_lights; for (uint i = 0; i < sc_omni_lights(); i++) { uint light_index = (i > 3) ? ((omni_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_indices.x >> (i * 8)) & 0xFF); - - float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count); - - shadow = blur_shadow(shadow); - - // Fragment lighting - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1656,12 +1652,7 @@ void main() { uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights; for (uint i = 0; i < sc_spot_lights(); i++) { uint light_index = (i > 3) ? ((spot_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_indices.x >> (i * 8)) & 0xFF); - - float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count); - - shadow = blur_shadow(shadow); - - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 2cc86482..5e4719c4 100644 --- a/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/godot/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -23,8 +23,12 @@ layout(push_constant, std430) uniform DrawCall { #ifdef UBERSHADER uint sc_packed_0; uint sc_packed_1; - float sc_packed_2; + uint sc_packed_2; + float sc_packed_3; uint uc_packed_0; + uint uc_padding_1; + uint uc_padding_2; + uint uc_padding_3; #endif } draw_call; @@ -46,10 +50,14 @@ uint sc_packed_1() { return draw_call.sc_packed_1; } -float sc_packed_2() { +uint sc_packed_2() { return draw_call.sc_packed_2; } +float sc_packed_3() { + return draw_call.sc_packed_3; +} + uint uc_cull_mode() { return (draw_call.uc_packed_0 >> 0) & 3U; } @@ -59,7 +67,8 @@ uint uc_cull_mode() { // Pull the constants from the pipeline's specialization constants. layout(constant_id = 0) const uint pso_sc_packed_0 = 0; layout(constant_id = 1) const uint pso_sc_packed_1 = 0; -layout(constant_id = 2) const float pso_sc_packed_2 = 2.0; +layout(constant_id = 2) const uint pso_sc_packed_2 = 0; +layout(constant_id = 3) const float pso_sc_packed_3 = 2.0; uint sc_packed_0() { return pso_sc_packed_0; @@ -69,10 +78,14 @@ uint sc_packed_1() { return pso_sc_packed_1; } -float sc_packed_2() { +uint sc_packed_2() { return pso_sc_packed_2; } +float sc_packed_3() { + return pso_sc_packed_3; +} + #endif bool sc_use_light_projector() { @@ -103,38 +116,50 @@ bool sc_use_depth_fog() { return ((sc_packed_0() >> 6) & 1U) != 0; } -bool sc_use_lightmap_bicubic_filter() { +bool sc_use_fog_aerial_perspective() { return ((sc_packed_0() >> 7) & 1U) != 0; } -bool sc_multimesh() { +bool sc_use_fog_sun_scatter() { return ((sc_packed_0() >> 8) & 1U) != 0; } -bool sc_multimesh_format_2d() { +bool sc_use_fog_height_density() { return ((sc_packed_0() >> 9) & 1U) != 0; } -bool sc_multimesh_has_color() { +bool sc_use_lightmap_bicubic_filter() { return ((sc_packed_0() >> 10) & 1U) != 0; } -bool sc_multimesh_has_custom_data() { +bool sc_multimesh() { return ((sc_packed_0() >> 11) & 1U) != 0; } -bool sc_scene_use_ambient_cubemap() { +bool sc_multimesh_format_2d() { return ((sc_packed_0() >> 12) & 1U) != 0; } -bool sc_scene_use_reflection_cubemap() { +bool sc_multimesh_has_color() { return ((sc_packed_0() >> 13) & 1U) != 0; } -bool sc_scene_roughness_limiter_enabled() { +bool sc_multimesh_has_custom_data() { return ((sc_packed_0() >> 14) & 1U) != 0; } +bool sc_scene_use_ambient_cubemap() { + return ((sc_packed_0() >> 15) & 1U) != 0; +} + +bool sc_scene_use_reflection_cubemap() { + return ((sc_packed_0() >> 16) & 1U) != 0; +} + +bool sc_scene_roughness_limiter_enabled() { + return ((sc_packed_0() >> 17) & 1U) != 0; +} + uint sc_soft_shadow_samples() { return (sc_packed_0() >> 20) & 63U; } @@ -171,8 +196,12 @@ uint sc_decals() { return (sc_packed_1() >> 28) & 15U; } +bool sc_directional_light_blend_split(uint i) { + return ((sc_packed_2() >> i) & 1U) != 0; +} + float sc_luminance_multiplier() { - return sc_packed_2(); + return sc_packed_3(); } /* Set 0: Base Pass (never changes) */ diff --git a/godot/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/godot/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 1e8fc7ea..f58304aa 100644 --- a/godot/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/godot/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -59,16 +59,14 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di vec3 B, vec3 T, float anisotropy, #endif inout vec3 diffuse_light, inout vec3 specular_light) { - vec4 orms_unpacked = unpackUnorm4x8(orms); - float roughness = orms_unpacked.y; float metallic = orms_unpacked.z; #if defined(LIGHT_CODE_USED) - // light is written by the light shader - + // Light is written by the user shader. mat4 inv_view_matrix = scene_data_block.data.inv_view_matrix; + mat4 read_view_matrix = scene_data_block.data.view_matrix; #ifdef USING_MOBILE_RENDERER mat4 read_model_matrix = instances.data[draw_call.instance_index].transform; @@ -76,183 +74,159 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di mat4 read_model_matrix = instances.data[instance_index_interp].transform; #endif - mat4 read_view_matrix = scene_data_block.data.view_matrix; - #undef projection_matrix #define projection_matrix scene_data_block.data.projection_matrix #undef inv_projection_matrix #define inv_projection_matrix scene_data_block.data.inv_projection_matrix vec2 read_viewport_size = scene_data_block.data.viewport_size; - vec3 normal = N; vec3 light = L; vec3 view = V; #CODE : LIGHT +#else // !LIGHT_CODE_USED + float NdotL = min(A + dot(N, L), 1.0); + float cNdotV = max(dot(N, V), 1e-4); +#ifdef LIGHT_TRANSMITTANCE_USED + { +#ifdef SSS_MODE_SKIN + float scale = 8.25 / transmittance_depth; + float d = scale * abs(transmittance_z); + float dd = -d * d; + vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + + diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); #else - float NdotL = min(A + dot(N, L), 1.0); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 1e-4); - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - vec3 H = normalize(V + L); + float scale = 8.25 / transmittance_depth; + float d = scale * abs(transmittance_z); + float dd = -d * d; + diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); #endif + } +#endif //LIGHT_TRANSMITTANCE_USED -#if defined(SPECULAR_SCHLICK_GGX) - float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); +#if defined(LIGHT_RIM_USED) + // Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior. + float rim_light = pow(max(1e-4, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color; #endif + // We skip checking on attenuation on directional lights to avoid a branch that is not as beneficial for directional lights as the other ones. + const float EPSILON = 1e-3f; + if (is_directional || attenuation > EPSILON) { + float cNdotL = max(NdotL, 0.0); +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) + vec3 H = normalize(V + L); +#endif #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif +#if defined(LIGHT_CLEARCOAT_USED) + // Clearcoat ignores normal_map, use vertex normal instead + float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0); + float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0); + float ccNdotV = max(dot(vertex_normal, V), 1e-4); + +#if !defined(SPECULAR_SCHLICK_GGX) + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness)); + float Gr = 0.25 / (cLdotH * cLdotH); + float Fr = mix(.04, 1.0, cLdotH5); + float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; + + // TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR) + // but to do so we need to rearrange this entire function +#endif // LIGHT_CLEARCOAT_USED - if (metallic < 1.0) { - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance + if (metallic < 1.0) { + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance #if defined(DIFFUSE_LAMBERT_WRAP) - // Energy conserving lambert wrap shader. - // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/ - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI); + // Energy conserving lambert wrap shader. + // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/ + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI); #elif defined(DIFFUSE_TOON) - diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI); + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI); #elif defined(DIFFUSE_BURLEY) - - { - float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; - float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); - float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); - diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ - } + { + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + } #else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif - diffuse_light += light_color * diffuse_brdf_NL * attenuation; + diffuse_light += light_color * diffuse_brdf_NL * attenuation; #if defined(LIGHT_BACKLIGHT_USED) - diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; -#endif - -#if defined(LIGHT_RIM_USED) - // Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior. - float rim_light = pow(max(1e-4, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color; -#endif - -#ifdef LIGHT_TRANSMITTANCE_USED - - { -#ifdef SSS_MODE_SKIN - float scale = 8.25 / transmittance_depth; - float d = scale * abs(transmittance_z); - float dd = -d * d; - vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + - vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + - vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + - vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + - vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + - vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); - - diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); -#else - - float scale = 8.25 / transmittance_depth; - float d = scale * abs(transmittance_z); - float dd = -d * d; - diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; #endif } -#else - -#endif //LIGHT_TRANSMITTANCE_USED - } - - if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely - - // D + if (roughness > 0.0) { +#if defined(SPECULAR_SCHLICK_GGX) + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); +#endif + // Apply specular light. + // FIXME: roughness == 0 should not disable specular light entirely #if defined(SPECULAR_TOON) - - vec3 R = normalize(-reflect(L, N)); - float RdotV = dot(R, V); - float mid = 1.0 - roughness; - mid *= mid; - float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection #elif defined(SPECULAR_DISABLED) - // none.. + // Do nothing. #elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - float alpha_ggx = roughness * roughness; + // shlick+ggx as default + float alpha_ggx = roughness * roughness; #if defined(LIGHT_ANISOTROPY_USED) - - float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha_ggx / aspect; - float ay = alpha_ggx * aspect; - float XdotH = dot(T, H); - float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); + float aspect = sqrt(1.0 - anisotropy * 0.9); + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); + float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); #else // LIGHT_ANISOTROPY_USED - float D = D_GGX(cNdotH, alpha_ggx); - float G = V_GGX(cNdotL, cNdotV, alpha_ggx); + float D = D_GGX(cNdotH, alpha_ggx); + float G = V_GGX(cNdotL, cNdotV, alpha_ggx); #endif // LIGHT_ANISOTROPY_USED // F - float cLdotH5 = SchlickFresnel(cLdotH); - // Calculate Fresnel using specular occlusion term from Filament: - // https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion - float f90 = clamp(dot(f0, vec3(50.0 * 0.33)), metallic, 1.0); - vec3 F = f0 + (f90 - f0) * cLdotH5; - - vec3 specular_brdf_NL = cNdotL * D * F * G; - - specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; -#endif - -#if defined(LIGHT_CLEARCOAT_USED) - // Clearcoat ignores normal_map, use vertex normal instead - float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0); - float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0); - float ccNdotV = max(dot(vertex_normal, V), 1e-4); - -#if !defined(SPECULAR_SCHLICK_GGX) - float cLdotH5 = SchlickFresnel(cLdotH); + float cLdotH5 = SchlickFresnel(cLdotH); + // Calculate Fresnel using specular occlusion term from Filament: + // https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion + float f90 = clamp(dot(f0, vec3(50.0 * 0.33)), metallic, 1.0); + vec3 F = f0 + (f90 - f0) * cLdotH5; + vec3 specular_brdf_NL = cNdotL * D * F * G; + specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; #endif - float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness)); - float Gr = 0.25 / (cLdotH * cLdotH); - float Fr = mix(.04, 1.0, cLdotH5); - float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; - // TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR) - // but to do so we need to rearrange this entire function -#endif // LIGHT_CLEARCOAT_USED - } + } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0)); + alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0)); #endif - -#endif //defined(LIGHT_CODE_USED) + } +#endif // LIGHT_CODE_USED } #ifndef SHADOWS_DISABLED @@ -412,9 +386,43 @@ float get_omni_attenuation(float distance, float inv_range, float decay) { return nd * pow(max(distance, 0.0001), -decay); } -float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_frame_count) { +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float taa_frame_count, vec3 albedo, inout float alpha, vec2 screen_uv, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + const float EPSILON = 1e-3f; + + // Omni light attenuation. + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); + + // Compute size. + float size = 0.0; + if (sc_use_light_soft_shadows() && omni_lights.data[idx].size > 0.0) { + float t = omni_lights.data[idx].size / max(0.001, light_length); + size = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } + + float shadow = 1.0; #ifndef SHADOWS_DISABLED - if (omni_lights.data[idx].shadow_opacity > 0.001) { + // Omni light shadow. + if (omni_attenuation > EPSILON && omni_lights.data[idx].shadow_opacity > 0.001) { // there is a shadowmap vec2 texel_size = scene_data_block.data.shadow_atlas_pixel_size; vec4 base_uv_rect = omni_lights.data[idx].atlas_rect; @@ -432,8 +440,6 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal); vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir))); - float shadow; - if (sc_use_light_soft_shadows() && omni_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow @@ -539,49 +545,14 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr depth = 1.0 - depth; shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth, taa_frame_count), omni_lights.data[idx].shadow_opacity); } - - return shadow; } #endif - return 1.0; -} - -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_roughness, vec3 vertex_normal, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = omni_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); - float light_attenuation = omni_attenuation; vec3 color = omni_lights.data[idx].color; - float size_A = 0.0; - - if (sc_use_light_soft_shadows() && omni_lights.data[idx].size > 0.0) { - float t = omni_lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } - #ifdef LIGHT_TRANSMITTANCE_USED float transmittance_z = transmittance_depth; //no transmittance by default - transmittance_color.a *= light_attenuation; + transmittance_color.a *= omni_attenuation; #ifndef SHADOWS_DISABLED if (omni_lights.data[idx].shadow_opacity > 0.001) { // Redo shadowmapping, but shrink the model a bit to avoid artifacts. @@ -673,9 +644,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v } } - light_attenuation *= shadow; - - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, screen_uv, + vec3 light_rel_vec_norm = light_rel_vec / light_length; + light_compute(normal, light_rel_vec_norm, eye_vec, size, color, false, omni_attenuation * shadow, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -698,15 +668,66 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v specular_light); } -float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_frame_count) { -#ifndef SHADOWS_DISABLED - if (spot_lights.data[idx].shadow_opacity > 0.001) { - vec3 light_rel_vec = spot_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - vec3 spot_dir = spot_lights.data[idx].direction; +vec2 normal_to_panorama(vec3 n) { + n = normalize(n); + vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y)); + + if (panorama_coords.x < 0.0) { + panorama_coords.x += M_PI * 2.0; + } + + panorama_coords /= vec2(M_PI * 2.0, M_PI); + return panorama_coords; +} + +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float taa_frame_count, vec3 albedo, inout float alpha, vec2 screen_uv, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif + inout vec3 diffuse_light, + inout vec3 specular_light) { + const float EPSILON = 1e-3f; + + // Spot light attenuation. + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec3 light_rel_vec_norm = light_rel_vec / light_length; + float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); + vec3 spot_dir = spot_lights.data[idx].direction; - vec3 shadow_dir = light_rel_vec / light_length; - vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir))); + // This conversion to a highp float is crucial to prevent light leaking + // due to precision errors in the following calculations (cone angle is mediump). + highp float cone_angle = spot_lights.data[idx].cone_angle; + float scos = max(dot(-light_rel_vec_norm, spot_dir), cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); + + // Compute size. + float size = 0.0; + if (sc_use_light_soft_shadows() && spot_lights.data[idx].size > 0.0) { + float t = spot_lights.data[idx].size / max(0.001, light_length); + size = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } + + float shadow = 1.0; +#ifndef SHADOWS_DISABLED + // Spot light shadow. + if (spot_attenuation > EPSILON && spot_lights.data[idx].shadow_opacity > 0.001) { + vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, light_rel_vec_norm))); //there is a shadowmap vec4 v = vec4(vertex + normal_bias, 1.0); @@ -715,7 +736,6 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); splane /= splane.w; - float shadow; if (sc_use_light_soft_shadows() && spot_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow @@ -772,73 +792,15 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z); shadow = mix(1.0, sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv, taa_frame_count), spot_lights.data[idx].shadow_opacity); } - - return shadow; } - #endif // SHADOWS_DISABLED - return 1.0; -} - -vec2 normal_to_panorama(vec3 n) { - n = normalize(n); - vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y)); - - if (panorama_coords.x < 0.0) { - panorama_coords.x += M_PI * 2.0; - } - - panorama_coords /= vec2(M_PI * 2.0, M_PI); - return panorama_coords; -} - -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_roughness, vec3 vertex_normal, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif - inout vec3 diffuse_light, - inout vec3 specular_light) { - vec3 light_rel_vec = spot_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); - vec3 spot_dir = spot_lights.data[idx].direction; - - // This conversion to a highp float is crucial to prevent light leaking - // due to precision errors in the following calculations (cone angle is mediump). - highp float cone_angle = spot_lights.data[idx].cone_angle; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), cone_angle); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle)); - - spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); - float light_attenuation = spot_attenuation; vec3 color = spot_lights.data[idx].color; float specular_amount = spot_lights.data[idx].specular_amount; - float size_A = 0.0; - - if (sc_use_light_soft_shadows() && spot_lights.data[idx].size > 0.0) { - float t = spot_lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } - #ifdef LIGHT_TRANSMITTANCE_USED float transmittance_z = transmittance_depth; - transmittance_color.a *= light_attenuation; + transmittance_color.a *= spot_attenuation; #ifndef SHADOWS_DISABLED if (spot_lights.data[idx].shadow_opacity > 0.001) { vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal) * spot_lights.data[idx].transmittance_bias, 1.0)); @@ -882,9 +844,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v color *= proj.rgb * proj.a; } } - light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, screen_uv, + light_compute(normal, light_rel_vec_norm, eye_vec, size, color, false, spot_attenuation * shadow, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, screen_uv, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/godot/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/godot/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 9de37050..1d309a80 100644 --- a/godot/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/godot/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -2328,7 +2328,7 @@ bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, old_quadrant = (old_key >> QUADRANT_SHIFT) & 0x3; old_shadow = old_key & SHADOW_INDEX_MASK; - should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); + should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (tick - shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick > shadow_atlas_realloc_tolerance_msec); should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version; if (!should_realloc) { diff --git a/godot/servers/rendering/renderer_rd/storage_rd/light_storage.h b/godot/servers/rendering/renderer_rd/storage_rd/light_storage.h index 1a92c547..b5f15231 100644 --- a/godot/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/godot/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -799,6 +799,16 @@ class LightStorage : public RendererLightStorage { RID get_spot_light_buffer() { return spot_light_buffer; } RID get_directional_light_buffer() { return directional_light_buffer; } uint32_t get_max_directional_lights() { return max_directional_lights; } + uint32_t get_directional_light_blend_splits(uint32_t p_directional_light_count) const { + uint32_t blend_splits = 0; + for (uint32_t i = 0; i < p_directional_light_count; i++) { + if (directional_lights[i].blend_splits) { + blend_splits |= 1U << i; + } + } + + return blend_splits; + } bool has_directional_shadows(const uint32_t p_directional_light_count) { for (uint32_t i = 0; i < p_directional_light_count; i++) { if (directional_lights[i].shadow_opacity > 0.001) { diff --git a/godot/servers/rendering/rendering_device.cpp b/godot/servers/rendering/rendering_device.cpp index ace1c34f..72984e5a 100644 --- a/godot/servers/rendering/rendering_device.cpp +++ b/godot/servers/rendering/rendering_device.cpp @@ -32,6 +32,7 @@ #include "rendering_device.compat.inc" #include "rendering_device_binds.h" +#include "shader_include_db.h" #include "core/config/project_settings.h" #include "core/io/dir_access.h" @@ -189,6 +190,10 @@ void RenderingDevice::_free_dependencies(RID p_id) { } } +/*******************************/ +/**** SHADER INFRASTRUCTURE ****/ +/*******************************/ + void RenderingDevice::shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function) { compile_to_spirv_function = p_function; } @@ -211,7 +216,7 @@ Vector RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_ ERR_FAIL_NULL_V(compile_to_spirv_function, Vector()); - return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, this); + return compile_to_spirv_function(p_stage, ShaderIncludeDB::parse_include_files(p_source_code), p_language, r_error, this); } String RenderingDevice::shader_get_spirv_cache_key() const { diff --git a/godot/servers/rendering/rendering_device_binds.cpp b/godot/servers/rendering/rendering_device_binds.cpp index e41a56b0..9ccf1e41 100644 --- a/godot/servers/rendering/rendering_device_binds.cpp +++ b/godot/servers/rendering/rendering_device_binds.cpp @@ -30,6 +30,8 @@ #include "rendering_device_binds.h" +#include "shader_include_db.h" + Error RDShaderFile::parse_versions_from_text(const String &p_text, const String p_defines, OpenIncludeFunction p_include_func, void *p_include_func_userdata) { ERR_FAIL_NULL_V_MSG( RenderingDevice::get_singleton(), @@ -144,11 +146,17 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String break; } include = include.substr(1, include.length() - 2).strip_edges(); - String include_text = p_include_func(include, p_include_func_userdata); - if (!include_text.is_empty()) { - stage_code[stage] += "\n" + include_text + "\n"; + + String include_code = ShaderIncludeDB::get_built_in_include_file(include); + if (!include_code.is_empty()) { + stage_code[stage] += "\n" + include_code + "\n"; } else { - base_error = "#include failed for file '" + include + "'"; + String include_text = p_include_func(include, p_include_func_userdata); + if (!include_text.is_empty()) { + stage_code[stage] += "\n" + include_text + "\n"; + } else { + base_error = "#include failed for file '" + include + "'."; + } } } else { base_error = "#include used, but no include function provided."; diff --git a/godot/servers/rendering/shader_include_db.cpp b/godot/servers/rendering/shader_include_db.cpp new file mode 100644 index 00000000..bc62c1fe --- /dev/null +++ b/godot/servers/rendering/shader_include_db.cpp @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* shader_include_db.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "shader_include_db.h" + +HashMap ShaderIncludeDB::built_in_includes; + +void ShaderIncludeDB::_bind_methods() { + ClassDB::bind_static_method("ShaderIncludeDB", D_METHOD("list_built_in_include_files"), &ShaderIncludeDB::list_built_in_include_files); + ClassDB::bind_static_method("ShaderIncludeDB", D_METHOD("has_built_in_include_file", "filename"), &ShaderIncludeDB::has_built_in_include_file); + ClassDB::bind_static_method("ShaderIncludeDB", D_METHOD("get_built_in_include_file", "filename"), &ShaderIncludeDB::get_built_in_include_file); +} + +void ShaderIncludeDB::register_built_in_include_file(const String &p_filename, const String &p_shader_code) { + built_in_includes[p_filename] = p_shader_code; +} + +PackedStringArray ShaderIncludeDB::list_built_in_include_files() { + PackedStringArray ret; + + for (const KeyValue &e : built_in_includes) { + ret.push_back(e.key); + } + + return ret; +} + +bool ShaderIncludeDB::has_built_in_include_file(const String &p_filename) { + return built_in_includes.has(p_filename); +} + +String ShaderIncludeDB::get_built_in_include_file(const String &p_filename) { + const String *ptr = built_in_includes.getptr(p_filename); + + return ptr ? *ptr : String(); +} + +String ShaderIncludeDB::parse_include_files(const String &p_code) { + // Prevent needless processing if we don't have any includes. + if (p_code.find("#include ") == -1) { + return p_code; + } + + const String include = "#include "; + String parsed_code; + + Vector lines = p_code.split("\n"); + int line_count = lines.size(); + for (int i = 0; i < line_count; i++) { + const String &l = lines[i]; + + if (l.begins_with(include)) { + String include_file = l.replace(include, "").strip_edges(); + if (include_file[0] == '"') { + int end_pos = include_file.find_char('"', 1); + if (end_pos >= 0) { + include_file = include_file.substr(1, end_pos - 1); + + String include_code = ShaderIncludeDB::get_built_in_include_file(include_file); + if (!include_code.is_empty()) { + // Add these lines into our parse list so we parse them as well. + Vector include_lines = include_code.split("\n"); + + for (int j = include_lines.size() - 1; j >= 0; j--) { + lines.insert(i + 1, include_lines[j]); + } + + line_count = lines.size(); + } else { + // Just add it back in, this will cause a compile error to alert the user. + parsed_code += l + "\n"; + } + } else { + // Include as is. + parsed_code += l + "\n"; + } + } else { + // Include as is. + parsed_code += l + "\n"; + } + } else { + // Include as is. + parsed_code += l + "\n"; + } + } + + return parsed_code; +} diff --git a/godot/modules/svg/editor/resource_importer_lottie.h b/godot/servers/rendering/shader_include_db.h similarity index 56% rename from godot/modules/svg/editor/resource_importer_lottie.h rename to godot/servers/rendering/shader_include_db.h index 9cca8911..d1967a32 100644 --- a/godot/modules/svg/editor/resource_importer_lottie.h +++ b/godot/servers/rendering/shader_include_db.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* resource_importer_lottie.h */ +/* shader_include_db.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,33 +28,26 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_IMPORTER_LOTTIE_H -#define RESOURCE_IMPORTER_LOTTIE_H +#ifndef SHADER_INCLUDE_DB_H +#define SHADER_INCLUDE_DB_H -#include "core/io/json.h" -#include "core/io/resource_importer.h" -#include "editor/import/resource_importer_texture.h" +#include "core/object/class_db.h" -Ref read_lottie_json(const String &p_path); -Ref lottie_to_sprite_sheet(Ref p_json, float p_begin, float p_end, float p_fps, int p_columns, float p_scale, int p_size_limit, Size2i *r_sprite_size = nullptr, int *r_columns = nullptr, int *r_frame_count = nullptr); +class ShaderIncludeDB : public Object { + GDCLASS(ShaderIncludeDB, Object) -class ResourceImporterLottie : public ResourceImporter { - GDCLASS(ResourceImporterLottie, ResourceImporter); +private: + static HashMap built_in_includes; - Ref importer_ctex; +protected: + static void _bind_methods(); public: - virtual String get_importer_name() const override; - virtual String get_visible_name() const override; - virtual int get_preset_count() const override; - virtual String get_preset_name(int p_idx) const override; - virtual void get_import_options(const String &p_path, List *r_options, int p_preset = 0) const override; - virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap &p_options) const override; - virtual void get_recognized_extensions(List *p_extensions) const override; - virtual String get_save_extension() const override; - virtual String get_resource_type() const override; - virtual Error import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap &p_options, List *r_platform_variants, List *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; - ResourceImporterLottie(); + static void register_built_in_include_file(const String &p_filename, const String &p_shader_code); + static PackedStringArray list_built_in_include_files(); + static bool has_built_in_include_file(const String &p_filename); + static String get_built_in_include_file(const String &p_filename); + static String parse_include_files(const String &p_code); }; -#endif // RESOURCE_IMPORTER_LOTTIE_H +#endif // SHADER_INCLUDE_DB_H diff --git a/godot/tests/scene/test_audio_stream_wav.h b/godot/tests/scene/test_audio_stream_wav.h index 7276dd08..30e3f5b9 100644 --- a/godot/tests/scene/test_audio_stream_wav.h +++ b/godot/tests/scene/test_audio_stream_wav.h @@ -37,11 +37,6 @@ #include "tests/test_macros.h" -#ifdef TOOLS_ENABLED -#include "core/io/resource_loader.h" -#include "editor/import/resource_importer_wav.h" -#endif - namespace TestAudioStreamWAV { // Default wav rate for test cases. @@ -148,25 +143,8 @@ void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo, Ref wav_file = FileAccess::open(save_path, FileAccess::READ, &error); REQUIRE(error == OK); -#ifdef TOOLS_ENABLED - // The WAV importer can be used if enabled to check that the saved file is valid. - Ref wav_importer = memnew(ResourceImporterWAV); - - List options_list; - wav_importer->get_import_options("", &options_list); - - HashMap options_map; - for (const ResourceImporter::ImportOption &E : options_list) { - options_map[E.option.name] = E.default_value; - } - // Compressed streams can't be saved, disable compression. - options_map["compress/mode"] = 0; - - REQUIRE(wav_importer->import(0, save_path, save_path, options_map, nullptr) == OK); - - String load_path = save_path + "." + wav_importer->get_save_extension(); - Ref loaded_stream = ResourceLoader::load(load_path, "AudioStreamWAV", ResourceFormatImporter::CACHE_MODE_IGNORE, &error); - REQUIRE(error == OK); + Dictionary options; + Ref loaded_stream = AudioStreamWAV::load_from_file(save_path, options); CHECK(loaded_stream->get_format() == stream->get_format()); CHECK(loaded_stream->get_loop_mode() == stream->get_loop_mode()); @@ -177,7 +155,6 @@ void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo, CHECK(loaded_stream->get_length() == stream->get_length()); CHECK(loaded_stream->is_monophonic() == stream->is_monophonic()); CHECK(loaded_stream->get_data() == stream->get_data()); -#endif } } diff --git a/godot/tests/servers/test_text_server.h b/godot/tests/servers/test_text_server.h index 4190d3c2..4e20d43e 100644 --- a/godot/tests/servers/test_text_server.h +++ b/godot/tests/servers/test_text_server.h @@ -124,7 +124,7 @@ TEST_SUITE("[TextServer]") { RID font1 = ts->create_font(); ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); RID font2 = ts->create_font(); - ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + ts->font_set_data_ptr(font2, _font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size); Array font; font.push_back(font1); @@ -180,7 +180,7 @@ TEST_SUITE("[TextServer]") { ts->font_set_data_ptr(font2, _font_NotoSansThai_Regular, _font_NotoSansThai_Regular_size); ts->font_set_allow_system_fallback(font2, false); RID font3 = ts->create_font(); - ts->font_set_data_ptr(font3, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + ts->font_set_data_ptr(font3, _font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size); ts->font_set_allow_system_fallback(font3, false); Array font; @@ -503,7 +503,7 @@ TEST_SUITE("[TextServer]") { { U" มีอุปกรณ์\nนี้", { 0, 11, 11, 19, 19, 22 } }, { U"الحمدا لحمدا لحمـــد", { 0, 13, 13, 20 } }, { U" الحمد test", { 0, 15, 15, 19 } }, - { U"الحمـد الرياضي العربي", { 0, 7, 7, 21 } }, + { U"الحمـد الرياضي العربي", { 0, 7, 7, 15, 15, 21 } }, }; for (size_t j = 0; j < sizeof(cases) / sizeof(TestCase); j++) { RID ctx = ts->create_shaped_text(); @@ -584,7 +584,7 @@ TEST_SUITE("[TextServer]") { RID font1 = ts->create_font(); ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); RID font2 = ts->create_font(); - ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + ts->font_set_data_ptr(font2, _font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size); Array font; font.push_back(font1); diff --git a/godot/thirdparty/README.md b/godot/thirdparty/README.md index 2cf40f01..f757f458 100644 --- a/godot/thirdparty/README.md +++ b/godot/thirdparty/README.md @@ -257,10 +257,6 @@ Files extracted from upstream source: * Upstream: https://github.com/JetBrains/JetBrainsMono * Version: 2.304 (cd5227bd1f61dff3bbd6c814ceaf7ffd95e947d9, 2023) * License: OFL-1.1 -- `NotoNaskhArabicUI*.woff2`: - * Upstream: https://github.com/notofonts/arabic - * Version: 2.014 (133ccaebf922ca080a7eef22998611ac3c242df9, 2022) - * License: OFL-1.1 - `NotoSans*.woff2`: * Upstream: https://github.com/notofonts/latin-greek-cyrillic * Version: 2.012 (9ea0c8d37bff0c0067b03777f40aa04f2bf78f99, 2023) @@ -309,6 +305,10 @@ Files extracted from upstream source: * Upstream: https://fonts.google.com/specimen/Open+Sans * Version: 1.10 (downloaded from Google Fonts in February 2021) * License: Apache 2.0 +- `Vazirmatn*.woff2`: + * Upstream: https://github.com/rastikerdar/vazirmatn + * Version: 33.003 (83629f877e8f084cc07b47030b5d3a0ff06c76ec, 2022) + * License: OFL-1.1 All fonts are converted from the unhinted `.ttf` sources using the `https://github.com/google/woff2` tool. @@ -469,81 +469,6 @@ Files extracted from upstream source: - `LICENSE` -## libdatachannel - -- Upstream: https://github.com/paullouisageneau/libdatachannel -- Version: 0.19.1 (c59cea8973fe5a182feb3159638af338752efa9b, 2023) -- License: MPL 2.0 - -File extracted from upstream release tarball: - -- All `*.h` and `*.hpp` from `include/rtc/` to `thirdparty/libdatachannel/include/rtc/`. -- All `*.cpp` from `src/impl/` to `thirdparty/libdatachannel/src/impl/` except for - - cpp files starting with `poll`, - - cpp files starting with `ws`, - - cpp files starting with `websocket`, - - cpp files starting with `tcp`, - - cpp files starting with `http`, - - `dtlssrtpransport.cpp`, - - `tlstransport.cpp`, - - `verifiedtlstransport.cpp`, - - `sha.cpp` - tcp|grep -v srtptransport|grep -v http|grep -v poll|grep -v sha.cpp -- All `*.cpp` from `src/` to `thirdparty/libdatachannel/src/` except for - - cpp files containing `packet`, - - cpp files containing `nalunit`, - - cpp files containing `rtcp`, - - cpp files containing `handler`, - - cpp files containing `websocket`, - - `capi.cpp` -- The entire folder `deps/plog/include/plog/` to `thirdparty/libdatachannel/deps/plog/include/plog/`. No other files in deps/plog are needed. -- The entire folder `deps/usrsctp/usrsctplib/` to `thirdparty/libdatachannel/deps/usrsctp/usrsctplib/` -- All `*.c` and `*.h` files in `deps/libjuice/src/` to `thirdparty/libdatachannel/deps/libjuice/src/` -- `juice.h` from `deps/libjuice/include/juice/` to `thirdparty/libdatachannel/deps/libjuice/include/juice/` -- The `LICENSE` file. -- The `deps/plog/LICENSE` file. -- The `deps/usrsctp/LICENSE.md` file. -- The `deps/libjuice/LICENSE` file. -- Added 2 files `include/rtc/exception_wrapper_godot.hpp` and `src/exception_wrapper_godot.cpp` - providing try/catch exception wrappers around rtc functions. -- Apply `thirdparty/libdatachannel/patches/virtual_destructor.patch` to add missing virtual destructors. -- Apply `thirdparty/libdatachannel/patches/fix_mingw.patch` to add a couple mingw compiler fixes. -- Apply `thirdparty/libdatachannel/patches/mbedtls_optional_apis.patch` to avoid usage of mbedtls APIs that are compiled out. -- Apply `thirdparty/libdatachannel/patches/disable_logging.patch` to compile out logging in release templates. - - -## libdatachannel Submodules: - -### libjuice - -- Upstream: https://github.com/paullouisageneau/libjuice -- Version: 1.3.1 (7d7a66d439b2e3e55e3f2494ff1176d527335674, 2023) -- License: MPL 2.0 - -Module location: - -- thirdparty/libdatachannel/deps/libjuice - -### plog - -- Upstream: https://github.com/SergiusTheBest/plog -- Version: 1.1.10 (e21baecd4753f14da64ede979c5a19302618b752, 2023) -- License: MIT - -Module location: - -- thirdparty/libdatachannel/deps/plog - -### usrsctp - -- Upstream: https://github.com/sctplab/usrsctp -- Version: git (5ca29ac7d8055802c7657191325c06386640ac24, 2023) -- License: BSD-3-Clause - -Module location: - -- thirdparty/libdatachannel/deps/usrsctp - ## libktx - Upstream: https://github.com/KhronosGroup/KTX-Software @@ -803,8 +728,8 @@ Collection of single-file libraries used in Godot components. * License: MIT - `qoa.h` * Upstream: https://github.com/phoboslab/qoa - * Version: git (e0c69447d4d3945c3c92ac1751e4cdc9803a8303, 2024) - * Modifications: Added a few modifiers to comply with C++ nature. + * Version: git (a2d927f8ce78a85e903676a33e0f956e53b89f7d, 2024) + * Modifications: Added implementation through `qoa.c`. * License: MIT - `r128.{c,h}` * Upstream: https://github.com/fahickman/r128 @@ -1003,7 +928,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.15.3 (2207c8ce5e28f566d90ad0ba74afa3fb0ff49f5d, 2024) +- Version: 0.15.5 (89ab573acb253567975b2494069c7ee9abc9267c, 2024) - License: MIT Files extracted from upstream source: @@ -1015,7 +940,7 @@ number and run the script. ## ufbx - Upstream: https://github.com/ufbx/ufbx -- Version: 0.14.3 (19bdb7e7ef02eb914d5e7211a3685f50ee6d27e3, 2024) +- Version: 0.15.0 (24eea6f40929fe0f679b7950def378edb003afdb, 2024) - License: MIT Files extracted from upstream source: diff --git a/godot/thirdparty/fonts/LICENSE.Vazirmatn.txt b/godot/thirdparty/fonts/LICENSE.Vazirmatn.txt new file mode 100644 index 00000000..be66b382 --- /dev/null +++ b/godot/thirdparty/fonts/LICENSE.Vazirmatn.txt @@ -0,0 +1,93 @@ +Copyright 2015 The Vazirmatn Project Authors (https://github.com/rastikerdar/vazirmatn) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/godot/thirdparty/fonts/NotoNaskhArabicUI_Bold.woff2 b/godot/thirdparty/fonts/NotoNaskhArabicUI_Bold.woff2 deleted file mode 100644 index e9a834ac6907b4cd564f66d8f2f8d64005c5187f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53860 zcmV)tK$pLFPew8T0RR910McXt4FCWD0+eI`0MZ8l0RR9100000000000000000000 z0000Qg$f&imoyx;5(Z!Zl5`4&*)WB>ZVQACI^9#Gg}-uk_7*D z?ENujDmtZeY+D26aM6hBtVd{e-$v+Q=V<9}5$0bMDwNxfxE&;Ua=kMUlgb@cBc7qBeTWnxmh9k^HETP{t)yBd;{wgF!5h1qWqSfs2MA(rp_3W?e7|U#zkwhaw70oX z@2R^ATWzhi)+GB=@FyJBaaZpm*}wm=XU-~Ti7ugQcJPCLeOm{_W5X#uTEvR;>iWVL z?_bcLs_wpT7LX#Cv7$|tT3_T$Lk4rTle9+w?jFG?^+F@`_Iuv#eLb7xm&vUHjnfQ5 zG9HaUYm7#k4v?N5l88APD^}Psc9hyNXNNU*P(-V$V;e!o(tatm>NRcc){YUvEaov>hx8c|C&U}Q=}iAsf{qGIN2W5rvqzVSxaTQ#xv{l39;8WB2)#B@S24aKwA zn(Gt2JH$d`NF=%#6t%a9_4MrCLAIb!I>+)!q7Wu&ghF_v!03?wn*hiF009I!)QK{0 zUYilzZMCe_00Qzm{JJ-!^ruqi8W#_K-~s-~`(LMdNqB}|kN_79U-*!V+&aF}>?>nh zT{CRi)(q2r^S_2mt9By(#ZPQQv=J$dN5d1ek?~L}6Zd<>@ydQRbD0eFgxN(tkpgb{ zkp@M$CVf^rzezPWYez)8_HNQl0xb@_SN^TFe`)xu|ks&pDU6C|A|mf74AV0U53YKQMd#um4}$d~)Q4x!k2$N z6*dloJqff-x47#^-KSE@()vJf4%(I>NNb0whTw-1?0|FT1Hz=hK=A5);$DBWN|+56 z=Kpo;|C9SVyw@ozmQw)RlgKU)rft}F9A-?H|$FS+D`3aK367GW_CrG_5T+nyqXJdU7p5(Z&8 z81X}hLZZZ1PJE);aliPWctA}M2b^aVeAIrcckhobeuLMkRNr~3Q{4Z0r)nc*2 zi8!U$tLb@y>|A+Vy5hJgsK58|hB`tKbcoZ(qVf#>zP$s`2*YQHa^yO!Lemg*EH$d!T1|D_-N%0du;eB9%%dnMrcSMwj;HF}g;;A` zx#(OphX2p`mDEpfe=TnkoiVXC00scEC8O4z*{ZSfvtNEa4cLYSpx{6n8nlGw|4cR8 z8G->6b!Xt{0Nz!JmqO7wh1R)r(Yf3GvkUCZU?E@@6c;;$1S}|>xH#!Siwo3}(lLk< zsB|GwatN`vxa0+bmq=a=m2(|Z=t3+y=i1#>rArsJUHZA`Ty(9A%0+L2+;J9g^oIdp zfhE{hkmi=LxBttUO{k$(1#S=qT{S3)<+7K_{OzHXrsf=_{dRmxx6Sc9Lb3AX3F+1% z;er3#%VFnS!9YVw?Ee928`ui~!{NjR|NYPWPug#(c8^z`(I~4C_jxRU1;M{0RVjmy zGgf9NGvU6CzG+alsTqNa8#&yL*W->cDa(*)3w+KO?Yo2cr~N3xh@b^yM99YejrIS% zqeK2}leiqjiHH!15Q%6cLYjyW5$W%D_P;Fyk*=Q4U)_7=xCS(6U`3sk6*Vw0uvP{G z3gjfsiG1KakfBW&Gp z>&Ua%&33mx98c#v2q7p&kQ66~lA>ys?Ic-VlvUkscl+b%e5EqjTpj?z2ucWq5~++V zbEYQRXn>(m6(F5e1w%0~h$T&4?+??T1L{SR4E`b!A5axJ)G2+vyQlJux{+fZ2g-UnFHhoGd7!P=(~O*C*4 zWh`I_nt=+WU}6FbhsF>6@)Y6l-EZCS#MH|Ni0vPI2Oy^ zGJkyOCLM^3Sh5PFwaf&2Jtd%sx#f^c#C-7$P?0beJhLVNBvU8?sX{LWNpz&3oY$Sq zshk823_CzFAyy*&;fE!5eCwb_jRkTW#Ex(5rY)6i8%n_Et2A@~YxcxG%m3 zsoWg$igVs_T>ehHEVITYJM40Udw`Jr7g_re58rrwx`^O;xNv!NiWkv{N8vkp%{xAR z!20qB36Nj!t;Y$$%)9UT(LTuP|Huckj$bFOQ`VXL(<(JjwR>;V_IO|HEXGBgyUq6d zP7gP}%(9qcibA~O=&ttBpXNet6GcK=PEkeu!&-na>id=;ThGjzzZHri6$LdNBMUnh zuYj$k-LO{b!i2!=BQ3(KW1s$6zycL;{WTBiE^_Ls) zuYW$g&s-#eXfBRR3sBl- zI{|x#0FPHdSShildH|lJOv}rv{AoOAY@r`+`AZPtk@c{6U2Kf?Oh?wquRJ*KS%8^W z3Fh-<#hNWXM*?oV`RZ?=K_ZM0^DPpLJ;<$q{KRWvcsALqr;@xTZ^*myKbdSFpG20D zhvca|v(!_@KF=s}m;7gB)!vjf>3x^^lWTFrlR%!e_AQzP3H%#?pa(V{AqhDZEkkGC zm!o7eiIaGWnRNVgp?yyr(IlFMH_6f6mwf7q`yQCVpw_4xDw5i{k7x z5YD&rJzy6up19xQ;$iu+R?SO-{{RyP2{{!l12Y@vtsX$?0PvfPyT)JYJ-|Yuo>Y?P z@*MH0pLq&SPKpgy+trILcEJ*GsI-6$A&^nA!hHxr1Q8P%Q7+Il^f6U9);NS1x2*8> z{X}|CN+pXz$}PH@X1cYq0c5<^d8)hN22?V_!N;ywy_qOLjsH^u@x7jF#!QkZaJ)C?enL$%~nndA9y(kt7FZLkFBVay$Q zkY4jI-%9Ms<0yQ(*|z-J?#VwktH;52K7*!XhY;@jfcw#K@`n#dAWLz0(WjYf`_HfQ zvCsTXxIe72#4kvAd*I3LPY|{a3fy-u_?S=rV=^#~l+O=J&nLJmmD>(7TzC0P?LcYA zjsXZ&hJdtb^Zif#9PaxL_lN6G!*|q@hGkb-Ih%|_;H$o|s}1+HaG#^XK7>-M)GPua^P?V--`!XovY8J~Bp zYRM#=S<$S5+YN%$2ds`UQ^`*%nuFC289P**_qE zX5nN3@DR!dfSojlRcn-oV%H}K&#B$(z3~*Va^XrrC4J$+GtWGGH{fJ=bAg%E2sjo2 zIA{SxPD`>7Zxr0!OILbZ_Tx27LhUwV91%G}2KLa4XVR6QV2E*kKVS7Wd+FIa* z$M`igBNBOp8FC5Fpn|v98Xf%BWp}@a0CJY_^e20-B!K7g{Oi;ss^?!%y}+^QLj2Imd%XOhh4r-1s6 z=oH4!#{$!IQlr}%CL zpypi8Vw6u9%y2Wizn*5W24@u2>x|G7tSEq*Sd46%=L>D4?X{i_@(nT-t)~7W2ZMq| zckL^QI+7y>#RsJZWtR)~Ht)5XkPK=L>I~{0oVA}2J9EEsUeC~Px6B^=;^49$w&zmE ztgreafz7<*G7Lj~#gjTB-*q&RNMMD4BaujyzzP9JB9SP8LpnwEo^G4*DB7p|3xf?d zgq|p=2cn!nG?W2#A}lawVZq1~n1y=%pf!v3xA~|1U~}9P1T-BXja-8kK@pV(-2z+R z?Q2pq=p_50lm9q|b|>6d1GpB4HP*SNEfGysid8py9};LCwA*-H}pFH*mIKPao- z`dz{*llqX4S?p>)u0vx;BdD!$vTAv6>SIQRA{IHZxS5)AD6EcFzf4vSi$RheR>v?7 z&VU0x21W!a)Vb01oLIaY_7QL)V8f3_%&zKd&ikj4EW6P#wDo;PcVc9aN9nW*$pI@v zFnSpPG9!JI}QFIZ-Vg70ZQw@=ZZZ7`q}`9R=bk9?sDC&M-6v%swz_h_f=F zHyqxK`(GMQQ$OK7Eu4%h5}ye~0)ZD5f!q+O1nP0f1zd?Z_D9maDPI%7z<4j1ThG@|VEwPofD)iZ!1PCUfi@zmA=_&VPMsZc_qS z&?2Vai)5)?O;U+S>Le|ax0hCHIk#bs<Ir?hR;?a{}Yef-8Y-ylD^m!DI$>V6KmkvGLE3>{y&(yF4!l7d!D zx*~DtJjtgUQ7KkkuHciFJ7Ce?7FwfMgK8MWG>K-~s{CE*t9OH{eZQ~1C=xq6eRX($ z*Hd&*>Ih6Q!_6DG*KKa(9(^y*^v2VI{r!S36czRr5(JPz1q)mVAco8;pWA80f0B}z zMP+U{42_lyeYCz$f;?$D8lnzX?vk^#3X@e!ud$zGdJXGVxdr9uTPv+#x4IEFVkEO= z#8)bgoi~xy-C!^FxHilF5jew79cn+`*We0s-0DN5&teyed61aLlp6sw za3F5dd!;9B`W2H+<=nhp$dsI;mv5ETPtcAGiD|y_1?tJdk5G(`p6tY;L$0l4Qhoo; zSU>game}&;ev41o+Bs7D5iW3Pr;AH_hd!=UtW<#Ih?$FCQPL~^nn*>>-Xt}CPCB(% zv=fM~CzsTlH1GtIhC7W#$9XMj6%DkH-|H9M(ZdV|c2*lodQY#Ohy^2qlVLj+RYro& z#CHWUXsqd*v15+A10Uis3t4$$&7E(n&U&J~yAaQ~w4ZzV&2-o}!r0!DFTN!AF}dmt zoog)`2&lPK8_`K1dfp%8(d5PVi^x#-R$bo`KM~NaQV-B`1i$J}@w-4Cnz=s)VDALW zUrgjZ3>$xZpTwqcaMCl`9I5zhQ6&Y)75>}SA_r=tgRzMY?8bHAHGzZht71BjWMrCm ze)Cy-KHBmA^ve^|#rGf9fnkJ+eBKh^4m6Sy_RdU+eQ&1MRFzP*C@t&0axYa-LJV0{ zzPd_jTC+##PM?m08OiuIb+nI^ZqCqcX0t$IS-y3&v$kwjhJ()Qb<>tF^k>-)>Crex zkSEwO`${R4WneAm#=qKs`2T$m!YeV@$IP*6P&V0gr#lkZGXOWp-y?+Mi0QxK}w%8*wxEHJlP&IFc zmy<+)Ls#%vV=hd!9>~ueH8lZdkHKloITg0)d2h{~(fc0=?J{yVYhU#CShOWv<#eur zWXd9yk~Uik-~u_`mV>wcTH^*Hid!lUrr@PBc?S9z{4FF{{RQMo-`tP0Ly7P zoWw$~?LauU)QZjH(nt(Jc1}Lm9z^9B;i{Xcf9Q$>+lu1CUpepHiflVAtxInU8Qh zG%|JKW=ev_OSE({r*dqzPmHxBM(W{9bD<>tBpVhWM^fL&4`|N!Q@z^9$_ttW{Yh7c z^b7}S{i4hks!vX`@1V<)&e2+0yksO8o;vEJ^r1&=vT=nEK*tvP$gO(Om~z2$F(pM- z&B=c~pAYn2loVpV6vFt7@t)9m79?anS(mEfv(gSWpWNh ztCCV&<%>C&^uM@a?{0-BJG^k*;?5@7?`(y0He9GQ@o2bOgW-LA zZ0rZLj?=%@`@YG#0wlW1(P1g+M_)^MeW+fIU23(KMQOX2iS=rP)M8YEmdI9^Pwa+A zEt|?F>b&6ROKS^n+T5w6qcfk<^{UdgPp4*Xr2|zv+c#aA`L5@{5{R+_v#LBB`ZB28 z@@aWfSk(gi(&owwyUX_KRE=>v&8u8;eScEzW4r^Tg_W!Jl;_o}TDfxHlUM^OWvcz> zs+HDmC{+F)3oGGi z9i%;#FGcQibTw8lqt%F_zO-3oeL zd))poeTBL;a6Ix@!>oDM@0wZ_XJ|xiW#!kLUf=wmf6eqVYesd8@1##dv#F%3-{+9w z#xT=UkY=a*6qL1Wwb;ZFyyf?8koBxu5~{tDuVDu->*?K{A>5`?*>d|XA?w+!r}4+T zs&*281EqI0BXogiGZi!eS7irPQcXlYku4#wsY051M_uuFa<%U^Qe;gYB7C4W?)8VV zeuhbSssp45fZmL5p4D3_ODmUYuP*9*Ej)ZukYie##oE=dum+m0)LY4oH@!ibP~7gB z%dDCJ@7kaiTIL;9ZspdsR0oTRF1rG5>dUqOOVHvZ`AnVKs+py}hrMP@QO_)@b(UJT zLyDDI)pU*Hk9A?QIjN1uRL_rEpNj@_5-`$>Zte@v_^P4+4fjkvHV0_NQ{wKUWQeHJ zA*8%G?lWi=gNR5IcE;?`DJE7`?%~!90TVnXLOb;gvOvv6ai{NDH#8sC*q`t!CSkRB z!LwX)E2KQZ@>;VhCoz54bz9z9ga$LX>Kim`)OgeOwU*nb2{U32r?9ekimzIJ5S&X` zsv6`VJ|(A5(=y;xBGb-62Jj@cJnvX@6e%`~_Ce9Wy$LGk>Z3}**QxdRUVYS#l%Ojv zV+c*bRc3~_WTZN^7QGyXOsm4tklbcYg<%9&cG;@3ye00LqAT6Bhet=DVdhZP98HUS z_{*h>_9zw9*4>KRjmW$9UVmz7vz{j_K6fnTRL#}gxE*V!vju2oTR(#ahiM!=(%O^p zDntlpIZG?ZjPlzR6T88{kGQ>&c@lM-02q8sSlGA+Heniw@T4|mVdA^`s9`h*78lt0 z8&BsG9D)F|T}*I?^(+>Ig#|1uEHT|e5oXNeG9#_vFPJ& z?eVe5S=v3eg?P9wen62->W_4z*vfb2BQ% zSE?+Hd6*&XWWF~aA^l()uigIeuDRtON7a5 z56-RdCY{OMy6Jrs9v{6j)7`9bmG)l45O8ntPa&>H9A8yoDHE^@4NVo!EC$BerNY-Q zYDs60w63ZbwN-k;-;;efb@f-LMemF^^-n8%q3NDe9oKi^DDHSz>IRDzs%g!=on+c( zYSpyNu525$A13)YZ%Z3Vw1%=cvrOa{PWbw^mVuV4_6}j@yG*N`WhO1;rY~3VZP1OV z^3Ybj7(kz2Irg)piXUpRtB=D>KZ4L|pZG^p4qUah7OB&wA5U6&*SZfnA3nqAK&RrJ zJYle=!Ph7Ye14k0YI#Glj;?+eEW2;ftkKo~g+O{aYX+mM%#vwEJ_TS9GN#TP7Lm<% z0z;U=@KWy0&B09i{7#FuY-b&M0gD7)Gskp0Y<7b-fWG;=)5pEWZ^D@tp?$$9Q~X`> zbg60Msl}+fFtM_+bhb0IL2j&CKM2YN^4v9bu8|&} zztKE*f6I9rCbNn{XaKAxk?g%?vk0^cfj~s`&Kk9yz!#o;3Av8PrK4od9w~g%OqHyC z)6$wrPy~-UzdW8xrA>*)y6dIj&ly}9TKAA@*Kw)Y2<{8=OTY5bcly@sZAgt$ElHn; zJbJo3Nwdf-&MX#Fs-oK@M)Y<-T3JkJB<;C$>`|0kr5-0&*!!7L^I_whShDQcTKAN< zJa#ODP4i`a8Puk#K2g;@dDXLU?-~;?V{-n7>(=|sy;lRWw_EHFIsf8_-VNAm?{aeO zU6)!-4f-5GnQjw0X z1RaNX#3vzG{vy{U5Oa~g7sA*4&*)#fmI3X4w10;#p9%O3y?%rQ>*2dTzX=o<26=?X zDdl_aPnh*v4Lyhd#$Fc{d$2&)tP}|SCiL%Hy0SZYYW8)zvidyG8xEJish;ERsR#QX zoxSawK9Y~AB;?`-DUOcKgwuL@y2MhVM?525q`b&i?b`89h^H;jBDHkLmNhM{1wcaw)gcmAW*gDs9-sESA@Fo3~e#xI~kLzn=DM!z34sdt*( zrvu~)$_nKk_6SEl>d}v3g2p`Pu^X518lMT8h>1fl8)mte#VlnxD#Pyo=B$BnXDXKqV52S%-{$l3XQ>H=j4XTgK>c* zn)=*7rPKllWpQ}GE>esHDKd-t{Wv;Q8nE#E!*)QJ>C$s1igTMgMMdn zg;J#!KnRn~Ei;w^ICACbI$r@o;qJvslqyp$7>>r1>1@7O&i}@0jaGYC|NCvytR-tU z?K()$tS46g!f;`_JnV#df+bR!T%lB{HCoy`C+RDaL}&BGa<$%U>*&hhLKt5h=S!tu zs;#viRo70z;|C;^aR3n}lyLweOeo_31Su^m56b5+YOM1@Ds8OugjCvC=LHH=TUQ@W zuRpTX)9SoPFn)2{RV0+OT6^51m96Kr@_f)*<98ySD^}Kw)qM5{1TKVPogyb|@u+ zIF=8$=#ihr6UkIMlZ}H5odcpIyIWJR@@SP;Ib&LDJ_ei53!~J@QYep6R7o5HhUP8f z(M*Liq7%`>`dY4;J;_G4lvRb-YDaa6ZK!sC_ro@g26 z+IG6wa$uc}wjklpmfP&}QcxhR(rTe@?JG_%S zyGu(VceyY73a|XCul^ct5V>;EYrg1fcU`U*Dy`frfZg}NLytW6#8c1ed5eQbKtw`D zK}AEyz${iuKoi$2N402=|sENNFjput=L%I)+i!ddi44iUvnwgl$Igq;h)EK@+N!P&p{4z z6iQBVmh;eZA?X3rgF#>j7z$ zOj#nn0*HYj5^#hR8Y6=z$dM@ubcPa}qrw-ci6t6xh5rIn+FG5rMw719#us}B+phZb z{BOva-$wj0>97BpHShnHEW5IXWMJ>HZtBnng_(#%nL#3(LubqdYz~(21y+b9R?8LEt2IXT2HVUQyKL?3 zb98c$LUn|}bb`xs8iJk2aF_Xl-~75*5~PDc!8!wGSkf0RJRG>j4eoG{2Rz~l&v?Nr z-tdkOeBujrG|)r~Uuoq#?TC>gM}Z188V=2f`4+aQ;g+zJ5tg;Q6^*p2)val5>)O!9 zCYtMf-*lC0b0fD7dBI*}fKw+?(bMLyF&42EXWa0@k0AOp_%XOWnpxU9x_Vys4GfKp zO-#+qg>jmfb=!~gy8kN)c0orVCgLCq)K>x$l9(hVBLyL)E^VP?D3e&kI`(mnd#=Vi z{s~TaA`_kXBqu%D$yc$;RH+)>(LFuVGc~G3ZF-{*`m9b32(K|siy)%bwXJ_T)QQe? zkqC6lW?DQ#Y3Uo2Pa&9;uNUcd=dCRZp`YK>NVXSZwsA%r|jKvYi3tFm<%A2;D8 zGC_eX%qvRlV>8M_Mci56#%YSft*=$sRE&g29;W7K<|7|_rmB7RNeK^ z%;@-ZP}Ln`IOS-;X_Cn0S%(@1>je7LQfr}=t0k>iB>8eRgS#Ot5n&hTc8@*>vRYFe!o}y zE=OJE}d#ymfOv2w%6J5N^ZJg!)KP)z*i4##rW1a0a4e1@IkN51dB zlk77PW_p;9){?Uk=OWHToQF87y&*5%kGe8Z>X>uT+W?fmI17E)L4!vXZ6g_snr~jq@-!R{h zbQ8B~EjOV2E%&k^SF(=Hm;%*X{okev$sTzvFAId-I>dO&R?vmHikLgOn2~ zQoBL~Q?J7$sS6eI zmY!kToFJ0~CqA7bYTFFhDKRJ93#*#8WpiHPs`>vW(U;>DzOI~8%&M^Kq>+|5$N%QS zjmrUy!x1O($o-O~?!Q3#31tJ2ZDlY9_^TKY{AdysOR6LCcuX~$XIBJL1nW^!!d zH}Oi<(6-TWXG~fZtysfmIv5^LRAOBCx{2B<6+^ePOsuUp^|s#Chx%CU^{L#i@sDzh zd|w^and3R};~X;NcK<-fJM85h@;4T~Y>0`RWms-ERKA=bcd|e3rzxUNi{x=>2Z=8n zJR5xC(ResXwdjPXg~$|~i^C>roNF3vC4p$EMCZl8%A+GERN^v9SngY(0C?0{oVcT zA4T~72Ooa)aY<=;RhxDmAgQ|DBbI6b2tjemZ1rFEM2Qw>Ww!+w+7x;2a_k)lXiDFBAX{w=`4K`D-0$ZCwDk0(&+3?M77(B5i_pr zlIlRbv6m^C`6V@ttvhrJ*pq#Wj7iF+I?Wj3VHC=)1k2VTHgvwH{E6Z?N-NU%%%mi_PIHlqwHkWRhAYx3;mewewl1gd;!{DvfToweuZ^ z%j1hBQoYgOj)RQ9zOJk^7)m62m6jf#n3bK-^Pt|XE3c?*+osnk?z?D0fky2y&?CLC zNWS#Pluqp|&(ge;Hx2_i=g^TpF_*9mI9^981yeHpd!@F=p~t4>rT7!A5p_b^PEDRWX-l6d(;q`0h5@*4D4hvqpWW; z%|&bBk&nIa1CxDdlGg#yV*zM=7AR`~=YJer{$+6X=fT|f0005?1%N=Hev}HWJHugN zhve%a^-pScfFW+xsk3~0mY*Os8Pw_7FvT)s{jqj61j+9EE^`7b?ZB=-V$FQq*(TIw zLbuf-z%yLhCLXIn!A8t!Hju1`E$%=U3&lck@hRgKvAxwWdg#u#QtGbvcKZ0A+rQKY zJZ(9k-@D}h46=QL4f_27F(BV2AEn`xKLsa40xoB6o=cMOv|mDct_sSs-{amOt$Q}@rtg34;dehOTG=SX--SJ!L1(a z>N1|G$(l#X@qot4l~a3I-#!KZfVn?srPF!Qd1X+&wpFWOq8iS5v8I+$ns_TeNC-U= z%EP9iOi`q`=_F$v_YRYU+UMOC9`ai6bZD^#GFG$W!%o~M)wlce6r5s8&zir!sw z0sU?Fj^miS+Ud`Hea+m7Z}|yNZ`?MT%z{ng78c-XqEF<1SZq+l0sMm25#+vgu$0J9 zRr`PsLsOQ{kHtA!iodFrh>Sl`DmC`NBdP{ZwAYea30G+V#DCca(k#e>WtRDKqMTYp z6Rnv=2rM9gy)lnT#@r*=WP2b{5q#BsUAvjGC=(Q8v*4 zBXDu{aWg5ytbe{{3}8^qTm>RKvTkC%o0Ib>aOtII&-IFihfIM=u>hMh01OMkt!BtE z@ICC8-^PVw^Fj>&@YI(FSX*I)$fV)^O*F4wA{kJl7_;hOJ&@?Tp8jsumSwdKZn@zt1r&jg=WKm)2dn z|?fMfev+G~^jJeU_Aw{~}Km&meFAt2x_Y?`HkWE_IuV`>-e@3l0i?2X9rli^_ znWCm#?r?YzXeL1;FKggq|^&=NxlG!4MUdQ@=(_T{!)OeUBsG#y3T%YdqvbyeM`Gc%MB&Ir+ zYjK5mxrmn1-Wc9{ZJ|b^{IM3r7o}4k4jEo){7R(<10WU52I4HaYF&SC&V*ms#*a>9 zSh7^-aMhIA=&NGH5|wrpTv1_d&q_9unS=&;H|8VaSA5#52q4X-y(X5N zSi*g6l5EXJR(B2SY!88Zaz#-kDoI#{T_$(q;e3|Ha8B`Bc0f z%OFITEkpA8vNA5*hB`TyXY=$f$Zi zAaLDzZCutSMb#R>#7p#6ZmK}mzX$ub)n&J(O zJG0}jZmoqbn$OvvM&!zjB#sRQK$%wV!|D@kLWNR8u`}7x-Ei`{n4h1oHO!XlM$COF zSR~5>f`hf=9@QE4Aq9iVK?zbiKcvG1a&^A@fEPAN4((V2LcEDSA9M#Pf;$KFp0k#5 zLvc4yv&`w(Y&FXJ@ot2&CqVjv0GC{clc|oOb~CS2q_!K% zY>MP}>1Um~Q9PsO^lV+b#YXnnYID-OvP?G)hl2PDBKr+WL{SSYrGs3n#vE{5Mri|2 zpNzO0tzw+&qGx;-AVYrDUz(P1^|;`|fEO`1vik0mhQ(Jq6Z=yKDPfYb;C-!Q?{izg z7h;PO*}y~cdl%p4Qp6=`@^RN4mt6(<|6Z0j|ET;B=BDs+7YoErZp|h{M~GwXMurP6 zYv~wf{Z`aNo=v(nAepwGQGL_>l;2$jj2{*Be8qBmu2OH8$>hIW?~r?YO56xkI)yvX z%{sc6pQhE-$x%bx&b#|G63@iE!$K+NI=TAFz6ml+RTop&sGM$2*T7+gl~4@SuPKkx zR^5F5<}~Lm%b-&xoUA3{d*XwV=W!0M(&|zD)pDHgWT=dqEsvjAt~bkdDv`G(2G_s; zMNsW8?P7M0&etQ~=CPt}#p+vlU&vX>*7P1vIYQ}eLwLpG?(d}C>{zr=Kw-@qWyeQt z&>frrjVxz#$*!H;;Rtg6G-aJYACOfiQ&`?~ofnyg#mKg>(6j>DDy&SdX`yT$jt$ zyY18LK0PGVTM9jQ!*;$yu;1r1vm&^d84A|UWL!0iPjAESZ6th0b$G5pLkFnT0Tlp| zqM+Uuj|VD@uJu`Qa{#fGI&a;pf1qt3xmAK6LdApPlf0!U5oBX~1}a&=K{nT)v%xnL86SNXlsvr9y0_LVZ(11qW@TtyIVIodKmU6NR@Gl-M-Hr&2EUZekb`3+*=#7tMmK6)VFda~QS$+c zcb^XvOwGX-wpZe;51eDn@VKUFDG975S4ugwOGuA&^{{@4DI~8u&F8h+6=}(xndl1pE^~}Qq(&%tIeM_WZ|3~A z(jk_Kz$?j20z=K|jlH5h^Z}q)a!4fp#U}W*s8D1?YcPS6#lYzRUPdCV(^z5bm0{CX zfKc!OFlfSg54)q?S->?)WP}X5pJKV^i8N+$`{$p@BYssHTV6JEYe2yOXKchtq~{*> zW3++5>r(dVQvFf@6^E(p2vbe6X5kZ{*R2_>wr^uv*B3K644ko0M>^=a1ShTZmz0mP8Y6DXZKWTe5{ zD|n_avG(FkbdO~O=CqAIS<3I3)ak^%jVe*%M3ZpOTp8C6usfY;#^>vWql3_^3r`rS z-xpFBJC0Wft_2=P9f(p$Rgy{Xx*ykZ#Jyt$&zkm}v16raB*d)$gFMn7jwfTV_~l{~ zIW_@xmx?8~?U`wkXzk$S7d^FTp8A5#(>;vJF08mp(F)ci`Ijp?Idje@vQB+yl~jpb z-H%fBOk$d3SqzOt*K4yyxLZbLaz1H*x`MoI+Y^W5-qg7J`^N-p-m5P}PU>>)0r{pm zpQ`c}l|CoFm1f`6W3@wDuDmlg-T|6+I*<$B<-{QL{Yr4s9Q;;LZl7E!5G2ekTFDU| zpd$*W56;$yIJ^=7CqUT0qcKDYfhgJ6m7LjD*AG59>(pxYcdkl!iPI{!uN0n|ge!c? z)dOmB^(cFMCJAB47aUsrtgva5{hj{gH^ENb=k69iG8#z5Pd|e1^rIm%Fn*>Ykx>7; zC1(`G_&e35H+Fc`x$q3}1tY5t&XZV-A~#ij!xoKeYP5U)1`q+VYP^6TrXeZ}n3`QYNW$|Ijp;_DKTQx=Pq%t1U+NzTlTNVLK1RT9$`vnV)P zIICOzzSO9ezDaYX+ya}`gtQXK@xO9u{#eQaN?i3btcfW?5daE+TD0vEAhpY=S_(Fuh^?TtwZ_(p=;Y3nt{#3wfgx2*TkopR$;iIWkh5!w*S|2l zn@G0Cxm44*Jjp>^E^s4W(dSNAjmjP(b>}|>UmM`DfvgUYE?N$^AQXen-^ABK$Stx) ziam+)zC_sK)zOiVj6$8fi*c|sp3K0iKNTG(s&Xc@mReVXqSMXa}4~v z33NX15sA-i;i^a9zt4Czw$cEfhw z7ghNW%esd%Lv<$`1iM*;+`k>5zmRgeRcTHTEG;)_lS4m9^h~At3O5MFmLiE@_2nO~ z(nrWx#N*`evnrvPP*NF?h8Vs3dEnx8N&a#_3S>d{`^>+@X)JCj7KGoG#z6;QMEN6& zWUA?&OUU>5+RT>Mn&zOokh=#-X8QEDNaSexTYl zlRu4k77e0M_~qU~K+L*KMw*axxtSh3Dc$w8scT30HaYGi9p)3{IMAU$HfM16_unhK z%YtN+Q~JGH%LT6S8R1l*tdko?slLRyp%z4ep2YXjVHii|SB5o8Bn^9yVQb4&+Ob&{ zpw>$ERP7)yK4`dL){O^<(cSsT?W(V}e(S}|JW7G`@n4sUBU7Z34NA`hQ z=<^b61f%}EqbZ%TYdYZ!Mz=eQm4zAh@CAbf3I_N4A20rk!ED7Btu1>^3t_!#LaDXr z!A71my}|=Kw!1GQ1R2J_2*wpnwhi~`R7Omfm<*UO!DSK=(BujHD4%bhE@+$P8= zu(gy{wB(MXZF%qfSK z=bf-ED+WU87r62s4%VC{@j#{s4n-9l=pOJmmCV&=Ko&R2`xsVTr_jpC^Oq0ck`qH_ zi3#(>qd#fsa(8EjP;CWmENlfL|L84x$6K@YQJOCE5Z?Ej6y|*=Ke?U|w-NE3l2cbz zA+Fy&4#ZlVk>kRB%h?x@vX$~~HlHWw%&^KJw{UX~hruV-$a}qL5OYRvr~<1B>+3~{ zH{S2Q&FS;s$#T}^fZT|I3`&0**E?B<(){+eZdlhrXYTD{yvJmQBtWV!h~U~g6+g)B zW`^>^btfZhbQRJunB~ucUSFzJ$xblqn{#z;6(8$7cVpu?IRyiaHsSUFvu4+FfwDa* z70P+1zM7)xvjyaOS>E{Cv1)?3@?9?Id;#9qRiu<)inhkk{6e0v_*BcoaB@?Z+e*UD z7Z#O4Q^*~c-w}m2Y|n--x!EZ{5WdlHUVHFyfC45ntJ#VCV=X05JKJz>Mhwd0gKXZ3*|iLx zHM|ZR5eY(3h}5e|Cltp}FD-$Ho&JbLY;;Qj`WQGbR&UnN%1t$jOrNkmwsm0{0AZ*k z*MYtoMysFn^Ev>Khq*?|740{wq%SA9rC?QkR9N&&GP!qVOmlPQhJhOwGF%k1muXM_dFgMP6uM^4F(&)}VqIGoc%(<>%P zCY8pW7oCc_cFi_rW=0)fe^kiLeV6T)a(aHx=JCeG7fte<3&TJ+onGq5*JaY&#-aF! z{kpsuE!AXP%)$H$W4OIfI;K z=1J_j@zN^9&H_Jt%FLLTw&h>8?WOMlzJbbtVI%%S_H0z@<-W{MdS9SpuYpGOqS+Hq z2VX1LwaqAQYn}Gkd->k=Fv8i-LicAKVAgl$_^4Mi1dTP}WS*-Bcj{GotT1z%l{%2h zyGCr%=Xpw3qs?}h7I-)>qj)g5MocUwb8!A zv>+!}>)HhJaELEh`L<|A^_3{q9g#{tIQ4IwyB34JTU6lnP8^x20f$87UYn2W`Mk%d4tQWKk-dAisUv|e?58uq%nY~Re zeZ0A^z+J%X6u>R#FOcCO+nk#{%!Iz3axSq_D~g@oXI>gke)cRsiM{e?9X;FEGeDv? zfIJWGx$`JoyK;<|Q=6Y=ORVos+Z91ZV+IK`Dko15TSAN;7i_y!qcM>v|49$*&`T6o zPRrS@s>>CyYWwha9On9fXx$P*{SU6vE{6g2?W`jYD}a(&{rfUvRU)>?$2pB{-gO1q ztTgLE5#m-KJYR!MfU~E)Q-*u8O3ew7NLha~JC?`wuOV|x=RV6Oj`sN=!;7XdGZvN$ z2l*Iyb4c$oXXSyv_$l9cDsk*UZz;Xv7mCBs&a_-HiNx?t(=pF|y)+^^xt=ej(TO-r z_q@qxOkCV5%3r@6>YXRYC$;hs>;f+PkTp;h-*<~h9(OY)&IF5=2K46dT+%-f7ffO{ z&P>PRQ;EOb#C;j3o;Mn;)cpu=a$|~o;hnhDhb*S#Vl{m;<69$uS&VF%pj@iWS7sN;0vZ!70CloHXxW{F{Z;Y=*LFHAPJp1;7oA0&U$Su`B z!qOrte)&A2X(LQ2_qEBq^ZYnz7RL;)>S6d?=LoGGq$NPL*Z6nU8p#F%1+_g>IXKKa zaP2y>R`ii%!#To!rzMAI_3$2eu|y@-7wb--h0#1V$QWJQvD_H8ue|dOV;w`5Wv&KO zDS0x=cx^uvtiIR{?Hm&JpQ73tOV9C(u$!|r2{Z?lift94s#oVNBvNVQYk`ZgPLdEN zFPho@<;h-Nz8>M*(R!z}F7XV8d-NIZ9Vv-;a^;3OV#9WYl5OzVx{3GQR=v!)6i{ti z(of`hIP6oOzR%4OYZe-|oHXGxr+KCZ)$AQ;4=Pk~J?K51*70P=Gab*$WJWth$^tpr z*}(8YP%zU`JFlOPExAdlDI2n&xdA&t{Qj^YXK4iefD$}2TSLkyF!tiH`G;H$Khl7* zPkQBe&MNA@ZXnSIbj!tyB+9?>JWF=o+&0YHH;$d53np&ow4F5zahtRW@C3G4sxrz> z@Ww(^X5>o$hy{N=H3uc@t4r?c!0%GwbL5B>b__RoPBe|VH7gXgp5c|9DB%aU4BMr6 zKNGb+3TRsG*9YN38m>(s49aHy)gzpp65Ki|7X>Cud%vrSV-gDD=>64@a7tK%iS+`_ z#4wi76IxfvG=#S{7$`*=IOs@TPebrX3uEVv@+-qTDg<8af=M`4aLAJ zNmKdxc~@Exjwk#Yv&8Z3TH7)xK zdhB~<^U~>3)UF74->9@bj$&ywsz@A09}p1yY|P?qBd1#)53kF%C=>;ecahjZrsrIz zlF06bF-#_)Ion$IlO>+J7Pf(tSL`3=Zz|Jx*Tk_f(E-vqgbCt&_=3ibbee@>*PjUX zd05g1!`=(MmZdTIs!tlm2BX#TS#CjOdx<^FGu2b-TJA=6 zrigLeqsl`}u6Vu)Se_45&I0+JmiA3*^0qHdu^lxKS{VTmfQp?D!iW$up%>5(?-*Em zz3!j_6IboMei!2hA)b^;b_|W4xj}?^e)d9Se-&*a`aoE0lkOi zP+viG`MaN18;n)P&u`w>35cRZvGD6+G3 z{S5Tq^VIh3^zoTE}qlV zfZl^3Ufv@Az@pp(;edrg^hYroyc%-yLqGx0cr2-*okb7$o+wjQkY-K-h!} zb1eHRm&M)|Vc*YvdV7h%->_GfV=CZ&$Ev}8a<=c~??{*1y!=SPe9{9EN|~sf2145G zrxAk4R*F9FVncQ*?X)mEL*sza+UEh4Fu$_~Z(zomvaVA`nrbd%S(|s7>s1#TLb@~u zLOfy-jDSz*j9jT*(FRm0^)Nq9i#y`LOGw24xwX1o98Uh+bm48V&UY^LR6YkN3m@#q z#|ZUzCpZ_9ybsAsO3r9pA(>~X)_klB}e^gCYFL2BiGz!)bjivP#HS+UI zv24J&VGai)*OqbsRI00dvu6gZu6!I%`F061QhUy*pvZf#^*g-WgCS*lQM&ss?@ zvo$_|>NJ!(#^$9z2CembEzAaxNVxvKexE_92bQ$%N z^;Z(^#}D_T5nXc`9QaJv##(7Dam=aKN1k+bRbT?GQ_nbG=O+7E2r4+6%?_f4@0Dl@ zZVnbcIIVzJQHSMCWSJLUM-zZsC2u?_6zrMyY`B8XFZZb>!nT&_))ZtKuK>u{;wMY` zGrs@gXkE`2Auk8B=o71PX@!i^+iN^3f8Ob=`t)()vJPM}P`>vF4 zo|{9XKUF8FGgnXJj!k z`dsN$_)?ZeP;=w98$xQN=k>gv+=IyVmIw5?EgWl8yFb^ApLc3)dII}my>sH|RFl*x zryZZ{mbpX-CgYRNcjXc72DmC3v%toA(e{?hk{l?H68&Y%r5S`a@Ha4?=T9iZhCrts5*iZC7E)v=-oZd^FVYnJy2`Tq^ zzJ380$B3YfR8mmd4&b}t0SEd+at#aOpy2n7;-JSx3nOllsr+9Ih?B;rd?i@}P;PYd zmrJ|5_9Ij6&Urhi-e+uqa+|8a3hnVIg{qAV$PiAaP^2BgoO#{{_N9dN8<9p}p4g05 zx=2t@{QRi-Fh3&lKp{DH&5qb>C)uyzW_cZv*-JYV&U5aC4SHTz{-lDg(<8(XbaOX0szMS zu?wUnQ@|5#<^cxZfn09=D5^# z&Dic>~AVYp93DA+ucseZ#_Bmn7oHT=(G_7xqPRmh~0{icg{Q5!g7X@; ze=?YH`72ymnFxW^vFteknWrA6Sl zqrgL@{r`w?<{VkbK4%>(Hh3aB>Cl?sDO%vfZbs^e?FR_=hvQF(^Xv(W6M#z*$iIEc z4eb%F{TAL zG5^NoDAjI3xWnqGe4r;;(Wu22Pl%;QO|Vf+&cPg@TQs({vRFekyTNGKfHUu!zPhCR zC9(=8POsC1I_`7)&stk;b^aQRKia(0YE9b|cE(0e-GKGXC-0p_nu?t# zaMH|G0~g3{cJE+`os^#t zM^UCjT&oWqItM^eyl~~!Eh;f;xAr`#v1CAay{b?b%>lLZdkWH3Y!>fksc_g9h?`ZTc$Gd8Qd@iNWC!>s<%?vYRb*c`!*CrXR1MIiU) z&|+0>Rf^lLeBO%KZ&w;XVIU9#h?;e|)Hm}UjX2*!BD%?k+Fk?-j1=+sE>P(%rNagU10NItdwQ(YJv~3%+r|8ta zh)q2s&yo9YHd5KY^bdOWHFHsi0nH)4Dh{c*6>nhxMOqDwq9Z=L|8%|DuaQMR^ zmH&bFW9AHOjg|hDW>h(qIb&R<%Cj`B{u#=Zv_x5$Nmz1An;;Tm$hdqPXC-s;?8`;s z$6e-ox>q^d=SGa1$J9N*_k^^pk^*mb=AJu}$=&u417dm^otKeArC+{|0-p9cIt)Rb%WLi**(S#hi+J1iC$@So72Z8!M zi(x}v^$QoZ=Du)Ekd{1j27h7+701nZ0XqjxvngVcidp3UN-Xh&(cQeg)tQ(jiwj$1-^SOb`RG%&=-T@?uc;$Go0jxSlfq=Do5_ik>}mq}s846m1YTHXdRc@) za*&!lviZ)Tf?#d4Ru7rq$x$QvRHjo zIMebNckS0CW~d$&Pg{!K7=zS9j*3bG(wbDeXR2Se-AwmbDmeuvMw;i@+i|PUWSG4- zb!F5WEsO})J$H$QO2Z2w2{Xri_HxY`MFY{Hk)eT{(+94ydD3;>A{i}{x^x#qQ(fRQ*THR|P!Fd|lXq2n(hzyhc4tD=a{Ww7^zUi#G50MFrM#BGj zRWj>^GnRN{z1#xj7T16Is@3W#!GC`V5;F-jl`CEVnX>d6d+&w}4Xy6UX?z>?Ym+5OzDA?Mza+FkwQ^<%>qL@w zhcBp_@5D6*{{FHj7HlX!2w4!e;WOwbHE9>fq)R=d9&QoJyDs7JmQ_(WOaTUGDHcqx zv^jl?1M<25q_#Y~-KE-?eu8~;n1>t5<$U`Uc(eJ`fjt1GVlV|5j86)b;dh~QP4llN z{(6~ov!_I_jZ(zr%H=M$_~nP?SWE#18&)mimj#VoknhO};&GqnI%C528W53WPq%TpbDWKKjevG^4UfOp09Nx#0DHk@x z$u;C($Cl@$GPl5!$R<&wx)!jRCM_GIyeT*9QfgJa76xiz1~+nPx)eh)<~ zgkh>?6V@`5BO7MQ{KvU@$`hXc456u<>2%vdv{8!XoX}+CvIj^lPh3uGc8Wwg8rxTR z^YaRV9L=!(##V!`s*DWe^3gFI%bYJEz5U_F8}@kudF z#QE$cQp=39zo3oK4Uh@ILslIrEukj8zh-O*?!8BtPhQ)&Rt^Y1qMSgHVo491^S3ne zyX7>8*w8X9YSkk)fec+v;`j1!DT8g|x0za}G+F}l63M3hy_zh~6&oqx)Xv1h zLeJPVRk{jji^gP%a^r#(j3qkjM!`pQa4IU2I(f$-`xp8D<(#~kSabY4LmMrNlb(o> zb9%vXsys)04sAN_mE!lM1BIf95~h#MN{B3B9>hQ}n#}9@Mughi0i6@`YS%I*{7I3& zp5gMdUuXKyNhqiA%ohfSfwz$iTX_Exc|M`X*)KU+*b3R>uMTY4<92*ihBb@QBO8&* z=u~L_Y^@nr%bJnA6}AC22fOOsU%KKVXc%k=9q#yTbS6ZuYzV02yWk+EU^V<78}jY{+M-tOC~bqiLTwbz!0r@yxeG)Mlf~ZSwJ>nBAz2u%e=? z5T!AOH*z{*6uS?#69!Hb(z8kmxOn^iJwuAgUD}CM+t+93jD|^!R%Q>i5f_72|Ik{v zdqjb+5fuS5D=aa!7Lh1|1Xd^FHrvddT`;GHG=#Se5mlRXBZ#wTJQas9Y8!KpSOV$P zrkhMlId}?VG%(vJ#W8p%K4JiuY6_i2-H#qKM=N_Jnj;d0Tddj|G)EgGB2&!_$8ML5{HL zA`zs*-CDNLNd6GokeEKzjn~p?iZ^fHj@>JXNu~&1o!U*lJ#>5YmA!v3|`w*Gj(SN3VQre-BQD=U)5Uk`PAjRZT3ZP zT)78f<1l$RoJa2&XA|FQP{=m#2wz@LslZ3K;~Xw_@vzv0j!zI{0zg2Kv4SbxA`r+H zE6yq?999re(l)H6bH+!HvTXCh2x>eV&lc@ss&waeHy)_!v-Am{wIsQwu5;s+;k3gW zb2~)j)`+YOKd#K;o9^BA;C})W^6vM!9etvDtjcC zQ=CbNyS=`89NuN9a?{M4pJj;21qme2m)|b%Y3YSTGM}_-49xM*w)ux=>crwc9eZ;i zU9ZR(3#IgbyXmZRgKe&*m4F8m%#iVdXLe;V8eM`!ixuK$I$l?2fiEeGF!x^xzlsurZ=-Jacc7n?esDshlFpTEm_kAQ?UX0 zQkja*8NbU7nphDb7)LG(eCZdizi2|)@J%w z7;`tQ+38X`&Qm@cu{3F4BcWr&1T!&#OcK+d3q|?cxcv;PDe=6-m2B>tpq;(n`wiLt$#6MkAH;vt|;VFCGT~YiDGF}JLh!hIg$Rud^VgS z>$x-+nE)JHU{?DELCF1CXdJjZmG$N0JH8_(1eHd4pL)zqP?;FbFPc)O-!fG%ORpmo z&AzBma{`#H#7iY2k;X{_>>#G0nUqE6Iw|kgc{FCw0t$@qrAtR=h!dYO>2n0^Gb09E zFx)JfC*X%`9(xETSnQg%` z=t1F`Jv}F@g80$(PKFtI+9H)r?yhQ}P;f@GEi7}W)6_k)kVCH(PfD+DXL8aT0!cz4 ziIWK}^xm^>U4d-!%NOn}p}Ql| zk{Trkf`qbaLU(@K676X|)p*rRfp6-WI{pj{_M!p<`?nlz#9{NWI7WA|ch^doyvRx9 zc&EE>PUCXI6V?6IFmf4QH4W%!F;9k#3|u6cr{?cF-1ZW{KX>$ec0UQ1_66BUOZt^LI~vv&64 z60Jm{@bTf%fPpa_~mwai`4NS<-QbjC#4sutlR)zOr%# zxD~jwFdPwcdct!#sdsKF1vl8zG*89kBWQ1%TdHaXZ}71=l!Mk$_Apo)BSfO9(F4=D zTVxagk@ly62t~jfLC}WR7c8aq4X9L!0{sm?3EU-}(B^6n6?bys&y;#VB#iDDIaoIk zUR|DtBp}n?^{#T?c_|5Q;q?W}Xua!Vb9q;-+LAMM{1G%h^w~A|RV5_M`ZMjV;S)DX zswz^_g=s=2?kN_nQ$(GLbwi(*?{hjdEZk3$k&;R*BmS_5S5m;qWNAjJB1SmtE zlqL&`S{UoS(AGs-C32Iq=bL+)M%z5gW^C>cc3&0!&`pio=HSY`e;a&Ua$gao?kOp3 zCp$6^FTWz_o-Muxd!MC>>zN_SX%MghYH?T<|GbbuC7B|YxDQ({3rw*gq0qY9qsU=X zszpwcD%4U&es4QUUxjBu2W5TqXktt;O!e4g(M3l$gqhX{`BW=2W8cjAXP+wP&|9Jt zQK|#F_TYVJ2sArgm*lk_45BfMFB})67NB{xhr&=k?=S9m0imT%HwSawykLq%zj3tO=+Ld3z!4C(C}+fB4_nYn>y*%xT1Wti8><1&2XSJrzP6IuS(e(}PPE z1h664B2~XA_~i(dmPiMpO1D~=@1@19DoU98{sO}@S#dTdO}rAm z2w6FHA;vhq()qMkGJWCoO*&whORG4$v|7u6wq3NB7tOsaXzOJ`oD0bZJLMJ@h23AL z-aje>CN?GG-IZOmCMvdut`k(|OkED~MDijfhQXy;A68;MN2HZ_-OVt5pVLMGOzPh@#crkAm}6d=7iPQOGW&5f^O|M`@V% zi9E(=l1B>N1wmMW!<;}cA%quHw1)hCD+-KNUZe5~&F-vZGJ!Y875HWtkkywEsbs=*D$*5> zj)!9jtSp}~7`PW*sf02i=+nbj8*$_SDz0fcfp!`)M(C-aqT^f=PRNdM1CNmzSJE5@ z?>Ec{L_~(3yE>|@*;(`1cR3YtplS*9mTVxz$%mE_*y*TA&4f@MG?ky(gBd%5tL9LV z)APohs+h^35&TiPzFP><45%0yFiNE*|9NLZ5gR^v;TW7Hdi1-PdmLe}Rr7CL_cZK$ z0-EUEMt?T1dqRlE*kmEym}3Hb4i#BZT}`L>R7j!o=S}Fb8rN>L460 zwh`sWRsLx_Ma85IP|O`HBz_r+@fCsy4^tp4&F*f1L}YUKf@Q|?McE#I%PaLaQ@fjoFEUfa)eD^z~@ejiDoi2X5GzWDRiRn zo#@|!f{laDSqSXZZGC*q1&EhIkyG@HEX}5PQ%sC$|5AIMh+B1V z0-VW!(_LY+H@;*=benybj8&GzsxEDTP}Y2ls6`spIC`Aibv}Sl96Mb!H zgHbBJU-aWIF1E={b)M?c@&4`H$p5yZZRpS2V$=0&q?-M0yPslrUOw8<9HtEuJ3+sM zxJW9d6g(QU03H?Pon4eV2fYj%hD)ZfvM*bXS#G(GQ6*&h(j&!=l>sF3 zz~ZkQ?1gfQ-JW5Z?vcH$;rl*L`q;{AbnafMeC;QpZMk_`#})GS_Y#C?V!ocYvc`zJ zxA9+ogH1+ZqUE1ITl!^rKd^Bl7y1X-Swa{Z#`H6a%Smzyd4|Ltg^fobOA$yMYD%=t z3yY9uXTfQ+##f@L<0-`cEA^VliQBVbC^#(ub##~Ga)?ZZ(xC|FlH3_gdd=c2(gDKx z$ZJ&$>U}DqWStm}f^{8&sabytZ%09)P;@2|UH~QTTqhjON!O(L#}qOL@g?6Y5QF#g zypN$04{x-6!(WahA~ikc%}bkY5VVnIiVjP8!7YtGdFmd2JQS!|5c2-p^87P2n&$qV zMgQ_X;YDw2bIC$QPR(DA<9(e;1OG=(+X}>1<1w3jPu*gRd5D8(fjdvxEs&noidUS4 zwUL&eU?MJ{X<*G%#hLvORE@_i6fdP}d(^{=VfJHx-Ei`)n7$+w?#FU7Ae=FN{O;|Y zsax8|PuR2lOX}A4v4+&v&hFF}Z=aI#&aTiB0Pb5T>;|*G3?0@x(jV{0I09$gPfQWP`Pcs(Nt<=YMpG8)p99XT=c+W zB$qliELbk7P-ztZN;H&*6ta{^R|7T6n5(V+dv$3KKqOqJQP4dmXq6I#i_0g8a?mM_ zbmA1*sx31Y2$;VK_|q7|8}tALO5kPeyn!LZ#O-u^BfHlGI$sIsnP`^XYungY&l# z$muNRESB(7Occ|mHJ%6DnPK)xVPKSctTVV`31w=Haq$%WU;+(%Dk=pMD3ehbUEXfC zWO_7DKZQ3G;EPH9z;bl`oW?5X{D|Wm$+GCD9Q$8A{BDMDr12ZFKeE}5-O`A*hyt)F z;OM~wV8RsbZ2ZDA_oP0;5e1g5NU|Xk#$hJ{;_aZ^xcxf&a}e1)x_pi}gB1K#GJs-lfN`z)~o z)4no6F}@^7gpPI;DtVe%TBWG5*hv=g&G3R6iYeTmlrJxO1Llem{8+wC9^siQw=H9e z=ZJ!Jh5GTDo?n9^6XdO`QkyeNmuQ;eF~pAl!2(GGQJFHUcbRLRyqs>cxPK*MoFGgV zDX~nS@B_NFmU)uA_pFGr#iC9{i%UL077C*U9dO6te4N7>70%A^HNWJU%rzwegfwZ! z@7+qc2gEUE#wjv;KloHw7K_xSlNMF&=9r?zNz#P>W+dDn6qjtO>*o7t6Hd!`{5H`x znIb1(HC+}G&2nX5COQHFFsT67t7poI_hDy6I8vAKgbd4NQ&38gU#5s_i}Dr4uG%im z8ebaj6tr-?y)NkI^SK8_nX9I*dDnT!c_44NYErg$q*tKD#oety>r|@Vm$!b=X=8uO z2BD>)J$`{20)O9|a^S>nT}h(mE=0nP(-atvTnX)*MNp9hAe zMS33gsDTp=Bm@RiQoWFX#ikGtIOIc)D^=A(!CxNXgT=z!xj2pqRIn9GrJUdWir;aB zeO2LmGf)*2+CRsy@2hF%4VW{JAC7fbFczP1*_ChvT-PfwYB?`4B9g{QCF5i;TmFn^fk0E-xMWgaAA2g^jsa_oXKrN4Gc3G~nS&knUI4qzBY3hXUv<&= zGy96NK8teoy{{jW2ohwNOzJRs!oo>Tf^zTz+AAPG%4spXgnTp+l*qX;az!+kt5e9` zQNl*|wo7H%<)pY9H^CExz^tx6{GK9(RxrO83t9vp#FpStiwF)vW7wda4fvD7O<;)d ze=*e%DQZQw{%NVq?=sq0tvzJofv)SlqYwFt&plvEX%jVe?cl)!H+l~);x9S}#CDIQ zeFq*@zUwA~4Wh;^^m;xEc_Q|m(<(o)ZH*x5hx`eR=H?$(Y<4*tvQY~OcSbJg8s#Xi z(APG8HV3LkI0J@e5Ir%w#X7O?r3+t%up*ZPP1g`wx&KWLE{`sKT97ZfDr?lwRs>#_ zTVqqY>u**P23-$R#WEU+(l-h`@nITPJa-(6?eeP$C(6qMkM|oo`#qi}Nk%Cg1sCnh z8lzO?@E=64wDuB@A8-gPlOYs^JKLNst|K5runOey~3L<|h5W zEBHN_=-Al_n%@)qQd)%P-w*V=|=y*LM85PC9v~2 zyoFNmV5ZR#IQ-(5|9O=u!*JU?oZ2Jxc>P!!xNtQwB{EE_u$f#`+CY<+LRgSB9np!i zpg9z@d2+8mx&_$)({|OVLs9(OT+wa@<-*8g2@nVmUTetoSzfy0eJs^$r~3U4t$vYZ zE!&Q{bkB8}R*7#6KN7$teV@7H^jmqgev;%fUu^yTMqK9^y=sS&plMZYL1d})0aZNv z4QmMtM6hpp2wk!o1FozSE!rE|1YG+TEibdxxu@Jb>7{v%IdG%DuME?^z^m+Nlm{y0$9+#Wo7nEL-8a6gCHKh+xptDoP z{3GNRD06EHPJ_fYq{oLy!gzzi5SRC@8H??I$G1$M&f;*1R1Zpw(=jM<9Q1o?K}t%i zw+Zu5u0qGz`}kE+$*H+mSezJzx*#)(2P31!gEI49803hjsp0(WYH`+N2tAhbn!|d< zVg1MAoK{2;<||Xx<4T!us9OoaBSSa-2^}vTfZ!*N#Zj*=xT^Ie&Y|EgO~3D|HmoJW z%!p;Nnq8A0_J)}rVr`+)Bxynx@Utunv(0>f7^pGL|DVK*J~fYnOM?Ea4jqI`du=w` zviuy|DqARqW^$%Yk{XBM+=gF-V=2kz4BfaFWNgWNJZ`TdMKf{64vxBr3kan_Fc|L6 zjPP_f##{mbJV3+0o<<;F8@lH9uYvQL&HBY={l{jX2Jqhgjb6-5%lf%yr-nRW0w0p& zcG&Wi5rhR^sxX-19@|;h_ndBsjbLnc!)}jf|3f!=ZCdk-ekuF$)QVaQ_9tVU!3&W| zk;78vm&OoGgecFtzhCTTTXv(jesj91?|zeh;IbR0=QKBvQ9breB^z@eNYb*b()aB!LKg zw@J$?E%0Jz?!6_khuEy~RVo30&X@=vmq257w$r^zEOZ8XphOa*_Zx!qg)~B(mO!OWMmmQ;Yy)hycUX|?Xw%9Ju$sx(Mmjsqe5Suq zS;s^(nYNz~9Jqo&lWR>IsRiZu^mC0d8dWYd?-;$CW|0gN_Ss{S<96Xd(M?PG#W|RN zgMqhp1FqX#9@iImRpdz#rOOWU=PaKi9?qT1;XjLtd6-w|a`2scp6}rPj2=xOc-RUA zabiakd632IAerxRJV=o$;B?$sRn9P9l`KRo%=PzHp98>mbO!;DF znaPPv$vt`U#L47bq+3jI*g}8K%V9C=m~+DX+H3t7G9P<-27MUqJ{goq)q880CG0$i zO8R$=#msKHfbwf^VXPfC|7vrWsTXZ<__C)G+uHeyHsPqxS*RLSLu<993It|8u_)iwFhJhy>5sZKfPkhNDr={1SN&lyNZuIqZ zK@zV{cc4%FS=f9kW!?Qp75! zKonBgG)@;rnaZLUL4FoRRinxkK zudKb8_nwTu|1s?GKfcd#geJe&x8NOcMlv-k%71>I?>8*2SG9HfE2ZKKvK6PD%V2U2 z^;P4lfO81`uE77}I)5fg@&N<6-;z{A`EZGN-V=!!yC5vQ@bbYC8Gg*ShLig_mrQg; zTgxK(Z3kC^-Y!9)SqzD%SWGD)C1JhTa7ZFF0a)@?d84LL)oxTverc+%*HQbcT5~+z z4UvV2LPi7#nYXCsBe~HKa1UCP55Sy#6tstr&(dAmbJD1tOQ2$ctUXxnJvmLAz4Xe{ z4;JQIN*BcVA)~Ur50VF0ng{{dYgEnO9`Xk$3=$er*UiOmvY*Po{^uRLCa-6e!IU`d zr_rBmW*pY?k3hxpJybG)0o7_ z05%d4j6kBH^<Egj6>zh)$b#$ThFWF}~t)WXsk3LL@OS;}iCsdO< zlxM1V)IwP5UpN${dBJDvAtt@BxUR6XQdUOF4p|9IYG&!l=9RKb&@bEHWAjNEQh)uK zh_lk?{iz$YBlcFdjNB7DDAISS^bGn-&*C-Sb4zYsZmAHQdJF!z%sm!UkAoHKuC#A> z^z|32DZ|&FB+ogwGWk^fxJr}W4EmN@w zhg2Y^GLU;m!|VuhGMUi0%rnPSY)vdYSg!q-{EN5&kAulr!9Y7w1tVT$&QnU{)lvmz z7zV>42v|f30*c30`?cfXvRr={`poDYmD)n!@--QwLn0$NFy&GS#^*<_8o}fk-zHU>O3s zqsu&!`x6GS!zJwDqgP0{-l#R{on`{TvsPX_0ZPF)MXon7oy_G#V?avabamIZjIY;a3#`5_uz$;o1b7wauE>%pBTm% zQitFRiLhWuBX>?X%cFQkq@CU{gdYh5d*z@o;t0wzH~t$3ZYRR5&{#6DXc_HDMg zRaQ&Kh+F}>n8t97c(e_^hC%Fd0s(*#78B7hfXN%?dsKX1v7-*iuhhAJnOuABb<#eM zo}b=YLi(AILP?VSLghauk(Vx+Oe>KzIG3Il| zeI!>?a{CxsZ9WCcrXONlHL|;tPh9LB8WmejH{Hq4pcVMiXe$&mFvM*YDU&E;Do;W& zEyPOP@X3%Nmp=+?>|ciePn#QQraR=U60#7c$*;s>FL|HGpyW%Vh0^>?!Xy!D2LO4V(_96}x2})pZ>wA*aP{!DHexBoyO+ zfJfR5A1Or`(5&4>Z0t4Om?jG8*cCJx;N6qK+KQ`sF*YIfCUO{=(MlkvGf2fx(I?@^ zUl>F`5>-jLsq+58qb8t93OACkCk%sU9;b-W9!mp#0ocs;`JRv@qB3jokuqpT5yo>` z(Ai>V#aTE>;`Ml5)lj@do0)#u3m{tyx$5a-QRJtorh6L0)+iL|X=yy>D9c~iLK7fy zwRV;RO;gQCi1Ms;FjG)8RjP#r@7B37u3BBmEHZjOR(K)wDhcDq-NnL!{c3+S`#zJp z>lWZe!Mou87zC7Y<;)9?$Q6!;H);Oovr1T`gJBLTo)wEnk{J3?&+70@7z_c$ci}L* z;WPkfTCiVGF&d8G%o|T;@SzA;=hOI1DrGMjzTJ?@Ml=qEJmx zqV~5$#z!9%NGRjFve$(=(yx)B$rEbv8uEBiqn<0wi@)CnkM3dr=jb0Y#ecpQN$!E2&D4PyQ5F+l2+&Ttq zELk)f5=z{JLjHxI13=T_(mtIp=OOPQ6K_y;My3Srbyfjq;0YMQ=YWrb@xttvA^Uk0-jilq8P%f~ zWDa`gtYzS!_v|NGZshoa*0aDgl{#O6(J-WBZ?_A79`nhi*MPY0J}NCA5sW`w|LD#32aWLLWvv$ck~k* zXcz>fq>hH>ZCU1l#iYz0G0*lP!Y1OqKd+JGx1wPZ;cM>^2V)$~!i`xo7K7inLh(tx z`>n-q*~oW>o;U(EKE_rr*&GxiRn}nQ8S%_O7RH0!L|6s8RY$`_=90$6B9VdWT0>5`R1H|GCiMAQLMOa(^LL!S8{KQ(1}Z*?;VJ{>!A+kz8V}IP3ue z1>{c0$d(Xl!adIp?Iu&{&!pUFy(P-1nwJQ>hCsB+CbVq;=2jOq9*#oqZ?aK<*NU|O zievc}%ZOvAC}Vg4YXK z@MJOp#}f(wP@!U?0|TRDHW4p#-1&TW&Sjus7Xq6Nr5)DaBj1I1APFl)-2UQwcl|(i zy=e1CK3u>e%S!jusZ{`U#INs@@a^SLs!~V-b zNGN17h4r`r+^?)*W+eX4`Yg>9;T*@W2PgMT>O z%K_F0_WULcCC4&1I1OkVisuDiHu>`=%f+F>e9pU*@Buqd?u7c43 zc1ivdI|uuA62zk6nCqihf=9|etbegYD~munB{K7BS{#uNMf}CO~A-ZH`U3}j7=f|F|(mHze(aq)w>@WmTAsqg8#>Lr;+CvgPAbNm4w{m)8neSr^bYI^@X z`gP5xhQgXST*b|Kox%NI@~Q(6YbNflEB=zv+Q`0Kx^^z%?_!)RC{!kIH!GJN-oQ@% z|L*)e>IQ^U9t`d#7`Df(F}~7mO%yeV#PuRkk5Jt3kq9A(Lb5(?k5E@x^&=;2h>WFWY1QdowNlTi%W~2uZN6;s<$fK{>Dw}ktKT>ig zr<+nnb{MT%z5)2>jMIYf)0eZMsXb1KsYziN{F2$t!~gFc4k$R7cTgxFWos_qAYm(3 z*4sD38@<7%)hco*0uqrbd|3SHCOdOtoGeK;CFCTE#F#>~$B}ch_0rf~#8`&X7Lm@g zCrTt1XeP4`+j9S+GUH5ZD?wE7&!;it5$k{b7~o?4`O%Aw;qlqVTbtZyg(xsn470#z zEmiTNMda+L=v4b!KKxPmVwcU%M0)y|F{s}%8kPKOLVRn{hbxHd`O-*Rcs3U(oA%NJha z7CyZHptJ{zPn!GAR8`3Rb?gHZW|{%b@x94^=}sktlWRz!^M9=FpgGpf`SE?CtlR3r zxpjC-fAaWApg7lfzun!HvSwaAH(~w6lCPdjA(9Slp4i^Chr=Yq5m4dur4<}20G{Zt zE4(|{GAlZ8wk%FYm<-KABp{a^OZyK~#4ky@2T7sk*7Of#^9s;~=mIB`*@Bvjc<4A@ z^KLUh=7;fB>DlvyPljyT@}I>+379N6NSUN5^~eeqxV?VErA<6`WauKO!cp&@K67k* zvUS(@Up!bGLd{e@pYen@+YPi$R%|V>v2d1%#t_>)zx}t+Ec)}o`9~-BO}mSH62z8G zOIm@iDi8EiyWZ+=EfFxdFgz2NH((?oZ5Mc-7&<_g4+Zx3~hy(99m zAMS|69Y0=qjy(5BkJE!V{XhDxIr_tTa5$2b(Wv|OC4gx=f6c>w8#!QdQH5CSW-U7| zG}OlD?v}%T{jiD25~!(haAYOP$o=V?NB_JgsrBtW8eOtL$R}g#XdqMk@3NZr=Z6Yv z{#eYR8tz(5sDaOFg#4#So~z3y`E25wpriT>Dl}R>vti23#Q%O%g=5*Ahlcl5&?XyD zM@R!rk$0y*mq4=#{{7(uU!zpQ>iLPI+Qjl>Kt(`KOGT7X$MB*k1y^>8a8k~lCC~O1 zCr=$^6^y=A`~>9JByS?gi$t^xZK|3B9T*WaN#{xAl!c4Ii>F7$+yoZ^lJ*zpBF5no z4Z_=p5B1&Ws6BD*?74)9e$4pRND6>>jYDF*!>ruDH5*ny#=_t&2y*Y3heGxa=GF1P zGnj?GVtPK4?5ZGC0`T%RjO3>eH_3mSA%VhJ!))9I8pBpnZEhr%J_2537G7QMT3|L2 z(b=6dgNB*By;ky1m zA_YaF_CGgX`l-D&;>Y%bHPA-O%Z5`FBOTvvJdXc&b|wLUL_7qE00I6;tlSl+;N-2}C+(X+x5{c+aXXp;Xi*Czji{X49FofEy&bQ zLNfX>_IKI^2ERQRau*eY6DqADD0c2?=o=+*iI=!5)AFyP7AX8%a4IQPSfhw;tQLi7 z`3oVA`DYMHEj};=Q>S*h`XFeo-W;ng?!X4DiO9MpW~;E@msH@63_l7{Dh_W6GP_2! zs(*cJy{>vc>)-j^m-2i#K=>X^6M`Z$wcDtDOb12=CM$82lKjm>W;=|VC9Pj@o z&H1W=LnwZHl}7Q;wnq8UdqQ>caQl#1Es=Mw+Ld?ybgGim+x?CeaS*NighLT?`9=Op z#=gCRU>Av2_SZ8-E=x)EKlio+5q(}AyiC8^vWp^kn%R!1eL;gvpeIZ5Rqk5a!kSbj zpC5^tU6&Ju_EtFsTZ=gYqetXAjEx<8K@*;?{)4Tl_}}Ovj^pp{FPS=+GVpJH&&g}z zI98MuE;Ev2CP8kcXJn&*5h=&F^qalsHT@nj=ZryUk$0>~z&ST44^hN1-?E{2tWvZ6p+*pZU(o=V8+ZPq2Fz5s`>!0o4$mrK4xqyXHB(k|U- zBxUS>aw|C<1QDE>l-{_BBM^jAQG$q=xaZwfog2VNq4KgKeH>1nxHwNM&M}x2;=&t` zMtk%Tx7aZdHvLhk$=E;&IA@HY?HL3)efxOCrM*aAAxz5H7jo;UKnyGBD7xncE?g$K zaGB6nV%5K_t@u0NtF2Ie_`Yu?wYgR8Ighr1L;Bc#D+HD0j`a|rMjPUny^D*IqsifhN}zTUJY9s*^z!qTu}vcIta;EHfB|uZl903{eYT8-co;XCK3mL9W@r zbX~KXX=(LE-IQiq94S+*zQ`(k6_6|cv#6{5=OQS-z)ZF^U0V1Gh^h=+rwTIjqDcAf zHOx_ZPj@MTTan-AvHKXQ0_5sTk&4M4*D6%cI@hHEk?FT{2L|Lgd+?!HkxZ4=^y~I; zAoTPY^ovJGanx=$3v;vIEgl=cNk_Cy)f!N!o+%c=fXHP3MS#c*2W0^dhInr9$a$*G znfweE1l6pD!u_ahgj!$r&M}yS!sk z5#iOlNCi~X8XI2j(`~J(L~9ByzC0dkG49;R#QUwXL~9EzzM@6Aoxyn*Gdv=*wX}pt zp~==}RI_tW7&lw;6Pr57CVhrn*mU)hwRJ%AaxKLN#%(RBd8`$B!egyaE7?1WHG~Mf zv23Q0a$~Nc$)-+zTBGk^tWA$(DM;fsPw8zS_qy`R8)C?(Z>oFKPF zSa*|4|7LwrX^Vz=2w#ZFC8V@;7L{722W;0eHQ~J@TSXCpt4rE>{~1g_F?13nPg0zj zYRxgu&{~jRDKVd!NX2B4MJf2mV8V;2y{VnG1N4-vq%WtSchf~k?NLz8D70iIqNQs} zK5LkvkS;l#BJ)J1rG?U;54yzZrN3$rz-Stn;c4Qo^>no3H;L4Qc^~ zzsr71Q_+Rigu3a>QWoJ!G7X+dKeo0Cd*KxbCU#84ZOrvUblS=5bCEmYiDeQ~qJEi*XO4tSYD60pIlMKVlJ?fI#rnB=id(j;^jrn+fUKZQN(NxRWr^l*!J7xEj zG^ZgI9~hO0jdKIf8EoU9z6`mYY&(nM7}pvF$_?aDd8QwW9vvW2ZSxLi7hk5{z|9t0FO#KeKT*bA9|qIJ~tOWT_5bj zt6Lt<_R3ekkr?*3tZvOYmsiO-2Ul%52UcmNBqUD{GS9=?ta(QsVJ^tz)OysH_`aSe zgID$jY&|%@=FE1!#m=(XH72C?)^?YT|8GiH>x&uof(M3Umft}54M1l zSAgK|;Y3gx?MH8fXhnZ-9dqo-?(cW z?SvrBfw*VxQXJU%cymrc!f?~L)NyuqT|CwAgAwoonXzb4)y>ZTk2uyuzk(}vPtxQL z&g5q9DzI;fvB7FkL)%aTahcurxz$ ziSHbR#pdaDd93>Vc6qJ&q21a$XKSfSKNMo}rlVVO{fSim&+if65yBj%$R9{&c)fz> z$zG-FjFOq%_|wT!r$Q^)ThKL9pViil9sdz$s(o{;60Ie)_zHMBX~E$mDZ%$EJ-c%STCyw*TM!B~CFFI%mH9N1l&8ZBvu)LJMDU?6eW6q6lPnsw54Qrm1 zdNH&8--J~-;Hj;+NLtFX_6kOj+^ zCbR|XfRb0QaW}7A9X_*bhtKTaEZ?y`JKwWYZ@zC`b#>h3*Z;~eJC2)-^KBKJX+SUk zBPPAXVZk?cfY&#`%N*e2h$)S-HC79|W4C>Wtff(tb4fEl${dS-N4%!VT(JSZkr`#ASGP;A=c9Qo zoP}1j>E2Vxt{qi32!Y|68&CIKUWs`U2a191d)INRgUI zdZpb9+u3!O!9#^BFw{5)i*U?|hys19871K$of&7|);x04wWMtT#{SW!a(j9ate(Th zo7yIAqfLwV^bN+UQ9$GE6{Nx4*|L1aQYhafsSmdj{s#fQX>v@6-~!GxuB<*vF1w)+ zJyd)BVJV)ltsN9}bGy{EZiTfSDy(_3lmxprpriNk6YIETaosqgmPfhBDYH5nFtay> zJw)bkaIoEVPw``)c397L`@g?zhxe2n3#6Uz4Q$Gb={kF!Oq)b(5{U#z??g}h-K)m#DT^sshF87pc{cK%Q|q+yUfm{CwfpFh zosxH=8|^+adx$uZ|4t0*h#-zK^w7NSY*2CB3@h7J+oMG-HW66UIZdC*Ux@fom#&Q| zRC^UVpB$ZVq^PCjGPda!%bB6u_E=Uf-qvPEH{q%s&pee)W&Si{BE58#Ggczo#09n{ z+fu5mu)N&>=w=fXH-wGI;J6+*eQZb)O*q6lP8I21ZPN7hiq#Qo2u`h#=HaH;Drq%P z#7c3!^xJVbV#OHNK~^r?^to{F3z5y9xDu`k+$3Sep|uXPCrPtpAvNs57-Ho5ZAz?b z!8`W`fy^VwIEIj&CJ;o&k%}Hx?<21+M<^jQ`kE791rpg=*(*Ne6f;>9iS(UJNe# zt%jSrh>R6rU|Q0q%#N}!r|3_9i0=oGM6V6`MZ zIo3mBDx==@icw*|QtvUmCI!lz&S(BM!GB@lzvwBM(Ti7YvLmS)`hAYYWJ8b74-n{C z6Q~-hK9dcr_=L?aCHa$2Kzep+a?5Rok)UzGD6pE%CLOud6tG7&9}Fy}5?+p>I5|Cq zE$#>cpszn;9V{_8ndvs~Dg%>y;T38|fz1;P$pB9!ou1)--vW}&8>95u502B2TWGsZf&fHTdTNrCs^ z$-Rkkf6}gLrk&xp zidPUYkNrTlY!WY+1TOl{o^NiGm#30BIV!W;{4QH`*M5AMV-Eh}GQB<=Q9vo3++Ef3 zRnP`RIkH0Zv6B>V zF$ZKFT)>&+D~0Uk=Mo}1wqIlr!PCn<@a@n#ku&7B8BQbzvN6Q-&@W`vR=%%S2_Ql$E{l-4W1~L&AVSaz7y}>0|zlwVN;8N zH*Lu&rz2v+^=sdXK(g-GJgoWmkolKa$ltCa&YOx^7W}<8@jOz)>#avJ8hzh02{Ocf zQ?#OTx^t`(?!Zpdzh&m@FT8uO{uZoE-;m`!F7W|0)YnxOrcZAnL;q)X0_k&xkX^uJ zKN)Mkez@~@W1-T@tT(7-QguW1%g8pCvCAOQPbp|-tm?nN$`F^Ea{F)3Q+Y}kuGuiL zykE^!jIQJtfX#ZZUeU|W{b}rmnbpVoN=agAzao|m?uuhSNQ)iokjHJUZdCal{ zSoi_!Q)A#ye=0?MXBazn+zjDQGtAFy{8Ccra8%Mlx>v8v*Pq_8+64+$W3MG!+d(cb zDpzLYU7I!iY5O;11I#L805w@FuuyW{fj@ujQB(I}oh#D=2-tYP|M-S_pKkamcw#&S zexEc#y;PrmelGAjX7T?!RiF0E|CQ_YwjSu6*AJ7YanYB1n{WJMKK6L!X$ha2DF5T1 z?qVn0%}hOI-&cJa09DrZL)|uFXbvxIZZmZ5?{Z*{>mB~zV@5{9$Z@H0pLdP|&+;oB z=8ea^Ly;Mk>4V=eYe46`v3peNu&6_m&S{yemPzI{sZuvmpcF5@P6KlO}{gw@EJbww><#5zU}vo z9|KVJ_Fd0c$LaAk$ayf``3C`zPy1)qLxA_YAQpGPl+Qm0Xa)(T{Y)$sG`Aih6_JVh zKA|{!kx9bp_+BKU)k!sw2zE<*?#7V{I@*906;X|b?yVVBYjk&2p3rZ1BXx*zny?T; zPQK6Uw&;BEjy@@J*jYA~#hLo}@qN%1d6G1%~Pt2M;XJb2A zm}ICas||B$>h>d4%33iIFf)u&Sy~O?10VItzy~#`F*PiQs+LVu)rhJwg{x?anz-mj zs^QOv4Y$Js9za4jFVuz%8qCwdzA*3-FAeU9CnWFzA4YH9$M2BCFZ^nUI8qH`w4$|b z;?OYQ-Egx2H^b?KZ5TH4EcPY&l6%sc#%o`d$bzh7y!N($d#a|cdcOtt_5SRm`_dEl zabN33ygnyL<;+jh3wDy?`P~2$b*5q3PsxJ!Mdn51iv75UWsW3^Z~Cnj007XG zrkL^8#tGK}2OP6H8^KjwJwE>KN9dKsz8kDaIPXa3A==V%iRp4kh8e3p!-&)C-0MYEQL3PNj{>06#*+K_7svN19Bt_NtW_Dw5I8r zmJ$7g{>5y$oJr|WGfgQ{7$Wxh$5WaloGOUb@9FZ88i^Ow|)BKw> zg^mXrVHV|-29%pr>a&!*@nvHlltx-9q@Ef@ zi6udca$c`Tpa*NDprSOeQhgdtzo7anz982Mxgz;mwvF?pOL)DqJ5Oed$9( zS$6h4Rs-1?*7QDu6{P@tBzOwmF4Q87SYqj;mU*V$%XItaz0TM-D)`dEewpL2AGcAM zy|%kND(E)T`uhdY&zil2a@DK*D$hLHxy2eLZA8yo*N69&gEJ##TgYJO^E#k=^2&}( zlzl!m{2#f!jH&7}2FITq-vV3vYio7yt1jwix3PPRs-eAN=t{ficn%!v`HDx3yboM+ z7FAdHe=Qh)#b$l>kh@2S3?E!WO%q1`eE2@vU4e5B%bqwhw(XK!Q=jJ%yI&lR>zC&W zLpt<)VMvFb1Bff}c>oc_nFnJBtHJl9oxySlqgk(GP=FFk7`C1)juETPtU&+D7+HiXsm%C;eBS)vb}M`6!>eKy>3_=1pgKJ-x+zMQK+PD3}Z3f5U8R1f)-bmA=+%21M;%GUE+q%Sx z0c`>%9-qeT8jXK!ZU((XbSc@hc&@eXZ6k_b!hCoq$(zM1nNVlry^skE=f!dthoCO? z^>rbV>T3T~FrTKD&-(d{O-;&)qjAxA($qQTN>Uzib`S}UXAsqyb z_B5eX{KjQq57dVv5W(r%bCkm z zRlEWx8}R)oipp}Ucr4Hs=5D%7GQ~^6^@#OW3@%5khrRU4$m30)l3|2p8A|T8H`=(& zgtU0`OJ9(c+!JIa_W~JYkPSJy-NkfyM&8P{Kx&L-V(u)_)Th^LDQ<_m_N4^erW)jh zjB0RN_|AC|E!*re?7B}f?9RTfu&k$XX_NeZTg4LQb=R`fD}7it;H+#cDIb)S`3x%~ zt)MBb1vJoDc{~f5qI_<~o*Hzrlowm? zT{>Z5VSFC!YMui-%MSvEs7Y;(LzhbQEu~48opBg;=4VAz_Y`PoYcH=&6#FB*|Ix}tgg$e7Vp5Gg>iQ`#`UE@rV%b(b?3Eb zjN*BfWu2&MVxpK<_R`b_7ymyts+OJ4ETS@ZD!JybCwJxNqEZN?I#~XRQ3u%jCv#vh zwux=M1OX|bQ4ur|+bVS+fKbGfdJ?;8Kex7jD5B6`XV$E{FZciUz?;9*@2bD|UTQ1> z@At&y5Sc(GkO}@SY-2))mQ8UquSE_o>zvvtuXz@Ef^%vq7I1Nmw;?@@(^FE)u+up*HZK>RPPBEeplcg$PSV&lvVjJ=2U=-F58IMWL(@tW^woi{<4lJV6wW&7tk zj3d7!|0=1BE;C&C*{%_C{=9t^XNA8yR?EsvbelcnIi})-9JY%h^}VJtZT(d|es@Ly zX&T(6Vru6%>iK}-O1Zi;D*x4he9A`EQv@1%T{*AQ62j46IyMW=R0k1y!8A)Eg<-*8 z@k`vba5|S#>=sxQWzI90B%YnH2DG){#dG$jApPDZ=*#`a7r-Oi^1)L%N_DdbxWVdd ziUV&XTMq^nuFTwP44`pWfYW6H@7>@$DYkG_PGw~U{njQFkt8Q}TY5N2X;KyAbEY5% z$y<`bh#|VJcXXI z!vib)cy=T)^+)a;Q37>fza!XZfm#du@qz}}t#*W?sce6zFLpSLaL+x-vRbacYZwZn zpLZb3_P5`6JZm8PK%+p2pq{pKl!C!{wENoame>(a$m=)~5e;jTGovSi#jPRD9RFz7UKhX`eR!9CMk%MCzG#1P+$N^K-p$70}TGD`E^oulL7IYyQ#-oL~8n=DT6Hs z5&}mQ14IDRb#!d_5dv`%q)O^okkt{<%lgqnH{f1ECc?{nud%TNo7ZNeD3x_fs|aGM z8kI;jB|K@0As^@-Mao?HgzhyTBz@3g-}&Uo0#xT%3GH~e>hdp_>LDxh^!4|cJ!Wa; z9fA;gmT%lG45!8~g zJsf2}Oz;}%nIk&g)q&x?;&JZtpQXj$vmDw%3d80_T1I&ghQRfTWBBFxCqfs1 z&0qStkFyhc3{(2RiqqvC$*LoAd~!X%-=hHtmEe-0Ipz<1v`i+PCcF_OkWfU~I&j}= zi8_-oc6P~Xwt74k{PZYI-QmMVvdjzQ2z3>p^Pnl2ijc2(4O(}(GjY^`dmZ`lJK*(I zY2G^uor)6V+3?lizJ_Fu4-q&JPKkr4oYUmO5ji6=Bvz%DQTc~@8HL${bFPFOwO64& zUe!lam8?4?mldC+t@EhvZDKX|Y4rcx$|u9247KcSCRR+qH!v6bvYn^utlpFbhk zoN(DDK2wGUOzjshC3rXDJG`CDwclnGQ+9b?u0=;HDPAw~l|ASTc`xZ(7oo6Gd8{UXxvnVb5|1IgYnKJ!V)53b}-DnLY2LI*z7 z1M_EXnU-uMho#)t5jya$#Oc#o{bVgS%oN8Z7aT=`edXz?QKl%hRvFJuy@Cq8JvB>k zhAVLJu`2CFoQe9ivFoq2>nk`UYpC|FQD!usVMFJKv|hgP|P!)W_Yz7kaW1 z!mZic)FoV)g3p{4;$>UU>{?TF(945DSNCeArXpJAPNIHif0l$_dZ2?PD8EV1EW8k5 zeVK1^;w8R`N9s9ZDoy_^&>wY_h>&*hZ)ZU92|my93_G|*8ON}I03~)2gymzT+%@F@ zH;Qe9*Kgy)DUAds6G*=%P-y&5OXClyu!2vxa{##{h-fA*Y|D&snjsRt$5E~~rhl4Q zjqFWl(vCY~yqBk$DE*ElXY^^qdB*1(c`X`KhRnn%VHN({|=xI7U4Sksb+wx)UAZ(aioq|tm- zN%Nw8I=s{2aa%)#)|Nh9dp`9}w;j`tJoBj49}`?=r^)23sB8Ni@;4VT>e-5;-By?XPzr@LqRoT{F#nd#tyfTZmb3gkaP zY|u5i9E~LzPVbI)wtp|33n1hLm1rVE>)a5XuJ;ekT2YuG?GVws-rhPI_w^(`>gtDX zh3u#g^ruh(LMrfS$%{E|Wp=qB7rdPwxr&4Bs zU4x`}M!Km7$9xC#&lAq2r`-9W7017oR8lr!U15(;(6vH#1VPG}HU^B-oog70ZxR(8 z?tFaYQec$;iYLC!xeiAb2x{v-U_M}Rmim|!Uh`%y_N26x#G-rCIE2~wDk&_YG5whs zS_jde-@8_lWd(C6tIxYlzGvN?*9%(eb4HqlUt|%eB^vW!ZfJK1B99GZ1v~~ht?@Jm zPEugwmuoVoj^BqgYT%$o6@Z8{7j&SSSg%}(!CeZjh-l4V40zEkzrm#G!%AVsYcCTF zZ=I>f;tHy1F|~FgdPvIKCi3LbaGHu_9GC~#TcP3m!HQ3MWeOV+8}IBOMwM($8f!m^ zs%3qxgHVkGn8R-KgF^_p32>NVAK*c{U!jkuev zlS;!*7{M%_eE51~=11xl3m8XlNcC%~ zbY0rzfil@4w%f?^lrL%~v?JOaWEwl7%j7phv?wzz6CIgm$r&OuhO;}So#7cKqJJuxR&KiwLu)mS(w{@kLFb3{I8Z0GV z=P@TWbgjtrIlux~S+6Rpvl$(`4U#;g!eAm(MwYCa%95`2U%T$H(+5Z}WXz*A8FiSo z?Blh|_>q7pbj)dZSV`Q*o$T7#%j+mo1)#4QfES5z3GpgmWhJ;jtf?+sK>!MsJ7mi- ztw6cQkMG(z3DcG5a7@7k8%nAx=*wzf=1hpbzC^-9S=XrmLscuM$*+*8%`mW*zWg+A z{P{|G{w2^ZII+x?CYA47K`1KCP)wzsW2+heD<@lbG?+VR67d^VQY)B|&H8kyOX0ts z4ZLJtEQ-Z&1xYNt!>8Wd>s+~Jpaw_<%7*d!iN}o%}7Iqk| zz`6#1GFu93qiod_MI0ln&mJb6gZDE-HS+IDk3?x@WC&Z=dDs_SAMz;3bGt0-1eXG! zH-N%-uOY)*Sf3TDC-%?L{!v)+Uj?8La{&qUH$86cK!tj9c6W;H%Y=iQV3ayRc^;=i z{h1dns)vzk{spniZ8N^G}@>TaMl(Qp#ZILatk6#7Yzu?P9&jn5jGC7D*9Sr0@&Gp-vi?|=toc8lQd>BiKCd} zNs*+DQOoRQnm=Wi`Rr-;CZ7GFV~!xCm*IImfL%n-MlLrFVqdI~SYi{yC>D^1wKG?> zR($xbC8m5&^^-=M|z5Ju5+hbt8S zgT5y))k(AdPb^tD*c`9zZvB!hoczZ*B)kxOq8`j7PP~|2f`5ost?c~NcZ9fV^vFfh z(n9i8f4JttH4FL^#bQb+O09&UI}!hfi~r{SQ)H~(Wd57_(-SjNgKv;w||-z z1IsPY=U0&P5X6~d*#@4z1qJv(oZ8u*3Wt|~vX#I$HH3@KhpD+Z$4JlE$nx?QqH59A z@Ce$4RF@1aa%-<*rCmo32PVrzyb#+Pc@$n^OWNOa+@@nZIzH;VS0YcVFQLmtm z42E8KXnaRcqnJ41xi1l|Gn0fSugfGKytvEn z%;p9^7q+!W!^h9uLE%WCe#0POt@PrNb+pMTCOSF*)R740_<1nez!33LC6xRpOIB zO78xh5nQ}R)mF(#PMs-)(edd8HXUs_Go$v9Yvx|3G~Aa?(P(bmS1bG5k(tfB;P#ld zd9sZ^oQHoT5Z!~ul+bNVI>*;w{%J$pSY(J8NgBP7Wq*UTwYAgJ($Zw#wOS{&EhT#? zfK4qeEypt&yC|M1DA?oJ>GES4a#>kfnKWrr_Bozm>F-VpGce-O=h9GPPN`9|=VgF5 zR)j+u8qPg%MGZNw(zc5m!VYkTi|b2D=vm~q)1Mk%U}Dk`Lgc3)*u)XI;L$D2naUqr zhW)iu0PMG)BG?Mc@2?_mHdwWkvYP9bINIFlC zefBvtS_zHLr&WyX)2_);`5J?xquJ9MpYB{c0x+T(lyln)&ma}R7S1KzxsYQK>!Trc z_36U1bLAKXaB<%|p-PHYD=xv7Imni+|DK1qzVGzXhm&u=L=k3IR$_~fPOD#0;&<1M zB(SY8TvP(Dv)ZQ8EOE!0LKi(cV>t7`?Y&%iw_nFS7DkFE14hO#7$Y_tim9SbZ}BIv z=X9IdUX6R~-fY(|K+HHezO?fyK6$9bxQ}A=qkgBWVZ<_HdGRu`^sUK#pHWy?uVT(0 z7sT+xb$5Vb@fDUqGr*S$+&DZ!qThk5#PRbc0hgBclvZ3uMuv;4js#oYmo%5HU>)*> z?IMCu>w^OC57HA_ll=m`8|}7=_qf-Eoq{Gi_70N zZ)fm6qXn^z{dRekPy%Q93Npl?!$C(!*E3v?u4ME3Ba(}$c><-N8{QLb|Azi)=X?74 z`kqjQsjlueMA)L|e1fnuE0CXBLBhajM+yxI2{CMOLvV9*=Z{((uQ0Y`i#JR1Wbo0Z z`R&OJQo0*_F>naFxlBI9+_T%RyI4FSqjpGj)d`bab-=o7*xcmK0YXL++N8#g(YHt+ zgz*k-CDQM{#xoEnyV;GFqcQo8=vlM`=c+P^ENK+ zx^B_|@$H7S<{Pz6 z8309RixphZ%_*sWJoeO6dFIoY>o4=T`DZXab0I3LaJ%B7#Q<1?>x43Tt-N!QT2FpR zK^G@%K0cq-VK6flI&#xL&#Zgl9gr$(pL*$;pUILv$)E4RF6sDyp*UOmbWqCu%-c_v z{n_0*w>wG*w|QZ=l^~Kl%$>}r4Uy7H@$=Nv6E4lyO(tNCxfeG$pFB#{@o7_h_9ZY1 zx10+(>ut*O+_4zbH!3j2;TR*9sag<<9-(v)(VqQZ<-p3x|B3pbF~LOV@g9HL`NNFkgZyLSfT^Hakde zkpMJda#;DL`q32E>X zvmOaCwQ;ojce9mQn|TcdpK7DZGXz}YY(t`UIlcD@bUnTA%mS(s31c~2N9Ot=yAn4H zdDJu~f4r_m5SI}eoIA`D==5Iskc)EP5m?Nq=LZ*9yY);~;V0f*(P1tw)Y8kl3I4*u0)Nx&-;4KuI2q1rO#UG9AFnkAD1&q}S08>I zhreEF4z@$2cE;sDzZcl*zCieF-4R!|U81?f&x#^Yw%j0B93!9;ztH+tCZ=^0toNRm zLcH<_#YfAPk(t$+E8Aa{-=94dzQlN_Osp+~|5 zR~tPTG3zMu6NZeQMr$AO;tEKWpG1wU$#L)k-9EKMmi7F&NhV$mO}ssX|2com4_NAa zoabFsIaSf3ks-=l)s|{&I0=bmEv;p{1-j%UQFfh>N`@83;=~o`o|K@i)AJfP&r!eWW9yL{Zk&lVme3g^xH@Z?P*&9UQflv zI^E<8wmeI*!eQ+bMD_PSb|;P2;N0ZJ(6#*l`U{p=YEi`+DTc~Iygg01b0AtQVWPq= zf^EbzQAiDSalVtX43D!QOKaK@?t*Y}qHT*wmNU>rZ-`7sx2AdR8Bv}{m9cUaO&yM^ z>=wisG6X9Zrq+gKBq9@%F{IyUuY_v{I@#5}Gxo%p@=zm3C1}#RA24utaFo({Vxsfe zdFSQqgpJ7007F%gs9bS-Q0L@TX(itMOj+VwN1dW9nF6!7Vz6jhDdu8m+L~zyY!1s0 z{vd19_r)U1I_Y1mR5p8mVx{&9C%a@_?#T1!{{8I|zW1@URy!0)H#b&TDoHu|{iD!k zWvSJSI@#^24iYjDOu0OV#hii9#Fyu1@reKJmv~A-It2HDB%1NTv0Iw2^czbWA;k0K zR*ron%HxVcsIoe}FOC27ii9v$BQ8(WS#5)Zc!c%Oy8zzdD64Ivly;s-Z~B(Q2^q}X zc83aRv|OPyDuqi^h(;L! zLC{iPan#>{A>f}@csRj%n&Q9!Kmv?l#OAu#G6n+}(2|Bke(9TXZO@zOz0Qx;#CGPi zP3_p*jM1LD3`%Tc`9M*y0-h;dqe8Ap_N49wIQ82-PCvX zvwb0-c{D3!h$`GrH%{(H*gQfzoKd!)`}#XOt843^j^{oYFd=9Xr7r8Yb`xq07n6jM z3_ub|&>aTVNqadL!H*)Jzs>Vi^_TIMf?1N7s)q9sxbBlD10aWvk@(!lx#H0^0qh!X ziU~wBM%Tcd`rOr?9sA*YIs}=XjKP-BL#YlRZ*X?qvk`<=E(r-O+K2Ye%WHQRNN@zB zH6mnAl?U+zXb0Z=_x;kRRp0*GM+u-Wu(Ez^%HK?e@vUH1*DUpijt>C@y3v?KM5}~7 z7AA?fT4ZqP4G{k&z=On5wnwN=gh@OeV-tsCNJ#orl4{DScl24GAn#4=9cldc<)Hh|Z`eMOktT$o{_!f^84-Ke{f+w>>bMq@X~27f-yI z`P4JoXp7Gi`PHAZ<|{6D&Go$@06fHJKOqa~WX;YmKZ!IpDf42qF+_SZ0EO1w>7Ps0 zKUZ##r!)V_SX+e!K9jP8R7FMCv?ph)kDcFRc8@$se*y&zi4q7f2pw)Xb<PTR z&B{NkDhx|&-qVjwm{AO&HOSBe9JH|>67Wd;)#sKpq*8oMulQ>wo0?P#!M{hi>9zY5LPLB;kGIgYXA z5jGh=9*)wJYo9>xNiWJ&ISbFZ^P_-A#bl=xp*Gu0goyGKskR?{78V{;VTV?( zJ|}pNCi1;0MFT@YF);>^bSer%M1L_1GPHgCM_0bhp#^_;_16HPIiURSKjj~5K*L)) z5nT$w&xkI$9e&%)JDg4+cV=MuVIECsSYM)!2*-K1@RX+To$KVTRh8=N*2X=zioNZH ziegF|5B?fM7}M60tq6}r^e3Lf>^~(|E3;F02`FJLoP$*adZ)dippsG|_cZE0>PaiA zhdFO=%=81Qcscb9bVHz%VHXoM>`2?ZD(cNEq2@A^y=&z)KtHqTWj$seh$NIn!|j*& z(knxDi`RtLIwE86OB}(R>A?eDp66Zn!UZ2KfK|DoBfy&;P(c04pS%iFZeS=R z_XLiM4+Y0=f3tDIzF$LYo#k5Xo8JvkS5t<4Ls!gt>1_WHpaukw{X+_VphCQUl6Z8X z>+CI>z)pcjA`eDoxD=fd<&O@ih6`7~7& zI8J4g2j;Y^c$kpH{CWiaE}G3+k%CA`i|^|h@FU@dzxnwlA~A#%G`bdP%O}ZuaTEpL z8y3f#8*>la?>b_*Uy?pTq5Hi*T|X}BrV1zA1e)ZTKh=_%j^?LwVcJo0I0UG7u87{h zN;#me?*wex&r`!@L@T?g$WG^l9y-XN@NfwPNFqWOL6UH6p?HL0-rA!FO?S3MoH&{Z zhGFr(yxKo@2K2))3Phu(ekmoNhr*!Rubqv1&e1k0sN@7COC8UN5Yx`O%_2$l~KqTo-+WVUt^= zp`W}22vmR}r_4kr)mU-fa#-r7sOr2>y_&K0;{Y9O5MfH0J$)>(tl6-1qrf3Bg;p>E zz#$?MA&Y{5+aQxSQhgUd`w@iUQr+VlbHnnZYvxvs^c`dvTzuuxBea!7VE@F_$|=WZ zZs2<311jW#>=TdE&MBK6Q5_sP3Hn$$UCY|restaav5ioD|H-ex2Wj!e!1<&ImV`N~ z@EV3NJOh(4K1P9|?R|gS%>Z!AKp(J3fnKkE9R_^nV1}SgM9GR!>T(Xzx-k(iR^l%3 zT6<*#L5i{5kzmvY*TNB3s%H#QU-#}x#erM}Ju?&u7>17};dQebdo}+)g$J`oA4-+ z$1!>4V|HNOIx%&1CV1C-$90Zupy=;z5n|o1}V9NUT z8~8Q#J2iPR^ZkJG4|KEbbnCI?%h6|~S4!{S-P_itWmQe9XCEr$hkY+-GYp!>`o20- zlHWI_3O4PH4k9xBR^2h!kZ3L+kl5KK4ba{W$TU9O3^((055tiE786V_)lj_`Q*<}U zPkZ2R*s%MaKBkg)nsMwWV;19cQmg&ozpVjDemnY7-w|ILZewhFw3=lm=ihVSDT-Q1 zA*W)L8myj5QQFr(9B(eMsnsBq8bChowd0hxAjliyZL3??D@bzsRpP`kGCPA|B-AHf zUkQMxPA`aA_=x=_7qLR7b)E(h4~e<{`Ei-!IUI&Y0X*>GvD~<&tVeCNLl513Qr&}> z>1&aWmC*K?ob4N?j2(G*yK>-}A<8+^s<_iIu(?*Yei?gC_f_QD?S-P5R3pJPB*gMUl zpK04lJHPavwag)aO+EItvb@)+hl?)$)2|Ii zU|0DaFTl%z%ZT<;@xPKdHx24hHO4Rl9B&|Il4Ip6&15WnuE<{*O#coVB<$y6~{h(v%1B4n3Nuh6g`2sDB`Jk@oqe?dGdl?Io$aPI(VRTa2 zX9mV5$6;6^e80ht5dTOvo1Ne}v3tpCQ+EO;j3I*8Cms~-XgVBEi%T&wZ)Q>C!EIt9 zA~{2ugbO}EQSl1va*E8SGv1L94|a_QGW-bENna%m{%=`Hz)Npc24LIrvv!FxTwX#G z&gJH6%<-Nd^7%(4VdZ(&n)f67YJZ)t20dF%c1yi`QP#jQaQo1MOZKJmEMpypC(FQ~A ztr3T1;bPv(vbt!SS_w1IDZkOAjy9I>&}_mKBelM+P##3^UQ0M*{_3%mwK6m#Hv~87 zn7h*PV@l-M?sV&W%*FViZmMG1OYsRk@B3xgXH*Dr;QL`g06d%%$Y$19jE1sY&q(LD z3?TORem~DEw<^E5F>&F8^qCVK~sM$l|4(O@Sds*7M%6$R{;Ee81jyE1`G@kui>o? z>RFjP!(ZQRnWEKOrF+D)X&t<2vjTE-6!e-B0){RFmD%cOg3lCEr}NY~0l1;@N2Gz)><@eo zw$kqw(5_x07cRUOWDVVI0|Fw#eN2F=)b>XEpYSWYohf}V?!NI@!@Hn$V(%HrzSuVb z7VSjUXR!9L^s>ETG@cBdI zIm5k05o*4;$Mv5L-uJxs)Ez0U`EOCzk0)D{6@29xB5zdeOldNIPE$k=#O`oL_IGH2 z>8im{jbSa87Kvqx!ZK6Cm!AU4tNX3{Hr5ed84V}zp}o~iT8WNn4n(5&CmDz#5dQxQ zGID1t2E7|r9{lArYV86v3U2B5<+H(O41_975A4H8;|S9E5;(}3^Mjlyy)~#4xE(B^ zs_E;ZBuE7562wf9LktQ6*#T`GiVozBKT_C!MZ-)jrRS^1T zL0obhSrX136@D@9Aqm)#Q))sTW~6=60~GW=8SKYJL{`6aCCz?xS~Ey8bWU`oTuOo) zW#9QyW0j@ah1>bt#6_&(gtqY!|Ha&Rsju}+9gr$i^Pf%JX45b&>CfCx&dAkXa*rHF zFdv;VAl11(tr#;)FFNKx>3gU~Dbi3%(0kF@fu0I)zhVQC##!@$a zgXom|CoozIn9@ujZDh>+_wW5m-JsPq*hxdzb?d6C)`>!bYy|~0sSNDEcAF?Jge}Ya z@>*bhN*eBU(wt4n?p6IuTq(*2<-_X{e8572%!!b&Qr}Ye^-l0o#ya%knW#|_;!#U32H1-Bt`_&??1|k2EI;3Y zZ>Xbmt=wsc^T$rxqhM_vvRIV4%qBw&GBc+q@dAt*-WQrxkli~=K$l~o_OI9a~ z%F@kb9U*9GCrzv#M3xm1>pU}TY-ct1! zGC^$8eq67{){7}JShZnDv=YJd+K{*xKgPzhDyFBIFh3W=NuL_=zw&tIwV)qIfoYJD zft_rV`$)Vcny{%XeKG?|oX`ILFc>f}SZr(R@>&B+6)+-V-kh9`xgs8d3*%JLx^yz$ zvUeuc9M!u6ypN*aTDnCEG;&8m?XA!0j%Bs?tYK(-ghdr2a<8rrl&?jF!5>RRdDe_Q|vZveNfEe)IOvgFVpL zGzSVfkaGruRf&+8>5>bRPk5h_VdfiMo9K#P>yu_pRzUIV@IN>fKhwelJNEox(fR zc8OvIi5nc=G7`i(_r958K*JjqPI~poVT7hZFI-Ty*qhR@EV_1YEbZ#};dG;1u6TcZ z0A}ZFMjh!Z(-SHudAwq3PL{g%Zuc8f-Y#6OZZ9v4=F;5rd?5RJJC;GrtbifA?_Ls1 zx2J~wa_ZFL)q>L&s3)mssVAt1sOPGNtEd(`)E0R!e4i0I(EtDy{6Nc&D39#AXFsms0A#!So{7KjYkzkmM8^QsE| zn{4Jel*)QX!e0a6WetDy_j$ytK%|tT4@+tQF(QM6uSAK>PREIDUSmK402gOkC2WgD zSoi1n0MMH7Q2OGnsmeX$#C^zZUgiwsNR#fMcTGs3WO@#uX-@4xdxZMfeLyz+{3$qc9^2;45h$P))X~VN9!npWfkhva`R4zVQG&v;$PH!5Fd6cy&VuVsm&5c>+YY^e zRAHgoQW?8>M;5T`br7^CP_)=?t|%n@Xuc|N7d}QBqwB4<8-Z~-ZbFByq8gq!FWI}@ zmz=5e8|?PjLks_g+sJ~y_<2ZY68G3wVVmd0xq7xM%=YsV(zGUaE)+M_5_hZyy|y}i zj51QqN}^`?e#JTM?(pKetx%u?zPWRq1xyi%GTlf(o7g5>~hy(p{do{cX?_@V)SMFO*ukqeN z_Kr*{L1hv}CEZ+F4_#CcW57)3g)nf+X&85AM!v}v2Gtx{!WUcnh+#t!H8+^J!at1Hr0&)io!*80C?Ic zuv6iMWlWHM%hK^|2-Dm18UP_riG0tP3RvBBG3bUK&&X8q`PJ32If|6kR z{6F#)gDBrG%@@=j+h*6E%g+^M@z?h911>sh);;x_P*sMpnYuRZ zKcg9mWEFMCNm@>VD1qC+=}-v~Ac_a+jSGEz4DZR1j7onlc*0oA%79HOyjP?4{9`^( zBhWZ}XWY}yU?W9=p2O5EY)lNZzHuiUugQA#=5_}usfYsw56EpMWZ+^u73aPhI+pc; zve8;jC7lC`Dn%C7504$2XkZ+0m2Vs+ewC84n9vTcncUC5*4zVQrIpL+POekgouEh= zV$e55-k8o@oWiZDNx~1Mdfo$7ZeXqL#E61Ibgs{zgsa42d+F_@sBryD-xX6Fh07(G zkx13`5Y8&ci_dwMdcl7I4Wb5bYpWNo=pK15KA>A|P3i`;?EzE-`aNelgg`=**Rkrp z60ocYGm|%hD=N+-Dz5!MVLLm!QO@R%ulkT#sNM`zRzj3zM-vxnHV=*>_`b9&<*EeZ zvXJFq5gLYy80`Fiz5v9%cN>}#vR0&T$Xd~hd(z`Dl(UPT;~<8ZvXzJ&7+Ma zUZ)&`HPsH;w!kozgi&WIfQEatK%AnkAInus`n2cEy5Vfx3iwrXM;+Mg1W`NGfdUEw z^vZhaK7?|nLXZ1y&Lq8XY1=mHVpuEx!Zuc$u}XRK1|5@mJq>R3dLaIBfiFaws@1D zX#~mNbvIt#wcS}Y_NIpKDzLVcC!pqeiHwTcL@8x=NIeZsqG6_YiI7H64ajo>nihqY z>`Koob5}c9fn3!zU2hbSze}K^N;J%Ty)>jaDSZXySOn{M!uS2F7_4 zpk*X{BDr81ioEUQ?Sdc%CjLnRs3;CDe_KPwb26&_IIl#8uCT<`QQ^3QZih zi-(e)tbx_zeS%6mlJ;25rq3tra8NlP#=tmg>JLY8P;_?i0ogEiTXve?aaHg^J=Qbv zm?J2(7!w%x9y<}~l|ysmhRdX9ChVHPUV$}n<2+c8vV^Utaz}ARX?;55NK~nlh49Pu z1%pEUx*7FeSvn&-x_v57-`<4nku*2hq`z0GOEGHDj8>7hLAA6Xndaj~P-$`VQC>w~ zw$)yD#<@H-Lr4A1tPz8yvo2-EjR8EfL%x-JJ9Lq>Sl7Wan51wjMHk0VuBe@A760Jm zI@)J4H#hezpOGtGX_zJRQ$2jk-s3(`JFG=kFFR6MRBcSA)sbpRRn-d-{-fs0?VOwD z>rtJe+)oCjxsdcMjN4oz1we_{b1`0h@6rDdk;erUDSM3q@Me4ZARjl#6C9E&=ql+- zS*aNy}H96=srQ>sf+`eyc zVJh)rp*=l?rK^1>H`YS=Pfb&U`2K_b7Un6+McX6SwURHVuA3)D;Ocp50y#SvCA)Zz zRB1L7TFbg-a}f0}H8GaZBc%j+K~Fda_0JPEO8s{)4P#sm-g3ca9VF7E6)0I)$WW?0 zlas&>RFd2Eh)4H`84$weIm3YcLv72k>*W2*wNF;|g6sF_bCvhW>jBTD=MSk$;gw>t{?LO;E>BGi1yV;@6{lT^m8j8rqbN@0657SC#1&17veXq z&vNE%@rdLI%~b8VqkHA6ZN+XU9|w6I(^7qv$j%2ld+J!I|3|65s>2#f*>PL(lbMu& zPE^foS)PGKG+QJn@zmYI+&KA^P_1HYSHdZ>2*Zx`$*`==8n=1NL-W5Q02564o&-Ry zNnYsFB}#7M5|nnZ@4*>qj@t0`Lx3FdA`H-wV@EfrKcUQi3IX7kKK*5%?YG7UWhd3f z>(dcScIuMH=Ug7Pqm=w#+E&_)P9C;zNaK(i8Mp6BCFV02r_@ z+w+hOP!6>vQNE2=i`Xyla)crO{b1395MmHCt924VJ#>#y|A^7&n469Q*>9coccu3C zg3d{aE(8kHhzpRE1Pi=;Z8-PwxkR%F zxVFc>50Cn6Y=ccX!$H4M7x&JUFTCY^xki-g4VTN+irsuY|L8Zf!DKWi3iLS|ZPR4w zc764Oj6P9P`ZUU^DV0)I+ec;|sCs-zI$LUlln~yjhN2SR;Z;(B;Sdwu^ko=02hJ|D z&R6iwmr?8j~;a7 z0f^)R&IrZ-7OE<3AL$qT6>Eh`HX&j~j2`}{G-V7NjMNZXn#w^0`~38u01N>noX@}k z6cOk*dMQI=oxQIPB~74W`O{k@{kPNIudff24p6EuLSx_D+t9%pFt`t4Tsa>>#Qfh9 zAtQ#SMkgR*hV9j?fp0)6*7KeQv(p0ptGSMG`;8Uq6i3NpxoE7b9)u}u z{|6L|a^3)f@SHT-d@#y9{y&^H*?EO!x*S*3f@eJWKM+UL@`A^B;gt9G6?gx&x-BK_ zRjiltFf6#@Jk)%9MjNcqvtT_k)%oAX_=G1`muK3hr{1{x`kIU)Yp4d7X~VYY(S_2M{uUAcc(5>n2Y{1t#dT zV8D|VD@&HHZZb_sKox2=H+M!WB%P#(adHO-kNBW;Qu;9Ia_ z9+x%`u==dAAHBX_HvzV%zR@1&It+ruEl(-(|1QNiT&ERPsyZ2!7RoE$Q#19$i`+ZB^vJ4Lc5YlPj+6C+tV|9fwW|ePpNh%&xiC{ zJuX}ChKp==U$4GpPG4_xzUT*OmKk;3HN3%AZ*^@hU2gVcu9lScYDB0_hiZ$HJ&(0O zl??GicdDOjw=Uju-Mjsg{JZ4d{bAn2W8Q;h-lJz1BgYtq5yZJ5NRmVuD2kHAyo}i( z#bxrt5sHAieIEEXtz&`3;oCCn=Q7^O7lYTU~QvCsd+xmWvs)*Q$KF3^tzpsnxGw+uh6 zJEjEM0T;kT?$o(=GByU?*5k|ODW1c&DRxip0)cC{2m>LA!U+PyVZYze3hQS4_L-zd zZvO4YQ4+%z=wDdZrq&)*KiN>#A=10N{(s9Doqcq+h^?k0CF91bX)rpomzC zmaxirj+wv+MM+L-C&!nX1nI-UoE4hm#hxV@UuDwiZ?y90QAFODbV#UhZ@d&HRTzdV zgl+@oB8-c4Bx;9PVo|AB0Ot2XSQ5b5QAAji#MshA*$~CqRZ3WsWo%bdwQ#z4K4ng$ zHCxRU3dEBZFiasyst#Xjtjv#RmYS}%G&d5$@#jX$SW6a_-3)XaMaJNIcy~n(za~%I zR4H;J060^CTuOi}HeggELyD9smd_e9=PXeihR59c!?J;RbbqzrVD`XdI z=q9V|H0$t3FLhUMO-J_i4!Q8 z!=Q09;MCYz+sfuMsN)2P6gZ%S4knn>3S?j3iVN z;!!kN&>Q2|ACs*@gpQuT z4*vS@K>&*)b^4ocOyU!K_)YVDau(P4WF5EOxm=1yR|6SWEDk~6!SwcttEngF2&57= z5!r~XMc2dYVGl}P1I&A+aIRns^gWBY9n27+*qG=3YYQqm0@cspsEK3aPp#*I5-W^n zh>kWg-Zuvr$Im9^vuGCv`qkU}`vdnBX@r4B3XOY4L&Lp+UPA~$?}ep&3?#QpJw7Kv6$k%d+y2J5K#vM#l-hgh$Cl@hQ|Xq(c5yQwsxv% z-Qg$f{&LQp1KwS`k^8=QEp{oj<2jol-(Q$gvwtQg1C|m?5J_o55?jF8FLkB3XSzP0 ziy6DL;1CCByvT4v0|DsGom_G$ucqB5usgS^C;YT1$ue`MN3o?F9RDoZ)bwE||5R#G z4K@(S;)NK+!1i+gu-Eglnno_#u<5g z7m%N_gW{ElZL{YL0h%dnJ%ThQ(uDSl<;y~EUJm`kYMh*Dj=`SFn2(6O$-vacDI|L) zX^{!d`#JnmRkui4@w8M>TK0PhYq_}-P&fdSu%zO%r9zsVZ;n@(qYg6rM2bZP6-Yca2 zNuymWHAOpZb%lGiWdOm67|ahKfZ)IY3ew!#cW`4wfdd8@Akd2_LCVmsxUVj%d#xSv zZhZ+0mby}=O6x%TM`B)WV>3NXOZzW=PZ3=T3I@TX6bQD3t)S+0!{z<>0smU#llr(jP&AmdzUYFn8=&98c`A=qU zmX?ODqH^aCIAno=&^=VZrd2dwmKH*}v|k6QWMO%67nLZ34#mou1X{kPr^rgiQcl6d z#_W>S7BeqbNm&=WUEC7~H7i>~;|R}E&O2pQHX|#22fOB6RfFC1`fWs79s}-Qt#gGV z_1YAeetAjDm@}N*ErB`FF8OVn1NzhnwQ}vU?UBa_0#H-qL;Eh`K3*gtqW2}B76Oj= zLywkrn}7jFuz?OSPwqffn>|tF08%!;gdpqUaqRPqRP$&7%Xv77E8>fxjnuy8EIKEiknkqQ#C=v_z8#UmO`qR z!YQxL(o=Zz?j6RTi_hnhI(w#zt+m+N4S~@&qxJn3IDVO@eV>VA<65_c;_oNPpA0K+ zlBtQ5_NY&W#hw{nIG?;=JoYF`enpm#9B9@OL3p%aBu+*{Ob|aH2x53FD0S*!a1;vR z#6qk~bd>hBVp{vm&8>Zz+A}so_ypQk{UcvXVWPHdi-5lXNfL$(n=}DR6pB>Kq&`d5 zH2?uYh*TM5uwg#)%5CGfHrN7Rf#zUOL6c~VT4@j{5omcrD6n39NX||^|Pzk6@WGXzl&!B=5 zw5Sets08NL8I~0y3G%Zn2SBN7%hTFD!fsS6v?+pi5F6kr;u1%<88B6D1fMBbA)ZqQ zad?A*H3&VOHR!=E8w1bv0Jz4;6JFWd<4upDTsx0bi8%TX)8sBN_p`fy?YIpI92RHn z9`Y=OGzm5YE6kt`GTzoA*X?I2ec-OEM#(m|de!X~G56 z6W6HBr0gQ|RJ5`R(XCe3A|8jcPQZ#-mP-KM^) z%ZmKRMk5zvDUV>FRpoo;9f55A$T4#vK6U)?$yhLygo*OIqz7^NRM}r^^~#M6hk6@= z4W)=}pusXr6{|r}B8mi-QoIAS-_!hw%x-Mvy~8E}`xxRK^K?au?i&#TonKp+u!7byZ)>6(xa;_~u=bxNwF}(Str;0K^3p%)<3e|KRaIxdz0+5r zhxo)0)U%V+b_;7Pk2qt(k#@Yn*K#2#rD`djpBgLjzpOzz`1lPB)897gA!)lf&Y(nL z6Y^liU|X#EU<4{=61(`MEWi?)h@!$>(-IXz(PKN&e?R8#ozWauTj{Y+_RYAjXJTJ4 zy>pR>3xs2kP<=}a3WS6&!zK4EdC8E_ON>eSB4IYv zxT4Qw-zu|bK2bpJA94s(lKa4+pg4nGy&5#?YHz3dp`VN z8Oz4f{`;U{l5V04=9J{6tdz#GAVkTAq~c4AU8pc(lp0AbB#47Z2&qabNIDD+vdo@CmFn4f=j~<9^I)2BR6V59 z{(>n$x-Lo!Dx(Bg5{|31y7v zBLy~6tM36ys!$23f>sD`cfeH&n3y4HA~;uxOv|z`&B{A9Jon@WX8eW9N-OlG7Pv%c zFZx31!j=AS0pUxC3i>FgO!(uKy!Z)J;S`<qdT57spPu;sn~R8lKUi+|l-~Lko^R!zUSx;+~>%6J4ejx{sdK?u(CwO*RxG zkG$NcF6TX^tG*vwVpKVQHdh8Jt~{U`1yStOH{%B5A(yEG&iv>D>k8Yw44~f| zks&;&5l%%}*8}PW^(0!$%?kh#yP)ShsRQs=)}93j6Wj@9XAg^~t-n$8Lkl*=*zPxB zuG}U@ZTRtG#`w|o)trlrL2?7sgoL33QzQqQHBsxGn4hBVcxi6HRwMo!J*|p@**u-5%j@^UT1U z0i;BRafP%2Q;>c!P+H}kbp(Cx&c6qSJz=NJF4%hYIa_MLUC7NMINW4&KPs=M<5HVE zoR{sIOLk03HCR2c1E~p(Td9Pa%Z+R0CM=M?Je+tvr=}LZrq@CdWusYFEfK}kBO6rd zf-z(3K0O!WF66J8W@O?j_YWAiphMgGDZ#tx?@+qy`Znf08M*`v&C(u2YFX0`1yI+i zpS0QA+nt<+N@5^OQB~V>Kn`^%5Xo||W*zE6XGY2MBziL^YAa&rL4pnx zqiS-er9_Z+`A?WRbD?A9eZ_%)VqDm7P6$LBo-HR`>$Gc>s1Xd2Ar=DIN+e{V0j;bL z8F%*5u%u1gd`8G9Rph!|@};$h0+X%l_~sNl3Cv;b z-VKwyjI7p26c0pG=ODZ&w;^9+1gx%*8&qgO0bu+JoRr`}7D~p!>KAmLhmN*n&%+1LIZMO3*|nGgYF~bI`wQ?2&DdE5HWk`hnDgmiZ+W?R*7Zj%-nq3il@; z87_%M*ktJpCj)f_bv#t-aCEKpinBy*YbL~UGN9ZIt;e0G+PGPRKNmOMM4rN-PYDqg z`10*vHz zT+H3DS7*g-5;Zao@X@TJbJ_H!%wg$H0s2vpMb1k%-!;i?3N0VA* z7CsojZ4w2|Zao6QIn>L&-WmT$z2poUF3}Qnt~x4Eh4c&jj0hqw6ZRg#lYY=m?FX7} z@eGwOyKgY>XPg#iH*7?a60{>LLwB`-NRxYzQR@56WU(2#rhiEvADp^g>0Jj5%kWLxl zLzJ$OD`{?B=SDy4W0pZL&Ar0$k=}WCgZa$O`S?j)O)tR%D6~1Ci-efh3B2=7Hw&e? z>k)HDR^_lupqE16=2jk|4ZXmr8crF%WL`6p_6v*f>mO^e4MEnqJDMm6TW(L5U?hHr z=@zQ#g>9*%+b0_f|K%M>PqF5vtjc5sZJ1v)_fU^c;H*kpJ3DMXb@uA7ev-22$6`L* zc1&LDV*?whA*K~3f_F7{-1V3h4k;Y)JQ7mNjRWV0g6Z2yNkzRkm2;W~>V`z0i=0#` zrvtGXC~s4d3aPWFynkpdfJ5*ZW={p`F(b~Mr}UUTnXB%`p9R$0rsb^6t%1j=7=ah) z{s486kg&aKfUEK+3;kV+t#G#0zE&XKDgvlN6xI4gh+5z!g`He%f4Pb(l^PJOy3|&} zPR;0dZYObh-S6~0mU&djUcK3;rwpaQA zRTnr0$GEdECr~^J@ZTaCVO6HKgKp0S>MKJ|nG1EXOCi`nrbiE!@ZK1@ zS;;cgajUXmlql??bohW{OurL?dl%Qe#Zs+e<-C3ui7riEbx(mk$Ztt$po69Z>iF`` z4s?U!J;hQCvv~>_NA$fYmy->044A`isGKF}`&-y9ak(O^^;h{8nTj2!P^&_I$P-hp zmnILRee%^qaE3G7e7vi)&MvvD3v6pNRtHoOJfm81cClNjT;z&oQ(p69yekbDZ$Ma~ zDQq1zU1!S2nX{6J!w{lG8Lvt!H&OWsM&GEm3KmH_T7?|75wFa7wdz%~3U5I!&e+}) z66zvR^bfiWa*b>D7j1*&Z>48mTOKr_szvXIvI)p|UlYnMGn6H)%?0(4%+kT>U!7iQ zK&^O)>>vv)5G@hxBMco2?bzSyJ1*Ep3hFsFE1jc}g}E&B>TlCsvYtJRWT@`J;fFQC zoy=ZbosOh?cJl6pF7(IRw!WZ29#&Ev7>af=^!5r#cMO#XQ);#V>MK3M`hXF;A1xm; zyt>2HRSy{gahuSn&K*!s3$3P}hiTQu-gHAHV0kZmQv@i)xi2JdCMC!*qjM&1PNVa{j7q#RNTQl_R2>o-4rlMOt; zL}v+h+)HnQnfDt91~*3rpl}i$=c(bLieCK937kE3h$ZOD0lPvkc^~FHj5U@|_~}Ia zm*}kgghCE8Eu=Y%gTF`Sh=s_V(U;ZPwogTMKZFZoJh>)nysR!S%R4%=?i5M~TpJQ#nxEFXdpCAd|Z6gRL><#@K{EQ{7M+e3(M;uP_Re z)H)W#ZL1uYv`q9DHtiZy9u=@D>haM7sywno-J1O+StA-@U~A>*54=W1rb$KRUZMnU zN}b%i?sr7I68t!!4O2USB=$=?tbPZX70eN(zO1hg? zUAMS#G8$ex5|Ks>MmeXr<@@!+=X~ham)%4B-CUaV3*!JC4aQq)CXs5N10IT>MfOak zc;6lG-9~BkQ>h{|5aq|%Pk1S*)q3O!YhlMIEyJF0FeX8576M2{qf~@crlGr}PLIQY z%6qjwRpTh=-A4VYeARcp=yyN#3@Uj$Lmeu-jo5;5PZoGZMW@#`43 zc>AJP9WKSVKlD<5uh^DSWir$6+V)J5dcIy-brcLZ4JL+9(`@b-JZbG!fOP0STi`ir zf6Ubu}sIfqMwT<~ps zG<=G(l73-$6`9Pzw$S$iqwCtp3jJnERWCJFFtI2b^qv=2N85% z`-r1@9BG|2b%pEcVCY;~P3wn^A;9ve9MQ$OjOV%@K`CX5b)A@_ zX(A@Pn)~TLbdEUGI?nm=bOs32+rqV~B)QytiX+Pbln4AoUOvNB2WJW(e9DJLtujBG`|_i zd3-RRsEgYb-*{swt`6MDU8z2x?~#?{sA6%-t{Aiaa)t6(uBr_KN=}LB>{WCuwrF%D z%ng8Y^NkT|BbHlzHHl`_<_0+rQ3MUy6H(Z_K+{qUIZLMa7Ftq62?L}UcS-d2jJ1Jiz zmc^z)m;}NxezZpT%Fvu!8=M>^)y*xFMT+~mS;iqFD@5LA15#IN2X__ML5Ye+$&Rz| zKBQ5D65$=oLjaX{(JrBGS`u1`y5pJ8ga~i%pr))nl+32ISMs4q89coVbtE%sY(|JJ zrdJ~;G@l}`DUu9`LL`3t{oGs_7#8cC)oI$}e4Q1z#g(E?M}oRLnkG@d4fBP~taYN^qzh zqxS8x0Ytz|vI<5zwZbw`JVtGZK9N_eXIhL^mhwq0#-;M25Xv6_fW;3xp8cix8LSAM z{I`l29q(m%(KbtuIJdmB=~s6_3DSe}@xqkXr!^=A2iyxFN-o@{z}C%fNJVkzQdVHV zSfe%x>&|Tm0t?I3Qe`=W)O>u0xl73z8V#_^tRSs3U|)UloSe>Kay-*jfJ#HSNXS0f zruBl`-n+_ScDXt_Kd~Jg8G1tqO&1EypuH+}YWbLTaL4Q#ZWKdC8v`I)A}ygX#7t)r zfaMdN>tD;Yeo`B~${QYfHPBZv#EaEEc+2vHnEb&b5(+&svp}3038v6aZ%GyX*uIht zm-{P$%7wUhDH*<*7n+(tut(d;V9wG z)64+NSlqT#8-#?8pB9?gGwttDu@8DwOLFi)r$W`9zBiRaLWmsMn|p9>`s2aaRlcNH zG_IhdSTUOass2cBu{Ga9qI2^PWN7%;M6>5np|2KV#muZ>0Mg{&@B`?4E zfm5iA*E!%6i)y^JyLE>{yWW9@jlx8TPMw|u=lJj zvpNe|x_W~bnE|JdYj|rUr6?)uF2$TTkHj^=nt1NMdt!*JJ&QG7zJY0WLP!}DL)lVI zPIN=5gL(^=T{O?_X%il|?yAGsaT1jc898p)KOa^(3}hL}?ClF$cAjIxfaHR4As%zg;{(^W@;Dy;qPFV6K+HlTW6p7-*>?IR+F65ZoGEoKmW{Ul;#u&l&yo&m%esBPass9JVo_?4=o9VF% zdM5GfNuP-&ETl`N&%1 zyYCe;Q7niO_Ly;@puc;Nt9n%qrX$aX?h+Z!O)XIc^Gs;inRf^%LsQ6{7r-(jM&LV4 zW{gx#mqe)s(wT&4h;E`+S=%Ysqqm*rwe8KHd9RvWNX@*TER(=Kp(cN#w)NxEc<;p* z{OqATIBT?5h`%WoLjFuq~J|7}8Vc;yg)j75O6duB~_ zbpNCe1`oaAZHdB)Swi^BulI1#9*|DK%U)m6byisLamgyx8HP*$x_{Pd`C0|aQL405 zVS!yyhUO=ey7g3=^iTH9#~PFe6cC+p(X!JU21W3v!Rk~RL;?zIr{~I~5a0}0jA3Lc z*LD|_-rASK?bgKcr8w!2&3R2ThE}0YG2-!#WnXn*gHSR0Fog25KN$| z|58*3w)U1=K>3Z$(Pdz@azvIJG}6@SLXL*FvIGRMq$wA5!f15shZ7wn*>lZ(q%0X^ z(cOE#w(;alHqptZF-J^6G#rmzIoi6_eq7elVT>IFs_+Mk!X#3drKBfN?le%-N>Sm126rSGH;N)0rnd{tOGu?tb1!=-bt5 zZ2B)OlggH;StlsXAE;MHKo)1}7t_?Y-q+9?4<82r()j_P#bsjNZk~s^&1(vz+#xL# z0gflI5#-Wn)zYD{;qU`bK7+2pj1{3DtP(kI`JjfJDRn59q7v++8zmL)DY9~o=$bPn zyP#Nv$nz{GT+GAV6o2_$k-5!q)$qhT^j_t9iUad(t3Zfz4h5YvozW_G=*<8+>2P6+ zB96SOJK)!Qn^K#IvK(bTqZpgwUEN6mJjxpR|l-so5mXFZHJde!+nK*MO zn=!iX>cz0fu~LgfZ*L~?1|e9O((qbI_sb;g{>jT#JrPPVJS0Ns3$Wfs!rLZF;C^?R z!wR}w=ebA-H#L+>oG)7=SF4y5F&&^wN3p#l5c_W=3J=UC}cv zi)oudOG{4k{)qkrW>V>RRL!sR^%HuG4=>n*S}eA?DBiw&uazmCCp z>zd6UuV>mv3nSxm$V+^IXQJzdeJUp-zFW!^vb!}$k+D(^#JZyb2KTcIgm(Z?1vWQX zy0!<1N@BOeNcYw3@+XE>(OfkEWV1t^_KV4@E9uY@3^Ek8{tQmB0Y;DNxZjpSC^FCo zEa)Gdcx|y0wk)3dL?jLr`AT(tOGegc?$~SwTtW(f%34@JnOS>JULJuAE8n>T!rKvb zmzFX(wNX6_iu!ju9ERZQi;moc_9zfR8HM5=Ug^N)DSU0824_%~X?YQ7?RS+}2mxUU zVl2r3<*T?z?KL+iikeC#)qPM@Hy+G?tWG#&Z2ChZV=0cq_c&QP5TFjHDo&Wjn846A zb!FS;vq3AGJp!#hzxk=2|n^`eODTYWFGPcnlsyHsmRfnd=s zuQto`zznC0&MnYQ0g0-#J~-vDhCw1tk>WwWg?vkRHi;6w>BH~h_9HZi?Efm|Wa|ty z8G=C&YTznzw+DaVuZ6;IKJYq)wmEm^-Dhc$9mGTqhLudphK?BFYT5bxbMHL)cjF+q z?5(c1WMx)&%JEvb5`?gupS(=M+TKU=NB#*WD?*9_Te+tvXq-srGbpQ@KFl^Zh&hPB zYzrqTp-fg94+9EG7tqucr5!$U2(Lm30ZHGVQqe+i?I?D1>(lYV+3E24Dqc)ws>?J* zJ7&rPqsz@&Rp%{yKc}s24_q6yzz;(j9g6A+U@+7ugj4-9K`8P}$v+)8>m+yv4bAdbH9o&Cck4NMd ze<8))l7U`bIQe#F{PxP;iowxMUg81Q^m#%8gSiLo4_wa@}ymT+J}J#)MJT$!j348t@b+J$a(}+lKhM{^$NDM`?)xE-NRWzM7QXK z>$u;^Tr3fHnjv-aR*-FAaW$lgZ zM2bds{&ST?_XWdD`+KVjiulRt-~8M;Ui{pydXfP?A?lxQu*jFV~h<1!ZvV3N zgu@C~N|cUfv(vZ=0FQYwu7pHu+ni-(NT^1y)BssV2l&NN}KD{eiLu#u7c7 zf~~%x&h=DuA>G~wc~Ayh6FQGcSdCFB+nfY%i8(Z!JZ)!7Fyb_Yoc;FLxp9qA|Hh`( zS(q(aY8IWFG0*CyQ9J{uQ{wV@mCSwvD5&7+GMXsEr9E~ zsLp1XImLf%{?oIQVXwC;I+1(*I6U#3w6!B$ar`F24K~ISk;pghu(<1V$6V8C&DU4+ ztEQcUFA|EwqwJmMgQ5IO3^{Y&(@0OwFDxI^_2WGfvyfQ676UL^K>8| zpD2XCzt+{&oEh~}M|?#molD#IIBkC$ZR{v+2Z!gN|{u zEi$G`BMZ#tgPUYP=haQJz3M!$d?FotVom)G=|u6P@|oHY{}$s=6rt&puBGN$wE4aWd{1CY28SA z_`OqvsCvFcq~GXb=HfI3s-!m>4Qz?SuQz^JoA{Ofrk#m)FhnamW0tuQp*H@4b2Hli87cav2yUJ7XE8uI)DasPFYk zVQZLzB>``la=k|Y&p=&M?3I8^^M#A|aqSmBCO#N&ZgJyp*i+MmN3W3dY1B#4ACBB& zm@A_TlG-E}rY7*elV(k$mT0+hWs$lffGt>JzQ>U3)B!>*bG@%sYDuxlZ8ajzre#z8 zf~rulVL;h{H0tqND|fERTCaa@#3jS}ezVMoujpTl+46L68$H@{+nl zMp0)fGZ_xDZ!F!V?h=H}<%)KzQhB;0O#@UJi6GX`gIk|aqsvk`uIjgQxB@GSeRpp% zH+twW$-s>XnIiQouPJPH&NsV0p$bd!X!Xi^DbU97qV&L;C($=fv9-s0WBN!~{dv_0 za(r_;O;5?0X}8af-2T@lQHyngRbpX87f&4{Q-7+NQGct|*3#R@rN1IArgJ~bb&p#A zH&dM=o><-O;<7hIy#EY(O7@(^ePmO$5`!=_RKOGLeZv#>Egg=X_h`<{+{&K@o{@zq zZk>Q`7!1!%c?NFWvIeRBqE6Ajf8@jRne*-`@C`}K&P}6=T57E8SvG6D&bL4q8}w0V z7GyKoC;fTa-j?fp?zT_mT1MRP*k45a+^Vb#v{<62lYY@3PxrVVh&PziCNt3MfL?7T zDP>N1GG#d%MVv?pchnffdI_mrl8m$TuTnA!KaKlV{C&;_8lmAFJ89)O9_xnxqeVvx z`p07NbDuG^Tff~1;b%A$cHX?3<6^jKW%0NxWNbT#MzG9-4z7(9cBf`C*?BcracIvu zbo|^WcFS0#kWu)l493Wq{F8v6Tg|jkbWdGG_9@flMNOR9;~9@q&2+IqtUVZ|b&+S7 z%dXgHt+U^H#wCd(Btfr{bk&1Uax5X1huI7C zC}@c(EUDA|B)^>oTZ#)NEosry0!)DyIpOw<7_Oa@QkcR(K`<>oZw49 z$T25&Sm4N~rd%EGuN$Y*)j{PHH;uLlb!2ji53|LCTcg=qow5|C_?u7Wr*l+_kK@Itz6PC3nLZ+9!ssz#6%~p2jb$RrpuEZ;@ zU^nmfbbG1;kJ>7;wN--FxEjJ8nK2wY$ARtEgfbqYg@PfCbHbNfqX>l$k6aLJ6kb(` zKg%u9Q^N|l8EMPFQsLm41Nj(Nh0pYSTdFe}3}=tJN(6x>cc$C14CiXe$0efTR0teQ zeB6@!`Q$Jv1(kz}2`9|xM?Nz_0A00KgL?)WKt*IRw{4s|{qy%V#eW2skfJ9F{euq! zKx&l^sf$FL9jytTXnRJRytfB#2X%_9+`#`J<~s5qbI2Epb^KL_;)6WYGb-~_O#mQk zlhm`Nc>ryOYm>MRBi;*y@vz@Wt{bw;#@yJXQ8 z!e&W?P7)gLuwrZ;1;UL4+_slDwhTrIk|OiAoTOXEII39}X2^UDad)v-h{M< zfF%imK5WQ~mnvKD(fvD``pHpc?9ZxHR9BfTSC9sD29P z)&heA4?46Km=%U3^`w?GU;_NhQK<_k4WrpuJ1Q!jAo?#*Pc_XNke7#WLp~KZAj=Qo z79x8~rLt1D$9`tp#4G#R zQcdDc*Y4=I3`TH@OFUvu6kEwt;`0YQ>G20*lu+I~Nh~Yk4kUPDIfR;u@h#J*GQ8#) z)yMw9v87zXg2N)cIM*viV&PAC#byMT6uK`qHb;}EyQcJcB_z4^won00M{=2{-Juen zlQO9o?@N!XlDe25HlGXq&n!BO6b5m&SG3r|TUI|Fc30*8NiyFZ|I^hnAsB1afkTEy&o3 zQk`nHSvgWPV~uMdTr1j37P5;K^`->Y4;1$N^00>2;Yx>0{Q~Ock74w+eMDTwMj>Ar zWWj<$un969X*2Bhjd2+ADub&$uz?qM8>Ij7R}qk2OeQY}Y=oE~d0>HWg0OnLN}Q!b zEg`JOY=8lu9Zl2b;{gEmbXJr@>tU5p<)*+{S3VC=R56B=oijOmz|VA-jZ7J@Fmd18js{1@($S zM$qZd?c1EyXIxxkmkR6xY*()&dcld$igfr06fNh-5%yHgV`j=Owu-V@?DIF3^5ay z47EbWLrFm|$WH^wm3+J1U<2bu7C0aJ&l7*kA^)7er*RZ=rfUy6TRnc!+0KQqA8nmQ zo{*@AzAPxy;PKc_WE1l*;n7`=2P6)&7qurwBGTF_Vh}NqLmrVg7uM5FyIq`eD)-E} z&T|2G*4|c^`Yt{AW^}zWd?}E$Mh?w1BMayhuTwd-gp`ya?{ejIX6`A2;LsED>%?0&9U8<4Ae|)>I~lOHKRAHuh@+fRK)?Sl)*-LXmVPef|_o z;&M!$`s4p7NOR9s9*En#>l1{ER(IbS%4|__>hzXFtMmatVTUpqAJ2YJJx-3{I!o>+ zB}S1hP7LGmf-MZXzaUq z+}P>|!+jlrdR>^8XQubJP7LwYit~xK!-w1mXB_#%GdyECzy65jrJHrCXrAO6aHb0pFdqN-nfkhpKrnUj|V||x~c)CDwuw_8p%V1L5U}0ktHld_J;j3N!ObYS= z{_q^R={Q&RLZSq81m5Sxb`38IrnMC0X5l@23?C;O!AjXZzs&7;Gm?tB{>60m;vijP z=I^Loj5g8&93Eq)B1xI+S^*tbiu&(wkwAZ4J3h^`A(C%kb+ougkax< z%#OLQgLEr4$*92@^SmUbqgW6&cRqMJh4l>y9B}S4H$nB=kQn9aB$=7{j!8MRmhbJB z)9hI77dzI+JGTNjaqr-9o`H!AYQbfng_N*R$I_oN*39f!)W7U6F zj<(>1i44KF6mI>jeqTQ45sNjj&gAx=i@2VmVCqAng7&`b;hDB;#~ppr)M6z3q|=x> z%$H|MqlA;$u%1MB;)xRyOg9WRin4pd1j!6SP%77V{VeAgA?FkNOkL+6d}aHGSobc! z?QYqsow4JEKDMn>alcW@Gh%4FWH2rf&?(pTuQ#s`slb z-7z%U_-iL9AFenWjmQoYYC%>+gQMSXD^=FbVxwu7qO_9D$`v*9^T@1SBb|(~3THfz zHs|WlB0WW>j%kD(k+ zX%t+rx`*c?PzOQVAWHnx%h3x7uSf7q}=)-^LsOY_QfUdRogJ3kMMZkLO$5q z@T+YkCM)w_vO!ik&VG3-!OXHcgDYYG|DZSpY!FUXN`TKdY(OdqFxKEQ5RJScm$58J z9=r1YUNq^@&B~K@sm5M1@h$=Rs^Vj)T-o`=;WrRI?zoGP=q2tkeA24jy9v1c3nsU= zLy%BRQp4@b9hU4H1R?>#q7}T!ddd+2eGK(*O1T_RqJ=wU4+%IroNj}qNzbwQQzDpvqixcVlpNJ2B?hM z7V_-b805favCp*71MI16Tv0Gghc}Zp{5bnhF}HP6JL3U~8r9!W0VBqmmEv6K<1%9W zw`?=1Q3Cx_0_)l}BJHCxn3n}mA)nQ7nSaXw_SK!r2mHQ+6LR7pt&jwDRTNI_&1Kw%|i@l~IfT{!_~ zAuW^YSh(1LpLE5S`1l9_x;h{jR7?|?c6dTd@R90_EZr|R!rruh^!}!>JB6QSs@!Sl zbhJg64Atl{RqjK>P}pp{%(`So>n9|7!*%Vmek9V73{J(b_+zur0|Gn5wVaO+5z>UT zsd|}TBTE+F6q{zMOwN`ZNph>lCSc>C-KO1z^Rzpl?QkY|=(MjJOZ9Bl2}||h!V91l zcesw2-Kt(%iOWEz3)~j08CY`R?b>yW*h5}9sG-igvO8;UFIv2W>v?N!J$>QnnTu7I zB#e1#irdsBPJ!>#d5`%CI5-UM>sAgs8wVYAM^_#1*+fcA)~Ea7}?t&VIqcFd&9_X*0MDrT~=%L81Ffwm)lC6 zlfSdVT{UP?8md&puKa&FigfXG>n^*WG#bchhj^U<=Cp!{Gs#`~{UCh6m&@wE!D8>@)t?7;DObw%&nM;5X2H3A2jx%9&MCPpbcsBD=%<)V}5+x@N^YA$u zAZiwKc(}@L6%^e8BT`^k@O8l?9GVUd38H}Dqj6;l7!E;zZuQ%aU2#eoT3i2R23h=u3_FU;%8rqSf%7A+=HH0Smi zNFtxVeoE?bm__=!=J+Uy{xL*M0@XgsT^NT%ybG=>+D#ku7?v~OGzn>VE*Yn&k3dGj ztZWjS%H?vP*d42gqFGQawhLic@N+7>89s-I{?C*^Q6!2KLIW z$0Q`=nxvZ~n(LOtk8EYk$7Q216bxqjQzhSuc=>3Bx{`Vr3Ck57n%&of!IOI^!PM}| z)HWPEp=w2}Z4Ixq7=uqd!OseBW1?@S%h5AHR8qh&372wQJS8E~gto%ja@TDZf<#Oo zE#kaBO+)&o3|G(7kje`OaR+95Kyr8ln*u|Xy!TxgaSMO|C>RGY2%1eeSJU@TSDyQC z63b1@Prt{gEVFl&G0!LNJ=WEP`V<#7w4_teRB-Q{$!U_mKk@>z^H~3PXU!U!%6T1f zhQt&|1solb$}6c!ri;1882#0V`%RLfX}^op)G5UJV--3YWhFo3~FdEgV9bQSs6890&(@MEe6g6il z9Pc8Xow3GBMu0Knk??s?^zRo)@l_MV2Xop)Pk+IOrw|w!vG>a2y@s0slII(`3nulQ zkB6i7VT$hj8B~sPe!##y90iPDEEl!f7>#Z)j`DYKp$X6w zSS%_~@1J9w?ysa+(N3lgZA>9BrbDzxeO_^5Ts9=mX@?G9C3zbNgR4uh^cn8tG!&y* zgrwBMAKk2jjyaxs{l{OBoO$UJ1Lyq5ri6Xpcri@gUPHl@$MwMIbCs-xK4-`Ei9KNM zkdq`yk>UMT;EB;g?lD1`zMIy}9?Hc6M3`?tHyj2h6Ols*5DEI7tu-1k=s@UBDDqTX zxeb92CE`ZcG=@b!GqGQS;Y8%VBP;CQ)F3Vyfj@IN2*40CM{;OXXYBAQ5RSNyh?>^K zgQ6*MOW}AU>Ff+&y;_mgqx^B}R*8~$8Q!j-AH?Y>16msh(^693PvDGF)6_Q(j?0c- zTfD!N14W~cwWPdUI;Jy9gS(oF*AeFz!FD$hV2 zzK-(gbi@>l$}& z+f%!xxvqK7mfiK+8l%FP0opw$fBn&mPfzwgUKThTqDz8ZSKK{C$z0g%j{aU~X&mt05|mBcmT;_?>Ah{% z_>-n+vn$K2)fj`rz2aCtd;Y1FYfI{~5{&j_Gaj0Vawc1fW>x`Z9m|uVWACTmDTysv z?s^YA5P@TOQ2X-rz*kG7PVV$CWO}>OW21Vu1Z(ko*l|U19OA!Q3pq6ts`IL6jR)LX zZIw|xGtZK{!V>&EI@%|yDEJ&-4=IHEJICf$))iDYPb{?=tx2&Kv)!OFiL+wFJ_;98 z0d#gqo7>~=8AVe8L2GSmenv~5Q7;Ql4vZO_o|`u|EzV!-GD{QPtm&aCZDnPv^qfGw z%E#y*8e$0W7A$U`q-ik6>O#Dtt*Js2PiylFiqirIT0>t%hxx@7MXtL`hy%j|6Kb=n zY73(R%Zoxxw#q0j!=vy%r+HY!F%cpknN!L1G}w}2Ev9H7AL`)|Wtx?mHmf^T!Cte= z&u_<~5W)>F_xJ!5Lsj1T;AO3t z4|(!@5=J>o3~K$zl+03kTR=-znTHfEu0ia)M%1nEL@JfVtg}&<&MAO5t&_ zv|r@b@n?^WkCeQUtwtD0QiVdwmCa=(k*V`eCrHUjfDTH5D)J;a2P_YqrI0OhbBD-P zKH6YcL@a*><0YAYh)G|>W|ae>y6(Vr#!m(~_eQh8Q0quU2@dYgco|wDaA%uF08pXK zzx3!(Q*jE8c#*;U&ftd#l>%3o0bsS6Ei=r(cJd1Sdi3dv=QB5!?9NAGfCn8ZfDv9m zNP62RjJCEC-Llc%9qe|0A9z-Ut#3n=5R-o|=UMz(iK@)2sk!dS*!ISMXOQ6su}-Og znpyhGyAGa3NW9l4jIU@Vx@X-SSvN))6irv$xS)n%JHx@3`y zo;HbDAEAuKx6oZXgGE+o-GTNNcD;O~)CQdCU?sVYQ|5c+{7l18MzZrX)jpFH6MNT+ zCc3q%%8YInWkOi5dJZ-A*K)wO!`-Y(3Yn#zMRg`K;*~9Kg+BS%XtWX%>s_F33^_rG z%EBjjkA@5Y0aM5Gi*ebYwVa;uB1QD`=e&^6{Hmdtp&=b&leTf5f~6%;!j~%g3s?$f z?7St(1WXKFoR z*}&pi{voOHX?{f+Tb%j|hSEnL=1ljBz8Y%qVY|9Ig{q@l-CW)?!cV$n%g%KNMJ0p9^fXr<^)=4N+?G%gI(y!^#{f>r;0&_k|fm6bTr|) ze*C{#`G*inm|+SnuqJ041Lb3);h8{j?ZEu>B=z-l4E}n8_?AhwVJRGQj}Ak_<)K!r zFb+bNLXqI*2m*pPjS4%GpNhl4$CzYzHV^1vh)=QcafiOmX&A(ib95t{m>>j{NSy85 zUNCKgA8h_CHUd3J$Sj@QMt3NYQs0TdJ^3MtJ%e+^U zC_Cv`?ZLMzS0FGe#5H5+19Bb=(YItCm&E%nxcr&mAl zX=hp~^oI|NnBM7X9_BTH>#hH3eZv<6KFkQ>8UFzTozBJ4Nu;q`59ecrVf2!N!$VIb zIymn5b&u_LZXXApO~KfeG1nCFU1YwD?bU+mjjAJk}>U#^~>ntinZ)=y?~ktxK9}=jIfnS z%mEZOGg|3p(hLO=aI=Oa=w+Fm{?UT6-TtR6G^&N~!&8(m+eO;-iwNXSm8OdqxyXim z-+^dV5}}#yYL3PWJYu270}FCEb@C0;Xdq?kcy2B}nO7+evD?FB?(yHgssx+tAz-~4 zrQZx-Cd7~^StPDr2DBP$nx9Ag6Wnve?t#YuQ-3jAW@eQgQPpv^Ki;|jAi;VdP=$B|7t03D_>Z5sbNhse6DDroISFf@ zxFf%zJFZr)O-!V}YHVm);rV>U^2TJvR`;SdHZ2_^HOk}$soWr!88e`xPS+7v0+$Tx zW|LVgGMo83=+Dij7ukA83I`V6Wag=6h?8GEEe13Y1=pae$oRn z?&7?#M4&X_zNyi={o*1!!;SC{+P71`eV(jwM^OJ1U#_q#&0c<4YxjEF*54!XZrr*o z@pOcOGMXzScNMC@SMBtWwB_M%D~Dd}#KSSb?J}Pz%(F0*3GoU!Tn8^$@>1vhubhXF zRL>q=JqeAQPvvP53jhC>zFh{S9uj#@s&!DNL1a^5@~P7ykxVar7~X zV!9jY$Sm86p>`L5bOOuKPPCxqt26;o0LcUi6YP_5hEU?PV-$*E3MdbFYPlG-CAHt$ z|2&Esg!7Dtqv*%QfzcQf)LjJa`zR>W!sZS|Q;a2a4E9C?Nl`e#K1w~0AtqU(Xgj)fZz*i~v{z{rF^iy$@EJ2$@(2Hm zr&4Fw!`wt4R`JIx=%GeQWO_^t92zenY$Ono*9+3%?Y`kwf34N+oGE#NQ*XA#I|3up zQcFW4vo!zG=Kl%u&ETh%ifM-*vzx|Ex|<*b>O0{+pQ3TC0doKNyzj|abmx1np|=-f zRYbc_6X_SZ%>^eUXEnf|H2(hPST}&j(bT&mn_6$_Q;Y| z)BE0H$cxw@TxmEMioV-do~EXaVzE>l@!G5mj}rl`Hw?xfCgU8FaSmV~;jQ^&G`!ne z{JZ$!vzH=AJ?e_J0>}kdMIciWx!O%lH=FJ8*n)WYUux=@V>8*y&KEqoPY@n}S|;lf zxyY1Spb{I(d${S87usHxIXKdUsf=B3c(*s{ZAa;S06LkspWpnhD0aQ(Z}ZxJ_e3Ba zZB^4oIydW_989Vb5)0?4)H|E+69k+7_g!+KpmoaTuA8Ol3Fv|`=qEij$I+sQI^@;9 zsN=biDo<2OBG)hTAh!8kQSNljdw`UBMS2AwrRuf1MrXV;zA+&oA>kUjao3-$P1`Dc zL}O`5X>p_Vo|LvqN^93e6f3lJE0*iNvJE&jKhh`v`SbBUp;7#Bmb-V#cFC%6iz0|X ziKXV8-?=euFcB%!j1--G60Jv9DmKw8n;l!U-5sg*b36BelHs@eu3J?5L@I5<@nbaE zRDhjGt_0h@a==Q`$tfJ;eG7y!K_9tW$0r*-0>e|1Ty8lbd`EDLUSbLjwBs`v%W$=H zk0UP)W0(u;itrN>> z@4fl$xnC2HU$-0NfBwy%a6tKn&0(8hP8G33HClLeb9*l?%cfww*evcHDmqjj|RYl@rM+2y~ ztn$xUWiMX6e3f1HIlFuby-a6^C+D6%bLvb|F5DwF+_Y%%qQx?M>{|MKQ_uvHHHaqh zx1?p@kYVvpCq=t`Fq#eKi$HQz?*5?gHd}AhoF6-W<57yA)|sXmq4kW|X$7r2%G0iu zhYR&ceAnzre=90Zq?KPQUo0QgA+ZR?GNPMeo?)DPbs1s?#(#rS3N5i+-45wxUTwCO zRcq@zCGA=H>;Pe21%*jrQ0|P>@QwNF(YR@{m$|XD;E<(Wh(@NdUq>WVSwtsST z_zXp5;M9ilt4+qHxehtujAo#ZW+vdE9{SH z!dxOmdOApE)=hpidBq|xBz)oc3F?s`WoOPc*tI1x(H~?2rc~Axc@p;NyhQSj8bsBDaAF`@dui;VOHNP;d;{FbWYlqn>u@R{6DSAk zat^|zH}YyDytA$R;kew|yF~I}W;32%E}~TTKHXlB=rOK)3?A>*v_36szHdp;htp;X zJd9}HNr7k*Y6q{Mf&MZkC@;7GykH?#iKpm>BM$Kw)cT5=;H5sz`~Cy{vd>B1(ZXmJ zbcL(Qdo>a2lBmGZLiFZ2D?c=&Z=9by_Tv$(`ZG9qQi`97Kp=lr=!55P33c~{hjP&D zBE0YtM^4B@iQn`94ArJ7EF*YqQtZ)^%lD%ZoA1h^2Deuyk z_eKl1kQ@gbcT3kjffJ4)9!$TVe5-BNropx|<2n;bGXNBP4JL5W7e(7^NGQs55Cw|- zMJCo=nQ0OYUI=?U88&x6PV&TiiIC-RB4OCglg(-vo}UWLW6akrfRm0Y|Df!cvp8(U z7#fm*MKmEnJ48b$s1pRufx@O~ZAK^_g2fh3_63YJr_fw&;M`3T_?7|SbEH?u_T?gs zPVg~b)+F-SHWYQl9RtP60%Y)A~10yaT0``cCo5v`-;&lnOg3a(?T zyt$Y|Y2-refIAkA=6s1CF%yYRLY(kjd(^Q z2UomuCo5}RHi;m3#(9#RyArtik-;9g1`RZsWZ)~fMa{)r0~X69_uZGaM#SLaYy%Pu z`EdY-g+ejWSF5W*|6C*a$AIbNt9AKqF10&@KJG^|jxmqTXb2B$D)_XSo;n#tJ9@UY zHS?(%6vR$0W(Fq1+^A^q6gUnk`(u+TH13}KQKOq5O0`hRocL#8^`W#%gn{EOV4;7W za+RM%KOvw#S5w@nc`Q5bEXw5YhAqI&?eugwo_Th8BcO{s#?vutFM@z49d*R^wa!vf$cHI=*v;_tn^1 zB(dxGnDs0|$BKvU6vn}`;{(3p+2Q5@Hoo(kYdXV?jdv$wNnA#edm$#Zdo8+|$Xs!bC+0-mTYMc$#-TdXXQ)^jnso8DrL=`9B;4xL6#bIgIBMXW zz^NTeF`PXaI&uu&#>1W`j8`6;GIfp(Vxd~g{MqVcD&*j53gu%YS+OUrdL`eCo_~%&oDQkq3Owu1R4ic`l@aQ}I&`H5WHpCC0sPB~ z9TKuxDoL8O2kko&^BEJQiaOQWi^tqK#?%L4sp`KM5kjKKd*{vP`O*qp+qPok|m$Pg#1cmb7Fqd*E0_d8`r)U>QS-F=6 zDDa#JD_kirzkTb^i8EIgbEySv-gbuKDQUBH*@XFNQhv%PL?h^z6XWg)6ZNNVlTz; z62ilQ0GBOl>ogR*w6p>SF!el^l?UQ7{3+N#9w|#p;82h(8-)sk2q=hMFghTN@^wSA zOG+zm_IBOuK8c3a=5E2F^7K5Ci;c!hCD<$|5sT>?zvd5)oI*V?g$Uc4m#_kc2QcpG zY3ODg>;8Q(Xly7>N~8qg@Ky@Zbpm-33V(xwtwxaX_vG~^F~zAMDP;HxDFoUHBX(p# z1mq{QX(nJ6y)aNn&7+ePQhcQhg2fUCVjl6C!}Q}B0)RA4u`ijo8O=?36U&mif}@i8 z8WgMSY%CW59Z6|%|eMrpvzWt>L@Qfo>?jD;iv_5U3xNf5~-d>UVRC!f-&isJ6OJ5`H})3 zhInp;qaL*X;W0K*Y3p-x0Ac_n4jfECBZiu<(%4dbXwVn~myt-t?q4J!2h_Yr;PWns zYix;72n>Sn$DmHb=m4Oq0sjDrPzZ2epT8TP%!I483^JaK{w6b(*X zz4ityy(lEu;n^hOd>nR^DAa;D2n|LCW8mQ(5JEukSNfDh?=>o^%2KCsY*z(SK zo@&$d)}oZyMJl3^Rv#jAoBa+J?}&gAVXMK&GYI5`p7vZMeKVD|A!kfbUeupt{&*C- zgaI)1T%GqlPwOnNR0tCLN{$Vnx~mq}E~t&CZ)9;FdyA2<_62w(=Extoed`7U==fY5 z34OI*lS=lS0;G3&SC7y!_fg0=KOaKeM`9yjN+Fj>NOm!qRLQt-?jnuoh5vb%6f~1e z)_$g8Uc-pTAtpR=C%|&mva_KkD5k%r*9_Bvf%0QCiKYFKb|MsSxHj%gj@NIu=9=4h zltg>m9XQD!rf@Xtu4T=Tj-_|K8ygLOF$A=e> zo(iK+n&J3Un;w*E2-_eyWsvdWa==GQTcPPd!ivasI*t}Yk6@xAnXc0XkgGvd`L0yE zQ%JOu`MW6siPi&_(AK?6&U4e8L|MnF zrP!R!ch+$sUPv-tkqARw{l^5~JD z(T9dzte2zlE!*wMMFoaIW#x4I!CozIAp{NQ=V^6cfv_R z9@$emNwlzF=O`~PAC1W__9(wP`PYw;9)SD))d^{AUyI58>J>|kcdd3gsej4s59#wZ zEFzDM^*~xDzKOyb$yi*^QzzC~yjI1#E5)_Gd-9m`ka3kNZuB!1{`nfqyh@#4d^a)i z&off%&-&)Zrgs5#8?33w6_&=5cWYgvtyZ9hsXe`5{vD}lw`!&08t&9!xmX}d(THUzq0Ew|U6YrFow6A)eh2QM1}JS1MF?rvJUme69U#m)w7 zYVe}}{W#^QeCaqnJBvD*U$9aLB& zybf9b(W4@@*i83z!_W)}3seh90iYcr4o?d%2USP9o^z82-VbgCeW3BSD1b)052vr{ zl+wC5SUNM1gc)Om!kQ4olW|Zn>xuio%t;?UqTnq{dn_Pbegip3gl)@K&`8}ZTpebZ zOkoWva+$P`Ukd4%RBsdDb=OdxGBN)FWIx@f!K=@hKiXv!zZ)>zriVmNrQgcw4B zK#O6RzP8anSaJ&G;1oRS>v1Fz*mK=G009HKKgs;=FHiYv1Lm554Hv!r z5iruq0?+wcZk>PNPqNq2CoTRaZm;fR8~Z^@EyRwx5wHirwrRsv-tx4UKZGiqKBZJA z6GzW>lExq!mUEx|@9V{6(}Gs5qO#_;#mA9HE;=Y;S?xTm$E7}`iA10iN@c+14z?DW z^pDA%9_&-;8mrN|g}zBXm{wD4LQTFXp+y2YIw>+c@xaOeByB_anYh&?t_=RTgkB4$OQ3Lw4vs-! zYsi@6PpPQMNu|_4atw-{nv(Xwteh4gflK>fC|mI_iNN zW!~mr1x*FT9|jLt^1OZ)7LOLK8)O482`i6ZyOz;6Dk~g`l7BgubuMD&GwGP*PuH(f z_cyJ*j$Q~B zp2)ziUR!snZPS3N!ZFm6%l+-&;^+4&6_bVldL~VoohnP@vFKiPa5Q<`<55O5f`{;J z6ruKen!j(f)6i&qew}0|BSi&_nar5FHH?Cj@T`Wks-{mZA85?krAx1@AL^xcL~+?N zCvAH1`F`L%{h>GT&gY%ay&RvnKEN?=w)Zb%JE)(+s2d)bF!+`IAKGeZ+f9j`v}2U~?hu(a@iJ@dkIZ^z2!;sBMT2t;i!pZwXd1 zqdmeUY(@vA`E$jM;BZe4-XyT(h&E>Xyg3&T!Fw^YW*7o7k?9j>Qe^`OH%W41VD8}C zLo2tuxEbWejKbB(T*?MfYMB?G9M&mYVpQcibkV9D3O2L!Ox6&MK8JQmNu3S+4=_p5 zAws0!vBTep|`(t2=nC(8TVNU1&s8G;DBo&zm?ilPN&;@08ypmcF0`a*oisJZ^^-pBH!fH13r56gNfNh18x`^lda0mD{3)%BCG_52LD+SF=ny@HD%~ z7UA>B$Gin>`hIl+CE*#6Fa8(xiBC>5h{^_(fVu>2(+C2^*$RzYOO#+rDhoE>Xj(HI$#puL96MnOtg`6gB`TA-3+Yx-J` zQ_xA=II4okZ0Vm246~(w;NaY+4N#@c(-Im|EYP_rRK+lpFRVYDFMQ`*P+36*5j#vr zJ%}06Teh}zmj#6{;87Jnm@Q>ZWN$fTbg$SY0Vs;et8E-~F~MezrbXp%ek^`Ud#R9_ zOhIm=EOBZvm-tvlXuunPIp*0M(_@#jya9DKi;^?W?nZ)`i@EWGKwtjHxo9R#d-<>E z!S3#{_#%5X75{kHGH54EA_IX2Lmn`KrrBF;6N=f+-ehCJnLqG$aK36?ru! zCY{401X`N2xu4O+xnA!%EjP+7P)EfaUm1(4O(8KMbghWNu)A1-#e2l|kdzQQI!Z81 zN#zeO5Q$3&-6vXL5Wj)0t|=}^lQvCQ9~N_x@kK)O`~~y0ghu=0>h>*3-A3LvH7Lm5G%2 zPjFq)4ZPkx--?>r8!9YA(YjKOsG7~~$mNi`Q>p_ zjcmK(%+uy+IsH$coIdd>C@Av`RdImH_l^sh?wuL}RF9TUqa?edA;{ zbm*JQ13RqxwH4Lr!loE%m=CeHKr*o}y)NZ-)WYftE>EqbZmu$Q=tsKYug^&%r#4Q> z*V1@51>9otAQ|JA6RZ)DRwcn?lo_tX3Z{Ge9|H^x@oQZguRGNzqaIO2g8MC|AuN(q zCKK9YCzj+ar}HET?6qC+zL+fw!_7Yu{n+gqw(^*Fg! zJFpGs-88Ldy%v4ekd(rB+O?%v^3Ta_Oc~t}iXR{Unu~i{0Y#>!dq+sv~m!fh^CFDgf%$s9@zYGOCFC!3D zdw?VRYHC!+b`ljaKx0tF$Y@`UsE++dQp5oLpt{d!TV+%k2_x!sVR<13-Sxg)b~R}| z^`F+4(8+QZ83wc2&7&M@O|37dIkesM-Ta`?LkTZ~%@qeiq?~cE{+iZ@Y4XI)u$GK{ z#SM*}s+`8)+xkEu!O!yTtkQD2r0F@wOPXF$kkfuXcbb+dDny^1DddZS!^#!)!d0%Q zE^AjS>uB0r_k0CeD9jNGMql+FGr#nEXr9rz@oV4QL|6; zPH0GQQ#XN~$HZ%Eb70{97c=G=9U8(-g^EfQeWLG!aI4wBrAnM&W3TBbSIL<_kzv7a6`S5R>+U8 z5*gG-uJKWcezd=g6eH%(%8?!;Rh7%4~ zk)wEds>6)xWwXy2@3WEv7IFm*S61?tjhYalCW+I~t=@Y87wB}ODafvia;v9Uqe`8-I-kd!n*P9RO1x;<%tvDhS_Sk<2B zGCB$v{#@|}eZ5Pu*^)J1e7$Sxkh7h|(q^0rb5iZ1=hdH@qSk{AJA2T`+}0T7gV#7( zW%E$9ONn>7clRq4qSSvpZsg~W$h|`?$H^A1XlJe8wp@ku|B+s$2lA-gi&oMhmfK~t zozh9;p|kmygdO6(*U&H`Y6_z_7XBLg>RZ;#Rgpv#4t*;0ES{A-0>twenI!>(6f`Jn z#3<{+z^6>!4?NX*IfIj9^&Y0?4j*TM zK(4#i^u4MJNP}bCE@PjKA~- zs^k9U<*S|d)63QyvTzJqKBwA@kMxQ|R*yl;x74bbvwHk%u>os`qaS+X%+ zP{HQolo~zo_C1vRV=sjSw_duO&F`7mxrLlBwYTT=-MwAU8GRMKcynDAjMVHfs*h|= z=T*atUV+9teh;b8ma~{*7Sk5ePIX>jc6Skv#@sfCcdSgn|1V=y;P-EH#)l0m`GDKq z`Q`XP>h1ig_$(iXj`jYCcx?WEb`e!nf#gB&u0sF+2Tv+6LYa0>QscMHy@u@br2|mM zOIz}Qb^O}>zIteu^Elzh8=lG4BDil~Y7mSsIp~Faz~qH|K<+s{pqRi*y*@azGuU+P zIo@_`b0y1ZonJhvF_Q1=%DAAm5)WBD$*(nmRQ{c>O-L&M(fOexfK->)`}HX7RDP5x zDHemjRyE5|QrR}r*=Kx*o@dN6<{2d&fYX#d2TMEB*8gBZ!N>k*vJ&A2&;(4 zK&xzf_sK3~%Wc?4vkaq^ZF+S%u|O40nCK5;34~NqsBIx^(}W>#Mzai4)opruoch#g z`&($1VQOys8|)8h3w+fC0Pg!$bP8>6#m9KEr_^L+u=Kmg3ZsJ(OcXott-yXi1BlJ!LEnZvCHLLo! zA&8gqLLx6(sLYC%ap?mGeFc1!wTTY1^i8`ub^ zjsb(3?NM!{*JftTkmwk=jUl&i1+W^s>v~_Pz;J1k6#5Fz_WrfjQ1WAP&-*awe@! zCvDj=_HNoNJXo5a=BN2-1sd{wury0UlELKoX%C*}r5eLa3-PXN5dJn6T%sf5lMx+ayvG~lwyUYpA4N(IX%@R9|-wQfeR}@a5f~Y)Y z*qY^;D-HMKHcM@9uR@WvW}Cbjq+QS%OKl~hm6vyUbGgA zszxV*+IUX&HTf%r$@<)_%*JPc6UG?Ghk<5WO9!g?Y-VC!IhR?jxErgl$8)L~*jyv4 zF_B(Yl`|G%bvC^=$u&-C11n(#h>2AYOfFU;fkVnO2eBfY7Ar#t-786&++MLbQfrTs z1(G~WGh3vp+~UDPanreMSSPVy4DBEbmu&k&M79OgjL;U|s;Gsj9cmBqW;#)+U<;NZ zN(~QFQhTsOPdPy#^AcoShLDXW5X8iuDm}E?Ei%ML!u?e{{~NrSu$PEU5v9tQm>`gM z9(}LjwpB#N0x)o1(#Ex7H(V$86u~uvyfNul=wNqB8~6-nfS3Z>O}d31zmQ$PXaj?~ ziG(->5i;_0TMM%gP%S}CU|W6i+8EKPeo;R*82Ix^-dOz>{Fq=K6?N2Tq?VySI*JF* z<;EG3w$-P1&1z_Hcvz?YZ4zisMQ{3cpx?tzL_afn@Cr6PlA?aM-oEhbuhshs0yFUp ziuy%8zy1b#Vfc>lU5aVQ4mO>kV1K2Wi>$3wRa`THqKz zBOvW9);RF<62Ry+VB7b`a;mf=j&`Q8AH(<9mN`r?6C&5D>bGJm7R(HIy&d4(K1CbY z#?mY?BLujXy2{tfV0;5}W0{g;)r(05FmHTCx^{2@XPk>s{O%z`wsC5A)TZ@EwW4x@ zumpBbhKboOi>Xs$+0QjNb;#$8bc86K^coy`8@HqA#_e%`)aJO2U5qN?{84^fH#vJh zxs!AZApz7*0@E+b2T%T_q~lyQ2qvXS)?K7D=S`6{%!cV=5`AQJ#J4Is9TmgL?@N=w64wSiCq_XYHv|K&jxFF zbw{8!fi474KFz~Nn?Mzs@Ny5d33MSy@_I-5DSpa^l%r*mEjFE-Q`YdI&lf0ANfb7O z?t(WbP5I*aD2Tw1+=!CCfS+*w(Nu!4m}K{_p$v#+6OFeWxGhd&0@d)hzK31Z} zFwMr^nN+D6(@!r_Gmr~_`88vr2@HG_fEyo#qa9qp8RaWQZ{;TvEhg4qR8WGemwVuT zsGZ0eYBc8XVvej|aBG_2%)vx2M}PLcY$J>Xi3+ z7=0s@E_@N2Mt?V>f1}#7Jf9(ZL~JVc>po6r*6PoO%17V!t;k6AXF`81oc{23$i50hEU45acBd5B6GSR^>vC-Ofi$ z+^6FnaM=3Q=pzU5(r6>tA#b z9pZ73Kb`2D$QCk~Pb|{ zo!}65jq$r@;(y@)=a#>wI9&y}{ILIjZ^}9A$>!eBtsGMLj-3B(xd6TIHX4`!0F^L) z*b1eZ*O!pc-g}#~kpL9O{fZm}03J6MkjbR*d%pl6Iey86y5R$!%?&~gJ_3lKF~O&| z?qgmK$BO~G^avm@s4O+TE(8mn^9_%wK=9_;)`<|3#U(=@olst9){gyH23gwpE<;&$ z1lIE9I&RXt&Y+{HBesQe3zJo7acDU9j2;kmo$3ZP2rjPI24Y^deO4r{mU)@2Ezwg@ zfd^r)b$2C3ARZBOTcpzh{_t1-4E&LeY-As1N3Bu>UnBTEI_J*hwY1UkZEbEx0Iq`? zY8b#Q?bNso;l*C@)v=?Cw%G(I8`e-Bp@N&BKLB?`cd%Z z=u22)GZKC+CW$6VPp*1z4f6|HlU%5%>D+j9!fmVOw;*5hM<3<;o`^?0qJOcaOv*~t zzuRg728oQTKtF0xXI*5YiT6;145MMV&=r-2zz9ZmDq`-5VHKAJEnhoB zC*EF7ee_$UiwcXdjWJAOvh6Xjl&zs+5Da}VLkRyx!Xr4~-Y&SV$+~18tRnqqDb0G8 zT9c}8qAP())X-DwxwWekXGDt}g&gG?YFbzc!M1`|c?A$4APj;sYOU25*0Uy~X;JH_ z=tn}|_c-~Q^qunZ;ow8Hu#+8he!5EZxP8Q7g3{o5FsIYx=W>GfKTu_crVGNfk;}s z42y^tFViC?`qBB&*A0~=x6?s$aydD8M@3-{`p}2I575U|S6JqU;$>kZuavFpW0K3S zZ}k243lvw6?R%`?P5P8+GVZ}4w4(I`v~txo!gpISv+{M6uXonMw)!f~4Q#?Hr#K5H z7L8qWuu$w=&*j?7+Go}31X?8$Z7J%gX`>tVDyM}R5J9|`h_hf~QSJJ}70Z~Po3C~2 z8DH4uh4Ug*KoGCA*rPoeT;6{&qJr;%icT=M8Y^*4o=Bg$Uw+RlIj^8EvJv4(a%6AB zM7*M=6JJ)xXS92yMA%VLBNiHZa}AR)$KK+_#fZl@SjnfzA2Ouy z?vcpM`r{)ko96ipxeyriY>hAlmk5MGMm&w8>j6xMX)k{lrrU|1c%;F9Emzf|pGdN7 zCQ7R3?3~;gPP;8_+YX6D9b9#Vu=8wpSz6bss<%KL2AP?w;Xrp_X~~Ms#rZBe2!;tjN!SW;CNBR49v^#Z7+}v7qx%?i^{i(?xTFq;mbefPbo) zu1667HR$zVdDKcL-w;|qs)f}(u3bi1lbE>{n4n(l7IUQ6QIwj!DOcWy)lN_=t0eRBw(*r zb9*mp|4&ys3&F3!=ev3uZh2)WhPJYoQtRfUhhFn3w9tOL)L?5cxD91UnVYDkpZGx&_p z_#8efHDhNqtHxWGwGN%xGnl!4#riz~>W@;h3O<@;*0SM2oQu#G`u5VK4wdiA`WLa? zmw1@2xv^1#5|n6(f(k0AO1&lxnx;6(_4XNzU<4yNqPULhxc-CJ5$yYUxWtlM=g|3v zqo>bnIhZxAMYV9lq%CTC7tp;eSR(VK4RgRGJwN>@_1eIgd-fsnBuCB_|^k%8q z(2+sL#AlPG^S0;KW5wP*C&hNE?4A4(<4RgiD=MFd?n{4bj0?Y>S+|l~d(@iVUJWsO zZdSTozxrYgl8drGwtX%(k7pFrB3?wWJ&uZ8x9F1mvXb^GGC@M_`>|h}y`GO(Q(rMZH|e+e?xqAn99v5~ zPV0f1coD(&-@FU6*PCPeoyyu*#AXw^qEcEB+r_qZ-$ckJh zQSW+S_0F*nVOjlNjFzsnG2uTN-bYM1Q{mdV6*0T+uyzk|UL)DwdNUiWC1y8IGos_| z;-yC2$IaTlRecLjWUNPE%+hlR5D;~J=XlGpkhTUXec!ji$M@mY>xsEm-d#ue&Qbgb z44&5MEva^6F!&0mOgU4*-~|gh4c?P_T0H8xR0tTg)|~G7JLMm+#OJ@ST;zIBdu8ae zGURyVOj;@b4Sg0Q@w6pBZreleTiPn7%k+&e+Nh{!78S17aJ052$zLefm+5oD z{>wMW_41asS{&j)SpCS}uKGQYC}7F8osf}lnOLZ9>KNcxHj(Gz|`#|g^&cF#I>YU_k=V#4#?Yg5~} z56h~=^7__-eufw~eR5pw(XV$FwX?KBP&>rCGxKjCId{ti7(>{N_@Vrq_&Ow7P4(Y7%aOoclNF&~a2Qx~J3o3P#2 zYhBEr!D-uk>>Q2*<2F^?&V+G4LFzDLBxAMZK0L2Fmi>HwziqWWvzaz`PgLPG#AHdl z;LdK_?+jLJOdHe2xG`<6&&$0ULqu)se8gYE!{={G}Y%f_0w~Z&rabnByxtyezca?=Q4n>j*l)j2@UoVeapvTe(^Mjn~ zksVPPsh)>*X}^CW2j`7X;z*)Q29<|Dx)vmceb>n%a)|IAI6Mz=BlchTrGKHx)BNXd zjC}L?uFI9&d7SWSe0*BP1D_$;FGr>h6S^k0aK=BmY%zt9U1SHbwzMs6x~MmPYl=NC zXn_wseow4pBpb3arc1sib@4fijr85NbG{%xCSN7#$jAt1&gq{wF+t}{f)MWS1It_c zL)9Vh{I3fzu{$#IAz;3Ft6VI*b>6l2R?OBM|Byt#Cz+5<5)>+J`AS+60MC?<_F$2u zfmjlDJ8ndb<$aoa43r%>=5{u8;;bxCKzwHom^FLI3P!uITQ(xOw8Q>PrKMYr82qJ1 z)lq}1upH57ly~`gMAp&?8jku7b*lCM4sBhTZ#(iCrOVhA3 zdtC@zsoy%6i9b+YFN?gfSF>muwmYVFK_b*L<(V8V!1*8-aP(iYwI|1=WG|8&q$}Ay z{5ZT%dqM(Xi&dMKuEbN1PS%2ir~29BJaiVlIz+UI;GS0Ll=)wtu`+!mcpT*k7)3r86$<-qtA;&C9lTtsz3g)==sMcq4Eg z&H2DFy6Ar%xIFj0Iq8GyIx2N*H5S%PYqgI8Wc-`_{1LVWNe4tg07PY69B%D@Nzmwb zZUlk?04{&jvH$?w-+l3Dr1maIb|BvafWQC%B|v$T$ta-zACA&Qz{I&ssB>a+xOk{%H|pc@Lx6HwEcE{>nl_ zV^s1H=MR(Gw%5pHe=>D;C?WKujilhn6MZ~IG--W$xyw>0;mDyPVEQ)VY6GjX;`}dL z691%pdK@NZV&uPk0r zLPizDRD_c9rUt@JWYcC|zOr7d$_*^-2KYEJ14o*-RPaA#!rKnQQ^nb8^!TD>SuDYP zVI!Ka%hmMjx&4l4P@oe=K1*)*@e2O*Z&LyZMJlB9(NSlC{bOfz^>}^y5Kg97+aL0FL$K2Y$eLsZw>s;nKDtM?|xE^47@_lAH_<#C+~#62!(Xx*Q#A*KV*X$=ND z^O;KIXr%7pZz%-u4OzvuU}^BJa#`I1x{>7~8*LoI>I5;FS$4z2`9>uIdgGRy#n|Zf z0MS6zD~R1{c8n5wk7GH^S)!*Q-56$axZP5W<0M<)5gfS(t3wy9>LR+iS-3vVQ5*(Y`--vE+RSX1>_}!uvQjdy zC#uCIadXDA3D0SJQud^?_2|*Z|3Pys_B!0RC)DF=x{}X=Z(i8~<#}_2jyXBu+5E+G zqKG_4c#c0hn9$GRA#c)9H(N&&`}lp?iItHRu68|Qkf2`XS#0onA~9dmP+qjnv*{r2 z(tF=$LKIiY%?WRq=o>cCaq}amF!Yn}e;(>6UMg6fvTQx7Ojvu>o0?ohDkq0;4Ugy7 zcTfAY&n9w4gEYWoTYwcA>@k_cwP`yO$HsC-%{~mSRL--G_Nj*4Sb;~h@@ z*`gcv%Mrpp%GeJS-^M&jHTLIGv2Rr@S~^1K?iccd*^Yt?u!Vg4qt^fbMo`JN8LxMG zGB%?0^2e>`Sd8M>5e`$Dw^#x_&f$|6hb;`Bfm5+JR%05D#DT&iD*5sYKClE9z`PiZ zg)x7RQ0cx8!P_n+HGuiOpiY2IJ=rnBA)*hH$N#za$D{ybV(@x@kJQ4-S5TA(j8yD? z#ytaxM4k7N)k`yQ+xUYp{uNSPg5Su}3MM>2J=%J9`+yP~NJSoANrI9jNQonnL#Rh} zT}lpx^x&ETIH|`H>_%J-|Dq9oaL{z0`;}<%#S@wZP7S9Yn~@k|F0>%eEy)wingxwD4${v7=#h;dc)}6$QRX=m zLJ@8`J?Lyf8!0bGIQS1iiY6kzTfIpw7TKJ2xOW`lFW=7OA|l);q%j!kei{*7Bv zM+STFpjZX7&{{A0-RLyK6OcjGai>v|?QJa4iLqcun28tYs4yR%!PM}G*vjKAzI^K< zBNEwEC;XU8pxn_S0CbPm2ILQ3Z|edW*_cWst1@VT-(V@~0=|dq@CT6|;IpC?T!yb< zBEEy)g@58IT#pL`&2T9GB4P)iubHpLVJ4o!JL1DFoQ+G;pG41LPn?WC_X4vPiK7j( zpd&wXOk=4tg{kYYNS`*hmD=>N6Z$%PBs9*KZG?kbxPbg_90h1A&-5zm@w+@zs7r`? zu+UI!$@JnHlc{xOc-Q-6S&U&kV$NX2#S&eW#WEIsa$`A@ zbw5^cyGJOGQ$`7jJy=MTje; z3-;SO#!ZoKX5)mLUcd6IBUv3>(10ZyE+TWKQ#MlQoIQcp;T8*2mT<1nc+TDwd=*vJ z^xB{y6OCB1xx%H~q1hZ&Ityizl+@%8x&s8!lY?e|+$0KKK!eg%c;X zPC6z@GXXNsQJ9?&^C?m4VOR+dd|r#vT>EbpTH2yY!@il`;%%}@A^ z=ac>oVHYhyg<16YQKNJqyAbO(ovczV;z0;Y36gPZ5J^Pm5m$&zb?H@`;SmhrP63)5baiuc^pV0kmeENt#~6P zRH=%C;4C<`9!wLP#o}fI8?x;k-Q-rYXRr!)g$Z!h^h}Uz!wun!2F_+a>h>l`eHY7j z%GOXfEhkfNH9KPuz1J50sy0vG>b(5AUB>|=FCeEEFj3X3qvO}g5cICkU#4MJ>oQ4X zcJI9}5&3>NZMxw!^t(*Irf+Dmpm$_aiD5B{VRnPFIy_u2Nk(hb)wj1CKUVs78LZ-{ zoI(msBygSj9fIICAP7Jy zDz9)mx_$XS>*?Z{OvFrIQKt4VRs*VD2*&rX-o|KG;ICJ$LeX zh&G`7>d?d)ytMAgq4{nE?zYF4p!=Kvp&kiL;jzy}OPU!uhC=B`SCJjz?blKS%$p!u}GUjjI zBvwwV+Y1KuMV4-=m-c-^3j)4pY~i&80HyAFXY$(xr zd>T88JGDaVIvk&z>p?>&5;osmyc*la%-%WYI4n}D~ z{=EUxeOKE;wR_!*v%69vq&xBUd&>h&gJQ++DXdd$RLtN=Pjz2cH*=9P`bZ1{^N2F} z=!yHK-;HQ?zu&~pbSWj!)9Xp=Vv**26EHC*Eg~T%B`PUi zU;Vk}OZ&e9!K};hfAc`1M6M12@M}ie!(tepXqg!OcU7u?TQ^(D(cR}R^+NF3??Gg} z;=L>4|CMoue?ombS=~Y8zmiI>21gn3Jp&m#N1N~$j&{p(!21JRS2=l1p*Z)>&#!up z2!O%VbpI35|3}lr=3Vu~891iE!O9kHZ*51*n}Jr1I$_(tj*->%q&MX6Ha$Dn&(G|F(Jja6NEDTFY!Zz!q}SUc_+~z#K+(L(Aa;^h z?#?RDgjeNH5BBD6CgjDgb;xo3_x#baVFHrarQQ;!4B#dTL~iQsncGlrpQBmDh+2jr zJp~p1;QG}^(oS&8%SeGam3WCd(#Xe85pyMYB(N-39v#E=6fwKF^V}chg0b{<-0~=n zFihn>4-Lxd6D&%ThsFrpJW?gU)So*OqRt%PgI2Jf8}u*}kd~un2wpjv)ljdraYy2F` z9>?PoiaI(!B<;im&C5-E8$Z47vxVutfPm;KFCL4#@^6ftFQoV!X1qM~IR^}q7g7sL ztl$z%?W+?E*H$AxrG6#(w!!^lKx(YVtDBoQji(CT(MMtK_P~qzf#gG44k7wbeLBDg zY6@_dZO@)9$&lA)_q$~n;g@5wFGc)kGSP$jIWj_OV;U_71M1s5$@ceMY4G3yCS>Mp zNG`RwQ*_93e&s|U)KAi+>}b@vj^+NQjbI~|tw^W1%~68I9o>Ato(hy)dc5IW3th5N zGOalN+_((NmMX~&3!lS0<wym&&yR5k{kV59 z?emD8K2S5Ge|oB*nfMbF?U){^D=MnS_3_P-+fu4F=A#i<4KrFBbBUvcMDi`f69z5P z>~v9e@m5Zxo%P1qQ?Za}V+?W5O;26I%2T$J;AwXG97=f*Cf}iN<&N5wJ;Z}FE=VqN zZj)AVMfpqfOZ><4BEZ+HV54|>9w5ZY0s`W0?rDqrYRECD7C{s8Z~Wf zzN}>4PogPI)8+GR>9alUt4&s1SYy0SF1D*$ zMh1-J4QDG7{fnbX{H8zWQCoC5K+E*f6qDa1UFiu1gDSc-eJW-k6-i3^<#Gu>Sqz%* ze4Kbbh<)W}ndrY}T{jzhys*t`Fd}L1dXyWMPqvq}vBx_+WX1bKFRA&!ea>jVs}oo( zvr=-ySgW7z25!!3Gd{^=iWy@*Q!;Y#EEi>*ht-#f=WdOxtk+aT@boZdKL2E!-=T#@ z*{g8WB8F7c?J_=SwL+IVcPjORAV4(YYH14*LY8=i5j_F>`jHHHgBqQM*Yz(T=CkK3 zA(}k=gvr{NG+ks3J4)DG?pIr=26t68YY5qa3)En}6y}`o&CZVX2@pNc_AO{LEmkNr z)Us@@Wfu~jP-{Ni7LsL-w$cqxeTuB>6!uR%I8%A3P}oSOY%{O%LFZX2&QSvIo1x2o zAi)M*Ck}^G=AoegCu`$zUg6j^gi0PHPJ1mOWV(vgTQ8l((LK=c3n7qPKQ|WwTHV^( z5@Q+Ec)RfR1;4iw>0D&r;#eqb$FrH7SEJr;VfF%BtmxFLA?tT<@kbqZCQ5(HpxUWkBS6%i!XV}KNI@{$M)Enu?BDnB2p9>M zb?P&9olxZ6Nsu4)hqNPLr|h{o75KxWSy)zKX~6C;^IPMS$ODGCX2lFkduMKm;BMUI zPocOeGU;HGZzDebYDE}-n@~3m0RCy+S7QZ*UY3VFHC7w@KFR75I=)|rdz17wiyv=+ zR9;_^>r588Jy%6zB)ge2lilsn9pn`eWm0C(mm$&0O;MBch{>pa4=+B$+FscQ3TB!P zPr9>T9c_f&BdZxAQ1(-bW*+&I$K@gWAQ(5@^#wbk!fmE#f6(BQi+oiYUp9{fgboyN zXFM?Lk;+^@$fz$P%k!Xfs&SuVhMIJCeEm#?Ukjni_$3P|J7%-qFOA+K4U20krWjtNI1bm!95&EQHbl5p2xRE=q^2q7R%(+B% zYLyvQpmDFiKwzD3bf#rbHcOI|hb@AG5_4K{y#dHtUm$c)*n`Lk4@c|QyAOYp$g14a zZ**))s!CWf4=1~gO`reh7_SQ@ggMmZD=W1V64;I*j_p)`{?*^59B-I|sG1H2mz#F@ z=NWzY!pAkU-Li|4i9|2oI;`8H=0lC7wE1gMKj3R%5kd$HL?557*;^F(XblN_y1c^O z%8nMV3^Fssrg0~>GvJV5{GWZKWo!3lgPf;w&G#&N-cR}fB-08e--oa(G)|V!gjI^! zy#_;DM`fRy_!~m7zAtS>NzJ#}Kd^lOwgr*co>X&x0oy;z(20|+Vp&+-OKmO_p@_<5 z(vJ(6Ah{thLY`wcUI4rcuI6?a);;$X;4kM02+2aNh`aWp)}ObAO|=HR`ButJhvGF% z_d{JX?3(3l`Jpv(PR6d&{a3!yKAt#(uladeCiLp(45cEB;&)f=K*#82dGzijecr__ zvQXsppU&TYy-CAf`y6Ec`Bp4mH@2@!_e*0SJSm!Xi2R$Z+ccXGFH7!JpT7Um8nuV} z^wAx4JtOP(YCHPisr&->-nE=xw%O(Q)U(vF1raLP9;j&Ur9qVmP!V&^1B;rtex zUD?(UoNpz@TaIceMVjs>nSxCO(>XG`GYc~FCbkT*L!&tProc-=Ca`i?9p(vL?PF2%-X?|fEraC#)SDN~IWJtp8#>zkf&Lgdghz}kzK5>M#_w)! z;JHK?{1pXrxY(PehUsizH4Sg7Qn2ibt$vTK9$PYdSKyoRn(lP{$g8z zHV%vDe2a9pP2KIcoa^I}Cqat(>IrF|jVdzNBhFWj*rVBQ-y2Diw3oNUoX>D-M*iwP zH16#11$I!V^~4ZT65GgV;eLPJx5kSIE_4*8m1B_k*Ae@z9O=M8YD=#?Aohi&RF2o# zb+^X5i(1928wZYylNR;0(YhlH+|zC0R90;%y_ z;FRo9X!(;8u_X;>&Y}2ptR~wy6x7=QHs({PD}cnqd9^VZVU^g97!|e1WRS5ix5p`) z-`nXm{spDx+dvPx2heLnzbjIc{Uz!^R$CxM#Fajrl2e2n#MA&-ILJ`4idoVaKWz{Q zVLi}RJfmB5fLw_Y;#TNexO$uV7B2xUXX^pi2=bp%6|Lh>NznJczJoZCR%f^3kl k|HSeuIp5Q8TQt)ZREH34ahbz#sjz?Nkq&LwO`Owz09BoDoB#j- diff --git a/godot/thirdparty/fonts/Vazirmatn_Bold.woff2 b/godot/thirdparty/fonts/Vazirmatn_Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b9b85b8549c4fe74517e6e2d5ec7da1d82563814 GIT binary patch literal 51184 zcmV)PK()VjPew8T0RR910LSnE4*&oF0po}O0LPF30RR9100000000000000000000 z0000QgDM+=sS+HxP6l8Ak9H9V3WS3&?|NsC0 z{~gIjjMacT0J^$qW>!_z-Ti|Gy0A#}2n>Tts-(&WY&(PRo{!&fVKV?X(tYB05*AgL2y|D&rDb1=}lZehuw99d8w7yg%A! zDMUa7Cy6}3hnMhQWJ&-s^_K7@L<^^TL2McN+`KVx?3+NiC)9~K#{JGwHANvzqOAA^)1fEeH7!OwGj_#~LUeFe9 zVdV`E>-9fzF$BjiKu$2zb(oNRaaYfKyULub7sLEA<1(*O!}s0WQE&lLP`lg z1V%-hZ3W=|M8?>!e+bc%oH3Y!AzGsIn(liI5prHMDNpmwDiJ9&3oP;u8#{vtZr+2o z`5z<>I1FTr3E$V=Z{2<0>@G2>?+_Y^aHv%Vhl]Qv$BOO!xS2n}!U9C))upRa6J z@8;_ifFmBjK{$$Zx*7LCo_2b|nR03efEm$Ex!Arbikj&>(OV_j~hv z=LI(48Bgq0#*Zkp1%OUbE5#Ss{KvJh?&b|7`GLUabXKsiTSUCL zEW!x>-c+l!Ka8e9QM-gRhSE7GlDKm#Bo08NS@Aw!Td zgeYl9N;`{&;WR;vilQ`kqS37NT0c8=M>A59)EJVQ@oP2fjCR%=6K!}VNG=L5^e#*; z2ro^YOS9wo@2^tdv3_FnZQ7>YvTQfm#nP5wfTOgm4k-^HhUcrB?#xowvlGqj{?Ua+ zfnh|&O|-KW&GDlPt4X{BLJJ~(?bYUX!W(qwDo;tEoY9xt@eY$rTqi(Cx?_IC*EBnXZ=?XS1xL!&vj$}YnoCgvQl9ys1?A! z76rn+x9^{H+Le8ClF~|D8OcVCkc0)$4tM|x!G_+6^5&kv?)V)+7|{k1gzBba`fgtz z{hSCrTlH+0qG*b65fPChi1>nt1aX$%N25B$4NS+igw_uJH` zPL@V2YkACyc0}xMcg#N5sb&~eD;l+_o`z+m5w+2z+STMXA*&j|);El7ZW`IuCUUGT z;&{hF?>h-|mJxKD8FGg|=#fCkV|mb@(*cE%Qk7Akz!=SC?B+@AmoXk|8Nc-!^hPG| z%_!CPlGNOfQui=P(_<*4r*S$L1#6tHQ0ojK z*dtaf2*LnF0Z0Il0D`ekga~&Z_x%KAQV@X8a=#-U_idVy_SHvTkpH#+F;V`FM?F&h zZTYoOo&o?100Mgg^E9v>b>s&N(Y*j*0uZF$GHqG zV>LB{018w%VyOHh2BDW$VPWIo0?-g^Vi=s9Jbb1&+z%N6i!got14ZCpnJ7$VX|i_d zojPopx|>cjce`ncmiri^9!e6-Oo3f1F-b$m;y>mhASR_ppPVTR)@;~wG{PtuF6*`* z7b1nu;tIqvMU6&hFx53!?M`=dYgb(z|A$e6VmLuk zG{bVbz5ZZ0W+&6RLb-;d)NWW$`|G-o)=InHx|kuEaHtsZcL z+r8(toSRN*Fm3*_jeG9c`_F$12^X=;T!9b@!nmrLV7w6y;NDMIeO`+`y!?p2Kh&P- z%Y{G}I|z<=13tXtroL&3!#_eGKeXoGs^h+j>te+lemha^{I31@w%h-{V@vrl+|m0{ zoAWJX=97C27jd~j3#Rq_8A$4;*8+jE-`ZYjV#~WT^io0#bcalsu)!B8RLp_10(ujp zxIbS}$1m$#%PRHmY-Tbe)cm#yRB&2ldF(7Bmlo<<_ zYLAPQxQU17yh@AH?r3tZ%T2i}_x=3PFTX{K63scza{)lhCCe4db<0g%Jfu9;Z+Xr) ze&T0-;a6%Mn*DFdwgiPvUAlPzKoA&>r`y`Q=NsSq$f zx%q{~rDgFj42Iz_8|K4eSPq3SrL-xd+lF)tDkX`Npz#NrXy}1~g^i0xKuAnNN|zo3 za>h)Vv0%xQ*BaJdUGPn-M5t$urc!4vTzMF8g2`r^!*8raWq=^TLe{lNyqRpn0S6s& z*bzq^b3Etvgt_FsPd@u%xU_cxfDjCUL_?9R21sH?tRnVWI?|AJD6`%M8*Q@L7F%u0 zzWp5J<--!?B>owqGG}tmlgoA=E>R1~e_2F=xTD6mNhiCS@t#Rq|9VV=y={ zz{Vpaq04|VGnTwItthBpP=`8oX;IG^FdC**XwH&#*=*%71qts)ju--sJ4@J`+I3eA z)w=_oHllRApcIud)Hd{CM!goSO0ffvR+goH!928TO19?Cl6Bc^l(*qkui-~JOQ+d?=B69>OU-DnNfbeQbS z82|wOz6TtIiG#lf002J&@`hZoQKOj9{2ws@w1ptSLTt9p0S6s&*bzq^b6l89-uvXU zFH5C(!L&^wSD8dHi&)-cEebYl*>T{LeSHq%%<_hKji9NSvgN8!rMl`Dn7Wb{0|W^c zVzX@yIOveWjyUR=-Y1{yO9w+Tv(Ldg(~XcRTdoRKs?Y12@q#)MsVjkcFkm!H zCDEKE>#~_OMxw^82@{4&^JGNymZkVc zFtd@1pcNgpcMezh)W{v!4%4Ex13(CYh9ar+-4bP0%NBbCb205Mr7JQTfU=uo*iI9x zG9I&ufk2%RwTi9IQhbYvJr#nO2XPVy%$wrIPb21R@u4O^(+Vzla{cfWRuS?)y13>-VGbcIE=CK+UMCq3AiJv`^oI2y{$|=B{zD+4v{5(0r{@51V?ep4a zc#<52x{izLDwUSIbmQldJ%CtAV;=E~r#Ao8VzRy>GqI4HoVmgtY5$Yu$AU2>E)V{daa3wR!chV*?!^?V$c}?Q@+Qo&F%xw@oo!HUdG^PXW zaM>w#fV%m$_U;iMxyVm`2p|gHyeEwKR0QiFoH@&2|Q) zUm!8IsEcXebZAd!?>$fMi#`PK0*efAYkgf@31->>LB{y4JX4-}j14{rUU?A|?`Re*|5iJQ%B9otOG zoKCOQbvSm6uFRi2M(%XHD&HTEwzFOAY7dV$(G+vcwa8*?thL?-8(l9UmKRW-kLtuA zv(?P@MSZexw0$gN^!CiT9k#XFs=YcrLPT#&&NI?D~nU8L%N_Psowb2tuO> zIfGnqxPshpxPv@!ctX5zc_WOaO`uJtO{2}E&7sYw`O}urRw4l+gkiXV;S#1R^j*ai zPTw_B*U8-=b(7p3Qg_MSBXytL15yvk{Q~{Q5ebUI5sk!%5R1f#5RW8?kccFSkb`Y;S)(4Oyr`EZD%AcYB;IFN(yFd{GC zIt=MW?2s(tlSC&G0PK`Z_(=!vReoA~ZxrlB|v**nrNWv`69$5)PMWv_ayO)eo87r>qA@@E(#g`2+O{ z@JWuJ!v8ehVH`dW`y$yB^$kiHme5KGOmQ#^%polxEm0T(>%bcFG3&sxq4j`$p=LjNH z@N)tZs1WFMNJj-iXF(P!96A?rQ9;oK4o8K?TI@(X0_2KL*o`P4xVAUcf zQLw93?x2ZR1<|S`UR6ZvAMvUtS~bM0mei^vUiG&K%x%OijpsIl^iqvaYg^Oa_Nebr#fhwRE=raqn37_#Wveix3u0k^-X@Q)(`v;Wlg&v49L7<~^hy1c}CzP@7ps!CG*S7zK-{W|`d@kP4-7LNc_kRhl(hOy@rOzIR*E5C{(dPw|r z(8Wmmg^SGjTaN4@*UxC2JU<6w(T8HWw>VdXyW3TibY%2pkb?bL_h7?YfMSC6)=FPP zbT!;uo6UFADdn=EF8Jt=2O@PQ$?i~BHDZ-cgPX&dGpWvYICrMl`6WgKU5GV@OXj+b za!1hWKpWNio^Y`Zyvda|^1)rXjXfW->BC~%8NTdv&-N`hmY+X$iT(Y=6<*;NyR`%T zwHqA-x)O(!IIzS)4&NM%3a*PUqTrS+S3x(SENIUSVu{v5?30E&W_e~;mve+saF z4d-9{Df@?}`{Vqk2|?12Uwv$NZGW}BysxYmN^sxwvI&Ft5y~X$uq3Z)sE?0dVK3r4 zcgepZo7L9m~_QEN|!>Rz8>8ou`H z+Sn$uAFt4jZfUDmG_&~z@SV-w;u)DK25h4?wC!Y1x#%65=p5x1)Jya9tsTl!;5pIHa@J;NQYU-Pxt|Ze zKPPk94mfb{clgeK)#+&r2mkmip6Kagjps#AQ3qz-os##jLps#6@U3WZ>Dw?4`;wz0 z{W-iNJdz{7oXamqH(K;4kN#;?M_X7Ix%0~KkSc0+tc8O9c)Qq3et@UTynG$MUC#~i>By_?(asZ; ztCe#A3sc^oOVZ@P0_HRYy;*n-*9IhPYc-Dewg0#-z3RM9fPWkO2qh3XzP)B8ulZ`d z9dLGSDf|Ezb{NNiMAwkPC)pWUJk0O7{sDIMyZPo0tXMv-zIK+;?K~aX=)bgb zfP1@KA-SXhJHH)*$Lbfl=yTyg5O{hM(t-b%l9RT}LP1xdIA90T(<{monXGjaH$=?M zA{JaFQz1-pJtenK_}8PR?j4}yWv_J{+vTKY?NQzpRdjQcxKxJ zn<=E4r8WqB;H`+P963{~V+G5!ug#I|aq?0OyksF(qrzVeT6J1qV+(<0<0bCgV7WagE7&ds6#@{@X;wfC z;+2>s0J8%M0{vLr`kcPx@VPXDaLEJ!sU4+9S=HS8s9bhX!vYQh5JLtc>RBZxrsTww zoY9hFCy4r(-~oy<5J=)Gx)s}bkO=}^zA!}%+gA)|T+`Qk+^1TdXFk>0d zL?*M4%w(5~Ik&WE{D+LF;&yjy8`{(sbijg#$Tc#_r4S_@eB}ZUkrg98P|yADy|*hp z>CH$+vzYXXn$&_4N?{EhbTUgKrBqTw14k#KXyQ*lTi>iO@;UW+Z%=(l^+5PJo3;#P zI7`V$R&r|G%yzUB6bBh(lwYLKlUivR-ip6T_dn|ewL z;%3HHf_e~#VF#D=i&C*zlGt!6#7ZK;>JAGE3F|Ci#=sk=XM_3FXTeocw92lC2%v2M zB#1|i6uHVNaSFP;F`7{7K&oLkL`K2+)lp96#THd!PauP0Qr+oI4^WCTx0JNoH-YQ1{7>Pph<5?G*`=m z_uqB7x+|S-8zx}YN#^5y!sJ%=lYH_|^=YHh$O|>6X?+*Z+=|wHwvG;u=wid}^3rpD zQ1UVJ{9Z8j((@u;{7Ze=uh58lBMIu2zuMOnjA~!U>w6;spbp)dgD4FG0v(ubwshbW|v3Pw0eZ>r!A zIAb|t!chi&Uw;oUh9&Ib3NHj8RNs;Gn5q?Ev8i3xc-tdvOqG+R-NL z_L|Z*tWsLs`>Ai)W5jL&t+uffJ&mnn@vY=q_IL>e4gDq|)?dO?RGZD(IUYW~<`2bGLmyF)W?87ua zC%W12c3pH%;%wg9CoX*ize4`gymvjkl7}5szgzP{3a3nG(ybYsZ#)gtWf}0Ez_yhP zIsDuXt}IVoV=bkx){KX!_QI}8+QhS``JUVZ6WYWTPPB*JYqLw@THJTxYDW=e?#jxX z6=*;)U>Tk4soDjt_Wz$s@q9lUeCa#JG_|4HHx$tj z_yIv>%Sbxg>gGAMAA1Pu0DS>+I=HWd@FWsR9oKU!gbZ3Xhw+}t7-P?*KC-NOi=FNt zOmOQc3>bwqGEI`qEHOIiy8>a+GTSWhTTAvBVkJcyHSfeMW-W9{>u6(xM?!<5E1=V@ z=F@GS#Fo|gv^eC}sQ_K?`ep6Uz7y2t_Px`AKfN{)?t$J`CnA)7dxqRik~gSdH07!Z zyUW};xB9&{_p_3+NlFv1C{3mZBTR3SrP1mZ(yk!Vx3~OX8(p#Kx=p6ll5>$KzIk$7 ztr#kjru{9MmbKP5>ZqeP*u8&>e3z-$fhTU(EeB>98p@I{DzUTS_Kn}JttH0oS*zJl z7c$s)NKdU(4S^Q^=bdg|t^6RIM1_0p)^EX}F@2$7ezKwTSre+s*r$b!dcyWt)Sxf7 z55ODtc#+ynNWN}++M+hMUesUZ>Nk5T_qnLvPe&d*SgfgxDw|c=(fImqqvV zb%TvG-c++KwA@;o?X=%fr(Ja2U5~x=-d8{Sv;GeWU$uKHS?%3~9&F4G__K`-yRC;< zRr`2d<0!TVEU5obR0cEaYbMuQX4J)Pe7#;w7o6hC!Ff{{j-|WS^#H?iK)+(PiS_g~ zTiR(pdz4*tiiE6Vt=CN@f2_0kI9Z|{4_(zJG4A1 z6GAZmftcec*Q4F_}l(l zK&th>=ec3fev#i|sfkZY#c-$nv1`_$7mjWDKfdkBq%^Sc2lxXG1X56gk(^)$FN7fpd8k4ghA@XMoB_cP!H7gWQjv}9jG++asMQcU z(C4Tr*{3#)3^X;l1*~BQN4S6ngG35@`1#-_uL*wM@RadlJrw_Gj)aJOf2AceImu5^ zN>h>Q)TJ>kX-`*rF@T|rW+Ky>Yi-Nhkj1QIrOgK-%ocWWfMcBD5;wTV6C&*8uyCWX zoz(d0Q9J>$6eyI4MJaj^E62@S_<4|^#3d_bX&$SUN`I0vm9-q@E+1hOu2>~2Q~B(! zRMl!wn|d_FDxgBp${F9%fzEWTegl&p-p2MHTDOf+_i3UhxEzYvBzv|$cs_#+zW zC`LWHXHKR)&VD%e5$7hHnQ&g>Fk|Q5z)6TT(z%5col=O?2TmR|ZZ+3SMbuylsO~kTYngHD#*2vY?dzx!50_$oMpsRA&(+5>^>7JY;;5jON zG>v`R=(D-kc};=6LBsWRk!{*)50{nNo0(nm!@{Pf0y7`tk~CWI5J>MRzO^Vf+e|m( zX^xqKv!r|`#BHbjUQo@{-taXs57x(&39%=Hom;6tKGz-6C|~f1m`?6Kq`WN6(GkD& z0*>p9t5qDkxw1XJ7`#cOX3V&?${&vr{=T;2m0a@>cRhTbB=dTf`3lE5e;JV~P+iH3 ziq(ANwaq-co07dHPp3V(s#AP_l0fGUF^Pxr2PShENc%dRA6dD#2g~Ix!lM0d^Y@RJ zYC%?bx@*k44Ja`!w9gIq%zsWX+;uHtX#*{bWz>xI1M57FGj5z)PS6MMWAWOE*vLmh zc>e6L{pgghcaPP$_G%I>=eo6>SF5ykN}Gw=7gEoegzdrsv{sE}PUXd@STWM=LVt&7 zoEsZq;?up@Z@HYDCTT&F0gHMW**`GhX0gVMe~S&@urPw`S`F^{@Spl2d{jgJBFWwF zg-$vGjZ{$20DW{bW}8{D@*S6KS(BLc5MOU#VG@yj<1{B8vA$P&I7BLDvTl|IT;q8? z=Zk#7Z{BIQrg`||O%ob+lf&1umBS*}$lF1Zvh3<<&n#29%S7(s#I}chFDgZ>v(H!8 zdwz61Blg&Ky(^nMvFF?Oh2jl`*Ie*oJoXpCv2&T#brvS}n;ZLuvSMwu>BMSgJtdC1 zG+hqOJ{tG*HY!}38YXH(#}YBZXNQrbh;!0LI78%Lv*0+r%UCYJ8tO^Cw;VrF6c=xS z`@)-lkL}+6o#Xv&A_dVcS=!*~nwO9Fgq2AQzBt(L6raZ27xaqf3}{+VKl^*$B!K3I zi{~P$Y^baNMb4#y(aPC4MY6n9fO(U)dyO4Y(&?mxK%=^pI!>6a9m_=dGm9=O%4d~! zm2yyE#FIoixfD@OEzNY&LqDe&W{k^jx({K+y*lj= zDHA;!oX#DWC1mdy?Pa?9@~Y9z5WC&X(}Wp!yn{<~ARjD*@Gd5G>LACQSd$pCTDzGH2HO@%+9e9b2IWVt54|D@%;6<;5pT@&&8kDf4=hb@z1|~!N8sI#mX<5zu5Sq zH{Q=*-seAbiiC`a?>uhN?jSa33tVAFe;*;E#Ap{HbyyUR^7wjfrutRe|6fH5qM}=_ zA0=5)HQg|+Br1c=6H4Stl~!*w*IR53S5u3py|cRqLNJ12I8j!0+x5dZD~FT$YO^~) z2u9K@FUqQJI$R!KAQXv%R3=}n)VUb|CL|yovLF`<9O)RxIl)PW8tzo5JJZ?Db-ocU zbg{|yc!itY<$d>r5lsv;f+%86TRPLD7XB!1;+D0-`+n0E=463mqPjq7;I=);@dDhH z4!%Ah!Ik8MJyK9lK}SQHLh@GHjSD(<2Z>&>#Hze_W+i30i-g%Pn|0N3Q*GOCeeXxV z>wf24Z4GTWk2>BLI0A`6W3U7wiA#LAW`yz4LyS)XEx;}F=^=)R@K@%yQNQB+?uv@7*^mAX=a8lhIzt2 zl+z!1(mA(9Bn}Z7ISaPvP`LN1IQA(Xitk+#M~pH<8I(aG;)ll3pm5i5aB?^=Q|HSL zL;iaP6-OQrD35eK>B#P2eeEa$nM_b5&r~_N#eO!(@hnaj3q?!fw8{WOkM<{abVWui z@z)OZz2I{1+f{4YhcxP+ZsR76!h zOQ<2qPY_je=~CzLBhedlNPi_s1FEy6stK~J_FEcKQomk2&zBtmL_8rR$-(Jptdq;= zGxa%0CjGLyP}$4F(DAYT)vqm7Aa8hAa;D_d4{1Jq;fqSuHonP#`r;XiXr)9g5?|TT zNWMJYYCh)`U$VbctIhrt5BaHyb{~Ope6Z7US;$*hLyAC21Lwn7;(TtT(a-=L3f8 zvjGAOKA5yh_LML^zvWS67mP89qC|H@jhZkV@Lqa6gs2^sTH{u9!O*RAWd&=8b22)W zNu-OU){S++LI6@I>mIdPT6ua~!n82^e*i+?Z<0dn)-kA^(>%{85dkWX;^>PL@s|ZL zZfTun>6yU|hd`iYrTY|5uvqle3dN{2ErVJ>fPlFi`4F?TmPk45@>+y_Hwd0{;r0ZW zU)%gt7QJyiPR1$=V78@IA~UFAB&u!TOXn7l-0P|&4n=<~vuHY}dHUqdR)m0$e0orM zi_Y9IKo-<6c@QY1m@+D8pow;R8DQjuJX{_4BZvDWkU|DI6i`A%BH5>&W?E76lk)*0 z2^=HFm4v7?1waZCTTw%9pfOl=T%ok2Nv$_0i+~&jiy&6iXryXVr%aoXE`4=OYPq$< zOUTO=9!M@QY@aQ^#Be*?b?dJ(z&ZIIx4F)+i;0tTh%4b28_o)WArMIvDxJyZ2qcQj z4tU@}LQ5JZKA}JD5(-KxY8qO421aHsP1hjIfzT~q8)CJVnv>yQ9s3z#j0Yr*zXUE2qhU~c*mm7i&s z0#WqmC{r3vVU$UlYHwk5WQDcdU+Jv{WOON2vl8=CYZumk)_TaamKcYbfXMRESRoQC z!eGT^tTbCK^Qg{Rj7k;iprs^5j+B{eoBqsZPm~`gxwFfwwa$9lPC7Z*a4|_8Ews`} z_pT5e0EzN!<~pm~*45V5wgD%DdK%e84b70~pldV)1CZ!wL>#U4S?@0iA3&qKR z{Oe-X!8iV{W092Tss(w$8iFNTKz(gwT*OL1q0w~Kyr*XjmTBLM{HK0IUaea(peO|k z4k9Gjtf7S7S*DME1{q?MF=mM)kt9+{BamD&P9NuEUHFzSs@?(aOwgDC2^!HHXo{c(7HOM!#OhdW%pwxHU=^Um&_MP9w^14e7h*OO9CxMULNRBh?6y4$zMaNJ(1 zy1f`Gh$WuA|Nb6w%_31uz+US7BUBL!Hr-8?O;Fi!=HC7%FeU6H0{SRaR{(O7v}#P2Hd4BL0P$f+}W!5W;)Y?B1S^v z7DJ*FbzY}>@PbFKg5h{o_KZ*%_0b(?;yZCssot({If?%;&UaT-yZ42VX zw&a%IO51ANZqMzyJvL@X?}VMaQ+E0;*=4(KH|*x!y4!d6?%OB#={>T?_Qiee4CfzI z6MJrd+<%?OTZJ4Plna^!g+nu-1yBUE2#SGLK#5Q{v>Un;+5;VcPD1Yr(+G3GqF``X zIxHWif-e@K6=4x!heyKW;7RZtI2Epe8`G}MhPi8?qk5UObG?^zgT2G;k4E4!_{jH5 zFyIYracg_nZ(hK&w#Nzp!lBF|?#@GT`k*zIK{wIl0dSB2UIeM=4hKNXyi}G3vodM3 zt!1du-pTG|2_Tp+WFl1>+{8PTwerBe;TT9V@qsZkNW*UliaoDf?bTn zBNJEvU^t=o?cD)v7GR$Pc4f!!xw<}u58=ssvL5_{d(xg9ATSpQEPu+M(jNg}%0(Mt z0O&mPE}GqgE>Yw5r}e3M;y?U11h}$4c#|W%`|P{L@9I8Gz1zQhM8E2T?1S_}c&+c7 z_3ANi_Ph-NyuEQH3IOo_Sh!Ku{F`TQ;QV(1FK=4O1Gu+=d--DQ;><<=MejwA-R~_I z#TP{v1sA!%DZGnz)~3f308Au+Nx5a(_0T_bb^cG^=0dj02|z+v_JBK`1N0zkiBh>X zT`sW;PF%oxSZ+Nz?^R#R$2C{ERp`wB5c>O8*>%{bN&eCpSFCU7D=+RHLG#Pm`!th; zrwCs4`bc`nyOZFFDTr=lo*$Uk`r{a6_9zG)g+%5(Zird%9`HA>3C>^mipL{vU!fNX zYH&1%MJ!*D6Mz}Ru9sNi8uQ}z2UdBhfQPyX%y|)qA)gruP)zaPuD!@o%gy&2-*8~~ zZXB6j9;};fO}KygAiGoIChrJ5YojsRsz_t#(1bAU|#lC!G02XF?`1o=BFH%xY2u zPd=APZifRWFZtgOfU4^o#txdLvZDUmvSU_t#wwqEvWdQ0H61FYpxcJ)u~DCf9AQ_X-e~qZ3(cz5QeRCItyd3 zaj;Osr$iZ+Xv6B9)i%I-_eg^VC*e3_UF|AgaH8+Kzy#>fj^rdS`N>UIvXg0tomR6H zp7Xqw@mWmHX17P4vcZibRDl_cmU~xBiBC#|{?1kY={ncC+BHCdnM%EuI%A1%E$eBZ zktVyZx6!^_G=1X-KbM44@`rOS_{${?L=cF;2;9o*a4!GbhZFk#W$?YFt$a_Q#Mc1L z=^T8PZ}KVbb=SeyPyT5e16@`s^G9t6SAYTwR@mAQc8lr39d{4MnX?P?O3iMbS_OMh zOl1Yt&7G9|w9p6QI~l1!7KM}^2^Vez*&pW^^UN+Mr_^wxuDmax8K|P4S$wPtndguS zC<~7v2F5@fBQKPiEd&G-wW@m4(070Limo_evA>9bC6jqRP0@b#v?r%v))S#t&8k&# zp2C9n-2*PuKOfffb!heTJeKu_`!^isUMdK_xsB$vB0XE7j|$TMG}yiOTlLWsx*&Ml z@YVYJ=YGRV?RKeo7+S+MPvgA1tpQhxh;t!k3EV@e?WDwrH7{jV zp?3O%+PtUK0^=Bl8qgEBJ0}uCq-lf2)@2G&Yl-SWkMF*$2%AaNM1>%ryM;i_M}ulg ze#X6WpT@1KXNl_2nDk?9o&iAs4g6?K8w*5jHYG_#iokt>m#c3tK4?WwSp%?2H>z|B zEkgS^Ucxx7;((9W39TzBQ=^i!wK~OSL@{(10+Sr&usW5RsP#M{g_P2dc$!vx(KWgq zf^U=LTBTfTNBE`wQ^n9bxm$a`ULA53R&`yLX#>F6G8mlB>q%Q~sinRJu1Ta3bPSPHiWuO4309F+RRnTPI1WmvSsAhAna{t%MS&kI9j)fF1IYDX2Hs zr|-|t+M-*hHcG!dhmk|B)g2$62Sk%uFtCiVkQkdFlaj;IdC!xTT0iibp(;3rYM^x` zjL^`wBD5b8g;z5IaQ<8*5)lR5i`N*>mo_rfrpB=xiE4`hR@rF-8Zd6ej>l$;!a9II z1KRR@Qeu?R8?6C11HlEiGdAF;{Q2LJ20Mm zQWKJp%9N`xf1C!$1%LLyDEpcw^}G!O4F-tuQU0N|c$q#oo3>ss73pdP zVyS%QG6ANRRZydP1%cheeYfUwB79UGIE_gapo`_O6Mn4yqaTb*2ZgQ)(2(7N@*98z zq)V&Vj{m`TpU!)jmvg>@ zHZ=vMX3z3tMe=Bl>|U`Y{it07hFC)hvk{NP4%8KaNiqotghx5kWjm4pfXhBnPZ9`$ zx96$zQWpAi-mQTHu_Mo$j4>pRo&tXL^q`cjtxwi#4-rmg>|sQKX`R>;Da}0e$yXH= z;w7$u!tKxteHo!&g?5fgCUeM+BRB|&1OYsktmGRIp9@J)vq_dgQL<5_A<3IG8swZ> zwK^*^akZGNs`L&3)`O?dD~e8fwk6j@Q3?0TMO)6&X4RROG&noQD*>7F&b-VdeMPMQ zMhz(XY8I0;AfwyH$Z8$lT}<(LRt^aVbv`L6Sfgr&$RI^ic3dIAdI_g^OC?8pK#OOJB-fIfq@y-R{u2hmAd< z9C+kEF;<0iSBMHFlY#0onTR2TI8BmF0Fur$m>>s`CZ2AbUl1v-5EZxNB7zmirjd<> z_HNBml8CddA);AgH!Ze&uuP%%EnlODE=(mTiz`j{7*jY^WWo-)g%5z>9l*4je$)>N zWEXp>FNi36L&>~k4!WenHI)(}$=-l79wLSqUZu`qNC-Mas4$EnDW=J~oWMdrFx#=89MOm0{{j@6^+n$&Q(j9j#R`5-@DK@CX3W+rh{uo3f;Kk7GSFf5^jqE-DrEcEB2c~3t_FnClw0#N=si3MvK3-|nx3B&j#RfX;%=!L)zDgu z*dVyN3Upt@^1~{DHZw}{0!+2AgGiU57q!=rM*`4E9jOtKgq)BSAu0}W^w6(WXJw5S zLIhIeOmP4p`}RdhBhsUlwgT$BNgkmeJeCE_C;^|yw~7HL!^fKnM8HvNKzEbkq*W`E z0Q0M>7Elkynnhc)=(TzH8pn}@ukRMMIMUO*HvoFLRD=Ai>?+dxtHC)q>eK20jo5CC})>hGE4_52mDr4V7xYHs)fJnnY<_L+69-%WjrO)EtkY+3| za|!j!bC_?PjoPMGgrIb?E5%{nPRN1q$0Ek1ayRWGtV`@`DO#@<0;;1eAr`K*zs_N* zk`~@NOYC-YfmJpHo*DSyW+}l?Yjz}dFTX%2vcNc*38epiLk)^qG-ASFWpcoaY3NSqnr6 zWg1Io-zyf#TP5s>?!0VwyslK{P13T}ifBOHc~fe!hto`PDl~I~H?KOYyWFtFY~7W8 zTk6;es-olq64q4W8eb0cwVBN`?xexT4?~yZYfT&3p;3IQ7Fen^!*+e6_=wes_VA@_ zLGyfJD6N{y9Ew{ry{qeVGNaY!BE}cKRsjp?#wAN>m;68gtr~ZL-`zOQdZ-r>ah2(h zI1%PTNQ)8~LQhfM{?t3ayICin>*b*kJ^I{hmgMM8hUa^Ol(T?HWOrmBE)8)ifP1mq zh_+r*{G99v4PS1=o{*<4=4Sasxmt0cJap05xE@SHvXytyD3l*hEEmbGAT3GmM5$y6eSK& zLgFr_NW?gx`PR6#ssgJns1W@+x{+*K0ycEZ0~Xe8V-66Vk0B5jN~^_D$l0V$I2b-q z#&RMplF(|GcqHX|Fz)fJ&<|UyjB*x`t8L*jQRLenC?_Tb9XiysGUKb5q3mR0Az|j01vp`4k!NYpyOSM_sHAnJ_6*Op79%0xMRf-i7JLF8V)xPd#9jz69|eH zyVf@*c^LzT_V5ve68FPztmR&yhkU3OYv*wp=zAvtPC$%1>P-ylAj>oZ2Sni#i4X*Zb5!6gMLp4sbTw+@=t55)%_# zzl;OTY!X*!@LI~wB6QFN!KmXm(6 z46HSsv0)c!)_jGrlNJkS!Xga#+wPZUK(T>&wP$zKx;m?#R@#q^eHKC?y~OM_YUURl z%obr0Sy)HLAaJ@ECLp)a8Iln3l4K-|Qtsk<4+9C}4IUX1yfidMYSCc3<=gVs>q<1F zWQq68TUZuGV+@ciD5SM6!XxXkK+z&B!Oi7PUi}v1Kp!#i@ptB|P#V36V2ba^O1wh3 zFUnQntpiRu<0ORFb8A$O{$y6#iL$6z^<1_b0`$@1;W*g=dM;0_7zhx(mZEi}I6b?S z3?{A(BWj>PE-32m!JJ?1G9%VqCGiHIJabnYqbpLwzC33k^3*h!27+>Hoa%3Fe(`GA4$>zCL%E~>+5C;1`>IA}Ll`Fz(&x&xL-t~>W(o;$vObEs ze)RKbx#wP5ECF6}_URF(_uBFwAca~z6MI1K^qh}7&qlW@$asY~_W47_DP}j1>^!dX z!V@1vTLdgCj_S&<4Zi<4{ot+G?z5i{+6@gMosGO+X%A`ObX;{-WXe>-3qi{++$437 zEynvT=mDk?`mju2IeuEFAGYY$N6Rd?>uf)IE4(5l_{giFCLM8@6VZ>7+ANhC8+ z=b-EJGuSPOi^aS=1k0WVh*bJKLfhueOdZ+!y>od)Dlh(APcgXQGTZWJK-VU-!vX8a z6?ePw%|h(>kO+hz;MI=NbB#@@)Y}#w#EpKLe$R%0a6R<(l6rGeRj%@WZ_>w1$LhnI zYruK&`e4en?A$Vy>uoE(GUZ)31hgt4PMWI>*v3mv85ggL86ypnlh6K!4FEy3RQe*=3|}Uqg68emsy?o!Wp0<7Ixl58DyCm;QJ?y z^VZ?SC9tPFG!&)VaHH;+Auy{~`nnDwR>8g;dIVO=Q>xrlmFC!wjsf`PsZ9bl3{^r< z&^{1HS~kRp%$XANkd6~0B0qdmS{8oq4VPeiv>@xFxzuz7(8V*f;V>T;lz;vsCp;r+ z9b|&K8~j{vAJH#x>|(q7D9yEc(zshSeMLztvs-1yIah+6R%-5TQh&$luIK0|)or$} z92IhH08fRmr8#M~cMHhC&P(Vu-w#jpQ=iYI#i}B{p^=w7Nh3$GJOkK*wTPz^^Y#bO zY%Q&Te<$#fG4=>QyX=i+XRGOwG7@#zBb~)ggG6`5iy}_9Z1dkh`#&^R_lBT1=Z|>l zN_tpgTE46ljaZjU1y&@*5LSAZH}URE)0sBo91Gl|bj0j}mz%94Vv1wn*`1ieXGF{l z8izx)x)tNeRckREx~zm0q4}6vxm%h^RcGcLLxD7aXt<-!?3kA!<=bbWf)2gH)w4Cy zKxH3pS&@e&5>7=@t&LK{uZv_&lL|)M#z>X+|MMexlNW8Bof4Z)s0X>dr|nx70JaH- zq^K+0S{r=FzJd9>dQP8vAlB#7?Wg5#leX1bWjABT_QQytSBa)${qA>&-)tY&x2}#D~PSXQfrmH)?RkJY2)=&Z7P^XRkqZ5d+>D-Jl#bdXzENBi$pd6;y?tn^U2P zZ*b&&Ap%R0HCs%!8j?2Z6zg4SRubN^oYIDDu_hX+E&WP6YCEe?gun;aK@g!Jb=0oa zP*g*KSY|X;5E8>|v-2l{2gkh%?;M;X^)-cunk2uH^BsFij}bsK@`Qm%7`Q+jf&>I4OsM`{ zMbq5df;?5)9+T^BXeHyH%hl5t&Cm^R;b{d)O$;HRvAvRGS#XMp*H6mrci+?2c_p6u z7z6|^9Z2`QWr@ZS*)ZdJAN}U2RZj7wfR+Df`j(ipe5S8~8m|;)uRbZU+gJa@Ub{4WK@p?f$7L%Fngate8nk!l{<0?G6^@H`2N18_g<1&NEWL8)M%OXz@ z<^w{o)v247a#O{GEk^tLSu}~rB8XIH`OInj%F0&uoQc!+x1c*f&=|$5rLsvx^S0i+ z)2|3B8-#$s8gNLGgq7Wb3EEq~`DzV{_qh?d{ygRrWEJ{lg1pY3@@bN5Re~?Lx3L=tfQ%cr2RlKJell!8>4S zCX3TZdj~(+m)etli5Ezx>7w`Gx^l;hkN(R+bdL`rChXXq95(c%DJBNdz=_!m%JEJ{ z5qF*co=fv&?0a@`Ghi`W?+Y*HXEpVfsM2c8n)zg@GK&=7cdx z-&+7sw8ERI>@^U`=E8A8a!!0)I8sMBA?0#{yROC8T~bpuyZxG-qjR%cbN)DYft8%j zjP&#Su!zNF<(pRI6yE$#`JaEiEY=Lru3ec06i~5vfKqP*9%*^E@1h8X-lQbdTA41= zLRSc*0wSx?7~Q=lSUONamwHc)4dd>S=4JK4nyLaL;-~xqv1%QmJaZW7H(hH;Oy9cgI z@r90cRi}Xq(Ro%4v};!1O_BDXjeC8*W@M)}IMR0HEpTD4Vn9_;cK+*W^}774oqXZg zeEdM!T(SHOIaMlMZNjxx!#9psh3LqP0hFo^s-hbX1&ChwakUk4A}OCnuTIv6TEUqF z9sws^ULG+)71lX-BADdS^+hoe&EN&>i=HI5TRtuLiACoErzcwJkmjU`YZxpEE^jh01{ZWgrIc9qOI z5*73ElAINQP?`xy=(mhKL0F@4`kmr^P#_CPim;}XS!s}M23iWuxTxvRP_46)+}T>? zkIJ_CZ$bU$$2 zl(`wyc_DjEdXM^h%q?$mVOD-rOZHIS8g0UO)1Szqy{@LfD6bCN?oGQDDn4BKckjn4 z{f*jg8;G`jd2|cHo$RpXAzsaWJF*Y9emOj4Ee}wXMOOi>;+J2l(Eo?5|3*`69bw@O zg#OK=y=ew!&f}k0w}F4(_JI>4o6RpxxSJ}#x+GXxV4YB*>JKtjpq;crZRRqx^1J}= z>SC@#)#e4i`9d1MvaC|oH&SJ}n_0xZH*5EzW>Ejk+b;)v$rt~G?q5e6c86v42w{$g z++o>d|2DrG|H+pzqgxu_;?d~ruHf|)F<~}f_nt6w1h%%=@J760w%D3YHV57{u?+Q$ z(F~DODWWO|y_!LjJ!V+(<}-oz{tFp;V&TERyu(vWoki*!#`~oj%w1!nfAAwGkW!f| z_|)+-*(LMyoYThq>-AP6%|upWHO__vi2kPm}vca;1%7>v@QyaXfx&2+Oue<<6iK&n^M32b^k!Pix z_;7&uq6u1jr3BG6r=pezk&S?)cy{&-5aiXjqyW7my<$*4v$y9;aNF0|KiEHD0DsZu z_1bwNw~=H}!lixGzJFD?&BAZQmsDwkA~ zyCj#7PoM;-7kX8&M*a?M@14|uh3PA5aoiPNSHxoe?Xh%-$R>=keWC2d@?P|`H=PC1 zN)cE7fqJmBv@@0eT-?pjU;B7Pw2hwyx*T@_}>L+k?r&GtiyY$&VCf6V`$jZ3ES! z24{w@vVb6uzRkshQuf}1_e)TM{=V>~w83wj4#E2kqT$XpQk}*d!YaP1&|u#+cJFIq z>O+=1QC3^WU`|Ez$0N^IeIGhQtc5L$!#4nFHtOZ4JlX~2?AGu26&EA8W4A9pWlVK% z1lW!;#&8EYq2(6ma9b}z9K#YPBamRCZbY2edCCkLnn+7l>xN11Q|8yTp zfG*v(BZF%%=02GJEc2mle_~8_JjSsflTN~xzF-cn!N+r+<_P7uA9m*_uMG&>zlIrx z?%i&C3KF>H8id9knY;A!%93cjRmhcr zZ{28&e*u`ieFF><1#LowH_-fF#*Y>}43>(MZ}Xt#labSUUXm9D9o)(vKIy+wus24gT*gt_bm~Y`SLV z*Ey;f=42%Hpr3lpV~pkwA+6{QB|Y4gcWJ#EM#7uI};CtKD_F zuZ&(tE}rhuaqh9?MNCdwzf@MXd^s^WZvFn8@OMBt@KPMeq4*ly*!Vp+mtsJ1FbDiL z3d~Q6xd6Ja+@3WOpOik*uH1$nPm0SN2RSe1EK3*-=yts&1?V5?7q_0p8_-^6vK(eD zuVf-C4pcC*ET+e2jCW5G;b_|WbB#VZn%Fr$4l36PrJKiHR^KCH)>+hBYt(>|tq^9f z7TPbb_1&>M8|)j==6Jxq`H#`78eQ)9#zwDp*AK-~H^uA&AD)~MTCzIkTwD14*z^o` z*7^M5kCGOjbG zM|Eno&b7ck<7p<8@UeU&(0L?!-@hk&5>Lsu{ggs1MOg>zpZ{@P%2bS%{xW^41^&xb z<2aAd#ZllWCoST>jK3}7HOlm2=}x{U59;zC#1&(N!D-amNg(t9M5G4<^aoZj4Bej_?JoE}EXEX@Wbjr?qwd*s2Am^ny+2 zgeDAB2Zcm>IM~R-ee_}lw-vT}ni|jhpL!0-6ni)m1BAV!9k4!T)*vctg}bdld9`tZ zD#B)@KcwXLoJ_02`;bhDdx9YcO1-s84~dUR^1R*Ti{j=b=CVAfn=Y})3CwswemgTS zGe7YbjOQfmC-sQ*VE2J1qIGcWt4!z4;0|=+E$QtH6i`lNVaQ(JM{ME(9+$ZA5!<&X zA`Io2-J99VjLLR$jmiNA0<;}hzTp?u8`=MFV;}dLUX%uBjPvtE8tZ%d0(XD1%xp)& z(Vy*4S}vk59Cggf&JuGn6B2J{5&@EvApB#6>E-S=%gdD?a!v3WPaod^&tO1jTxMyz zgUlp635-0sHzrfrUz8DMoTVFx;WmFN3kY(PuRI5?wDT-@GCb}T7%j9%l+YM;K{z<+ za^}j|`{*hF`lIm~Bz954z0@}*FC?n|U?VIPm%oIHzvl;WWHvtcwIU)X;o@7AdzZGH z>bOS#Yio}4ry4GmInGkYltG)K0kN=rYU@;X!8lPGPRoW+?c#hq=;9%dA za@#G^K@D4eo^B?{&L+5Owe&Iu70@~^KY(e37lG`I!=Kw(dz>lftgs~6dAErNPsXb2 zFM57!!PxR-EKv;;l^m{fZCrC+xgKTtxLE@YUVOsW)YsC7q>N_-^(od{99LW81};hW z)Auk1q$DVK4kZ4FY6Jp%sVS(wrX0;D13GHW4|m(=*HxgXW+P5$mq8z8ufjgsg+^TS zcHzdGy2&=bn~LDMg=9ALQ{sBCb0NN`q!TNs7ST349N2t1jM;^hZ}c!(w>VZR@j!Z1 zFwOM0jEWOd&7;3$I4cjK?6X8Z%(5sbAaSdSB&qUOmoS&SK~tG7tklD504Mvc|B&9DlJ6b9DX@YkWi#arLpr$|l=zK`T5TXPj(N z6-@a+MXjNPS}MXaRrI)LFTP#43aSPYSK1_0%(#0j49ZSKMs8Mx8Sw_Yhn*I+OxV8@ z9PekU>vI;>OaJeER5~5!#(#gZ9|~aBK-Z_g|8W?Gvj~@GQ1Hb!`?o@%I)t{gqv&b6 zHkk&X<4S8w>y7IcL<0QVt?2~KbhNa(W~PSv06ikMfSEo5SKXWa0ROWvpgQ3#R92#_ z0+_A-C*&tb(i?ZKZ-A<=ylbGtaiKIo%j>MB5H_3VWR+7)?0Xb<#DePr`!YR)2YCT81CYvAVBXFp$dI=nA zJf9R0iMdz+XmtxVD*)a53IHzERz9PZn}w%8t_p#;(QnJR$(Dx3sTSNaT#v_LVR_)H z_}mXl4XeZ%N#y zD(vlUaa-nszvC20V*zu#98#e~p1j5}QIx#eMFu$AKuJ+a(GLbYp5yXY1Hd8LM_maj zhNONzt(UezNiRJ=ivVT#fVmk@EYN+r_NF21`wOR;oC6iEFLDHOTwl`5p2_v*!d@-k z^cL8|0_J!+WCffqv2q~C6?9x%TwT1+BE=4RzncVTs8oZ7LNRijZczKCNbOQns7Cd} zTLsd-fapl;mrm66mZ=27#Le4)2cdfLK3XAIrDZe=#em+>c0~~Tz;>y{O6fEkkPKY5 z8p1+8UIg}%5>%L73=i4XPqHF6$y9b}GFm$sjmJZPXNhb@y}L7V+rfK-PD%v$0Rn;* z8a9y+P8Fcu3Jq|%Wvq4+G0Dox^`m9T3KCN;&Rh%h(U@%>TVyk|85n~7ebkI_ zqx&=WR*pBrnssS`)@)yt-(L&lgOoIBx-=m(_maKC2R_&f<-AQW~~Avk?)mNOtie5J=56aFer-*_(hwl zB$BEsF-I!JQnZ$cX`6P&c0w0fDy<+Xl6+1T0j2a5kxK8#?opg`Soh+(wqFdfz1XtV zdv*DLkAxBo?E(eg%wkHkt%x3_2QKR#T>r}_L+lT?JPZ%Kgl@mw2=&EUjJc(1mEj8U z1(*MFtc!W8cDI}J*@@EXNfoVh_pq}Yn<@Lt7kGNq4VfXWKBWC&YS(QM^`-u zZm)UVNR-T$L*71w6S~A(LAK0+}Tt&CuwoQP^DuL!(`#wAjIoCVhL; z`X%$e^cC}#^^w~8arX>%hP+#7v96gmZ$I_Ez1dOfwN963)QxL5Y8YXOIC3=xO(qkF z1aiVbgBl{8CMV*t3Ob!Gr-Q+l*n^nCOftrWC#z0sXp7OdotRE<3&w`Vi0RjiRG)KO z$t0|lr#Z3*I7D(D70BT+nC(^%!_@S`M^H-P{-pGUDJMY?wSj4)DC&96DqYp?On;B{91Sm7 zd$Eb-uioG1^w@Q+cjHa1cjAFQct{cGP;~MJ%6i&mqRRF<)-AnORyFCO8{W&$_*z>4 zsHjm*Yvl<|w!UD-nEntKe^Sw~HVB?~kUxBE*b@FNyEz{!JN}q?zTb}Q{YLU0!P3<{PLmgu?Up00m%C3(oZQj@nhuUg+&>I*L zOp-GzID7hdU5k8WoW+<95MM=ruN2AFC&SAmDVUc>Nu_#2|B|5$4XrS(K_X(p-r|J=3VfL>Lf4z z_4m?Kkq@*zFyb2$)tbHyJr3n7Y&?zAaad^q;9R~`wHAH(<~#AFtT7pTZh3wvNVD)L zY7%?PuBVFfrf`7_MN<U;ipj_X@0=SYRo4Hk<1Zgww}{N{&&4N_aa}8{>o{ZT zZneN25CzpouEQt(=BTAvTI;TRckH$BWnFy1TpFmA|J~I1fH32tNJCvqDZ_ z_J7_eIk?u3EG9Xur-AZ9RG52q4LRn)j;LF-A*n)Wi!!-(Klfc}K@5KH1E)MS0ktr? zSWUF=Y5N&5(Dd5U(MhXm>R`b>VGu})FHi-Ivx4zal^T^qtX5S<;j~h*NF()erK^Oq z+~X;-{Or>X=M^hvLIGcf1tXdB{NKBs=reYX?TL(JStc%-TAp1_m$9UZau?(9fA=@7 zW}w+ByRVbQC>${hTUf!AQf2%K8=C+XWs#sP3{@&5GNrYEhZ|ggy$geZRO2}pK2&p! z@m=HF5LJxr1>?8^E9I!k++LvgG|oH6`)pqp1j=fhlKp!k3rhAkpX{6f zGp1U?qtjWf7B>yhzHqb$3m+ezqpH~=CzIbDm()eixpa@pSUc?TOLK3{M!)s0I>>B=2^m|36;_&ST0Pq&|H;$Km6dutkzwP}9O>rN#FTU$)!N8rac$zV2^Xj} zQd%|7Czcw>uP7Vv+hQ%e|i44*0@wNL?*R7Vd za^DvogO*kS+A_y#DUT+pOq0jIsK>CRV-N0;Ey$tZ>Hl)sg@A>7D6p0R1%4DzXA~)h zDqk_(nE*uSO5@iYf`vUSTM3Cabj-no;Ez7m9G(E%0s0LGp&};jjH$;rD;~Z>;n$ z_AdIxSP5qPrEn5*B@vF_Vqwy)x6Y6hF?YDxw%(c8 z9}*sl6jK=lIld)0^f`1eT+9F}F$Y`vS^)i=Ce&J&XXT}%xO()Of5Ms&8pE#0e2STp zw*Uq0luMZ_>KK?Am@Dh(nHgBB>KIuWSu5*+n5YG(z-+&SCc#(I)J&!=b*9bMqNA0A zB10iE7QlbVY(@RbZ-xD@YkjhP3-t>v3v~-GWv^|?zm$HtQn%6)eaE-ieWy9RW%a2$ zA1iR!=GfkyVeN$%#>s3v6jxO!?A9iEB~<{mft#im04Kz377kKYT(l3&^>RnsuD8eS6%%a zDpUTGxW4tKEmlc=434vc%=V)K6| zuWZU34|NM2|5n>MYa|$Ec8ZhJ6o^}6#M zCiY@4Sdd2sd6pt*-1&5rj{%M?aystaVPQ+_QDKPHN7nU9NTfl92DsdF)}SPOo>qcX z_eg2ZT9gd33;|&OPFd``gL6>)f)$ojNt&~^f!80dylO0F3QS&&ZRnHRXCCQ$ZZ#fr z$_7uWCY`Wp-Fa9T`_6LzS1_^{f{Kch37pt@<4Ae-8ea*Yr;%i59?4$oQ;PkrfICcT~d*ON?-syk;65 zpP`YIR&TP|wm1GjP*HCjo?e99%jDmQ&&Sv2=4dJ{bJ_9g&K9Qa%MFzB3Au7Wm%(X0 zHSw^%Y5ZZ0_0(N!XdGL0{ckN7wa6qKm9u5f?WDq%?J=&uFoCqP!T(cVs__RRS6%F8 z*;^l8EM;v&;2nQz-OoZDTsOiSarldM{M5d^mYdyg6Y0_KPY`G|*)zU2TfGv{Qd?Mc%#f?<8pz44 zwr%8^>LxPc9E)tUbJQ%??R;I#DybAySCW6zH0T%+qI(&8=2AyrtRe^0)(NCgT zPpza+T>TV5)q}mKrjCCxHs9GO|MiqT|I+s*V82XD=@9|Gs}vIzm9q*A*dllNzP&S? zjT|-(36J_05ZfaEzNeQv4NVpLzI)kl&RgpyVNw<7HIIqzr4+mRByhiT2~NFTjx188 zxRG(FR!_%Yq!3x06FH$TAURKezEpEV) zk@InK2Czwh)%*pcAhi+5p>aNe2BfR4u;{B$&5$d2Nn;O}7o84D*MHVG-EJy78>|x!W=tVHJZ*=p|H~({wV5jI|Mn~l$57sWzo1oBpL_U#Q%3@g&MM= zvd3wv6$xCm9FEH*5H*<^+3C3S^fwYxZzLpeU|d>3j9+mrEc$&reYa9>+IZh%D1Xt- zx&;lb<_N_!9=Q-HtF%YCqdv5%@4cyRT)*TvTKP1jez$Ab5|?N?Mfr5-^};^=cH=96*KY4 zfMp?YCs#E#aqxKsU1g5sb&?w<=hk?IXxKU%Uq~52ySn$CdT#x~xpN!p`=|9*&&Q#v!w@R!U{8aD zrLJZ2Y6Lu7O(7QumxznZG6vTfh1-5~OGUSNi80LwYO?dDs@vcVxY>2rah9|=WEG*H zp z*vFI+$_O4T4Q{QcG<}{MoNG=6RlB?yAP%&w#c41&{*5A{zo%iGhV=nH^UF(nAEkR> zXiP5SKTVLE@T5At-mVmCEJjXK4Hwqx9o$0ozhZrU!>f7!O+ylo$ zt)3_pc51UIYu$~i7H?o9P&6sf2Rw_Nv1n=tIgG78ow~pAJ#XT%z_ZH!MWuJh8M_pm zXNLMRvs%;p+yM5=y&iWltGbZJloJ%FLRh_L%_GaETmO#kbhdas;dKek{o$6bP20A^ z_S+>h9l0xf;3xw}R3qS3@M;M)fYoNe4dcj4{6$-OUT}#f&=0|E#{03h3cC1f<8ZEo zWjmcPZnjFn%OblWqF-26DNHLNW|xC7jvsRUJ90V4{~ituOWlmZ^0VnVB`J#(+UQL+ zT8va2N}MCeE=+-gtk$WtxhI2jfl;k6nxcVPOoiiMISJa-mSl?DO3kH1X|Sw#JJ1~} zL0k1So5AQ6sE>AbIyVS}CDio{6b@tu1H-ia{iB(UU#wW+lz~p?sxeqshQj(19~`9B zoP3#{DJIhpOE0bg!pz>@3i+(cw3=L7SwvRUN$L$kSaa*~m%*!!|DUXJrmV=$K(Wsc zgBzdr_VVwx;hb3X&de$%oh}lZC@`z#=;P3ljkkBZ97)4@S%LhcbzrEWF?djb5~C!F z$qZIhL*etUJ9ab@N}AGRqz&Cxp{)kUAj-2pIH918lwWJ4pLsO3IR(AzBVm!aT1?MB zs3xG2s=8ZJ7f2jZA%9IG+cqrI0SG(!J7A(BuR?u*)(;D=L~BB|=N6X-B@IJef50rM zYT=|pP<&!;(QsIG8ak~`#o}00c53o|sGtW5Z%cyi2T-w>KMP;svk3V98?OZXqWh55 z9LPxuAF~vSIV!nHK9%z^LIMb3*JiD=P34~_SaPg8uCB^W+55{Vh26%#QvgDav`Tz2LJI6yR z)mf&jnmBwCw3m*%?bx1qQ4r*?0ZhA$a?yGLAHcDxS1Ne9C}pa zP>|J`Sx2l+5hVIKUw34@p<7nM_|auF%kh>JGkGQ`poPzkZkt$c6qDo)LZerEB4f-( z!2CU+K#p+WTx;rfNowo3i|&QQC?Y{rY?e6}(`_Tv0wH)x-B)w}*R~_XmdT|dMX#ym z+pge*~D22gQ-^4emQVw{+SX?XJ~ zsC*8-xh;M}_{2EM7_W-h_oXli*>l$~<9`E=sdsheaUaQamA6jQS%l4Jo~QE`E=EeL zKvdh6IR+l&-qHx;KSFjz`B@ULW*!$`y7@o535&17>TrnoRSLECTi8;i{!M@;`VaqG zOu%k%2z$E&#c^D34^fmR@P{gWg$Jm3s#B%5VN=*M5pZc%(1ok-4 zDvR-gX$;d!R!|_M{QZ@}rEiq9zM|8tVD@NdjR=@@~J)2(-raKVm&F}=E$y9$08 z9hPsUpoE^jYF9x z(0@Q_n$3bG+LExypm4iz9;~wvN2#$_bSI(xiF~#YE-!z1h!tCHyjr_m)R@cm3Ylkc z{Yb!4ajQ1Htw>68NtmKzFE!oBvQhzUgX5j1(1jN9dj*ptKb*;xj4Ciq{ zjQ7g|9HpK#H$sz^SPVVWlpJ(l^&ib@y7S2QL}+4KW*|ncwX_0C6+-2MY=14ztMSx_uKKo-6BfWyx*lpI#Hi@I;)IqyAo1C3zYD5Kx8Qecq;| zdTc|={r6QVj!9w6&ni>vqzRjXS4CdF)7r^AbTOI`B}>6b z;o!ng!FXhrFB{cqvcgeuJIu#qJ%+M#qhG%$BN~rLEegMv_K3`~cdQLhhC?^DCQc;` zHy*=t0F~o|un&g9KS=$)UjgV*B#d&ydVo^YI+359mjf9$4$utCX`$%E{4*v!LYWAE zyS;>@GtlW8C9B+GN6uZbw|#D6-uRJEbf1v;M@h1rbWk)Ic6{idq(%1=pdy9Xjt_4Ro4rH@CEV^{3SbcEur==zbyb z!veDGG?3ED!4RFaJF(rfhXIQXplc~86pS)}3ZShc4aPb|%WrN_KgAhipv-mBub}1E zorY4VJvy2}#^&G6^YecfpzHFs4|kFA**mAkx2~!xpqq)P@bi)#H+|5VxK_~3cQbPa z{SWN&KZN(5_YU!-OiMg5RUxC*Nts4^$ujR-;0CeVpsOGk<3JXM&vQU>==Kt!pSt0K zoL*7KDipq~DpLY{K=CRAO%8RkGP^Xh1tOM52BGZUa5JDhJ1`GM@xXa(*lZ!y+q!MH zLSn6i@$->B4C73om**AN+O&w_ zL7@EM+rKlRCEwex52kc>u;#cfn&oLes!;8%3ZWD=$V*Uhs%`eP(bJEpD0)mK+erql zmh4%Li6B$_JorBl_17H~bcuNqT+b%8rt6ws(qR^^Zg#4C|E16A;;q8@0YD=KCO1d$ zHr|uuGLx4*t}1K4L`^)tPf*?Xbu!00f~($?q5wwzX}?N=$*qxen;s~wPhc5OZLW95 zReRag&1C6$`~}bDBaf?wY$!BGZ1o<@b&yZ@_gUol+~uO|pqi(irL_7>b(uzqBEgyH zpGhg;I@aff$r(uBFjTwN#qf#3_cvU(HNS z8D}h`n#_-0lMzJxnNp{wj!%1mHnt~UkNc3e2X!z!>U=zPJrI8I5ikE~l#inz_>^xn zbWKofd=v}_{y+2MU0$10jmUv7HGhn}6{N^c}E ziwGn~c^NkeT%#cLbm+rd)QTl#DE5I$t7+bRaiOj8G z4Fv+3_s|_fhHqmz5+@-4x+KzzxH;eTcPSP*oJKo`W4D{x5{C=Bt#FW7I*4OESIOtc zA@{nfAfher%AjNM2w@SKZwzZlpM6>Og-v{Sm6zS{-hlCb0(kn4TZT#xJ*sT7Dcs`Y zy=^73PKIbdkl$~<75ebR`a`Q9{CJmy2CY6^mG?-R1WCoA=Nv?0ke8(8Ke(`mHh@(- zTfb%X%24MD0~%x0!0NhQ`t7YB zDRNTY<5fA2Bo*{lj>ADn2_Hb%GHD69SH^j)?Rds@A>8R)G}ZID_HRE-=CcOJnUWFo z^ncMlqhy((QLRBw`MsB%Rf8-kQWD>(UXk7JvAN%nHXgGvr|X{~sK#LCudHw^COCwp z{E-z(arI@8Y2xHpPJ)6|h9!G9`yiFcsO^Y^gP4M=(qAwuf8hGBAxM>y;Tt6u;Bg-6 zRkfpzm-{ibV^xx8tn@#tm^iQnQ*rppGRFe3@BY&u8zsj}e`~&Fmut*+Si-TaT7R_S zeb>Js%&Ihmy^KGh-cy6vG!B%DDnXP&)~N-$QRSHcasNdz&f%M}RfY=)B37ib_wzVf z`oC3l+&Bk>y&=zEusRKdl&QwsOORRbrxay^83mfXn3}EB9D8{3K|Hyv!<)PvZ6myr z^nL58x?15+s&JJEZ5|yQQ}nh(s&4{3t)S=2F{Bu7m63P^xjKEzdkk*aT>do6-0FDv z-n_>W&74uj^P7;ZY5QYNxENd@D10K#Wa^VNScG@a?$>q`&$I=$ELKhah;}&H_we?^ z4^JK%Z{*1pRgfirT@vnEd8uCNe&;pGL*mnMQYDV4 z1#0)-)%Mq>Z&>ZS95icixlQl-|4trZ_%zFk)34aSpSeVKW?5jQ?`jKYZyeI1B z5DHOzIysRwCGN6XqR>eJul}JC*&7_@h6Zc^G8p1 z1ycX)OfI0$2^aUVe=eqiZWrgEt*m@YwrC#c!qLS4te~>LM6(~(%yWgYg#CWLuKoe* zQf{-Yrb|IA(eYSfTEGQ0Uu+Gx0)=wRtX}&L_-xZ|&aHQ$>12PQcfxgHU( zx4AMrQJx*8(sDs^47&XGpa5!n<@_@uLQOgG!B%a6&EFtsZsudIkN7ey$44#eM|>C5 z9h#a2rBl8mA*>HZLm1kT8g=_jD_f|?nU)X6xN!uvU(3Eg$|;}W5c;t;4wJm+8M-No z0^tygnQX8W+MI9B(;V4TH(7SnRGO1~;{=GgTTMi&sTBD#vGtscf9&EFNz-*6iQ%2! zKay7NT0e%9KLcCK%1Y$7%9FO%dnEH)6Eiukdf#1{X$?Xc!qP(cWo4}P7z=zf=t*Z` zVPQ^83|z**C}qqnELg|sv&5;BQKg%v?`g0ujE;}#-!`IL(euL@lP}B4Gc6V-(^})K zNsIN?R@OCc7Z$)w4@6blMX4-eqRFYLp(&~0Q^NG!?eU3bUK(6Fpe@n)`t{4#ly~fR5ts1GOtnh*lg4g=E4j^4dd0t;{Y89&GBj zB{|&!i9JbMNIYO#lpr$HLP!hy^x>^ROxIc3FKWF@~SQ;zMCDy7^2RJkrO zCxh@u8uRJ$6ONFDeII;($1gAr6A&;vjK@4d2M{x}W=22mA#WSM0tkEmWpuKfd+R$4 z_ttd?sD0#Hqnfr_*G<9B8q!_=R5itSeCe)o&qJHI;$OdUvi)oL57PMrxuaPWWbR|Y z{x)=Dwn7uiJnxOU zt!8YGI(FmfkxSxMD~RQso!0w=Yv*qNG5SyCqNb1k0f8cb_VflnM;2IM7DYkb^WGle zu6s%F#~&67Zo)Pvgm#W6!p{JhvOm4O?swJ8xy#p17wxZ|El$IGz9ryaB&UgQqV!j~TC!Y8{EFRskWy zjI%*&>WRfwa9cqca&s6)r_D%>(CB7L|I?KDY2aL2F>k89^}% zwpSzTw~sB>m`si>HZ)EyCZK>XS%=Sc>7mHH)#XRVB8p7hu4ECrC{j^}bOLu%Ry(W) z_8cJw#ECl%O=EY6bT7xI8X703`dCWLrX-f*`QnC6hic&CxgyJ4%T2jrqla&ES4kI; z_}U$-KFDkK_BRxY4fy7&*`WFx|2rIW7214wu48Chys_T*s$2c-0IW zT3w9|jin8$f%99Ctqab!_?mx*xh2x`L-;{J?w^y%2n=Y#=+W^C;9yF-1k*S#fDf0@ z2i$DHu+Gc@!2|xgAW@9qz)eIJR1D8Cii#Oae5ghsBg^9*q`~*+9`LKCnEg#Q0Vmud zZl;28|0+n1i>2?-wu?Xq497f1g)Gy|wu7*%cXbkHt`vPUmH4l3VW@w<>-|#Nm{!GR z|8q46`gev}cv+13I27mKz51^!^TSUjXQ~QI3nikr?O}Y}Dk;AtIz}$eq{c(8#qKae z3j4hn(`zx?5EL~P#BPBkZGLc|ntAs2biwPc`y%nvdFBS`?ks_v0%ptCzrVT?0- zgIy?3kO@uvs;1`HOwpe(C`2fB9ZIntYWXZbMDg#9kB=;9y0j^RYc;CL?T6JPM=i#Mr#b>v!*IE}7DKZGnxw3=y~ zB^>9*sidc-b+;kw8cA>qf{-7?6Op=yua7y;<)lM6M`;REh~udBy(D=#Z$Z|yCE8aPvsTrgU(OYWvp_3 zDlTKi^HXh^t3OH3p(FLJmlo4zsEyu~z8_*0;Uzznq;W%d>IVF;IWFOHtCyDOhlB8c za18$!4jbZ*k2-N1Zb~h_@I@4^c!=ZZS}2I~2yi@V@u{)sC=ZDKTMLUCe{}+0xfR-o zUSu8kuVMLg-!%N}W@&6%NsdhQIMw6LoBf^1D@V>!N3KUalk@Bdz*_Se2=t!}tBs9+ z`RgsKV=h&Yq=9_|T!FfRBbaKt z)qbN`v{G~~rJO$E&_74#-GCMCunbx5-mMs9Kwbg=Al~JWq3Z{%@h-nQH!U9|mLgxl zwD0cS9```V@#eoLzZs^rRAn`+4e3@@MPh!cU$WKggqQnRS>ZTI5Pq*Q z19@``S#rO_?JY*KyRG{8xQ;WZmVN65YSe~8{@QNB zX}03=uhRfhnI3FMIfh@-LR8aH?5(s);fKau zhGUi*oaPB4!>eLmsLrgU7b9~-lbU*WwlR>uE$8eX1weqsp^9^mry3J1R`cp5TG&&O zZ)z>1275~diFnSXPOa*HEIa!|r%&ep8AK{Cw@EnL(dliGwXR zmJ(~+KMC1~SoKiUG>B+&pMD0@q+E*VYPjR37suDu^{tyi{s!q>I99AdmJ}+9e-b#) z8KJL&mH^=|jLY}!YGi4l^e)`^C@NGOzM*HnO)V|`JsJ1OU!a#8syv2dh` zc@1(+&x2M@#g^BUwxzid>a9TG#K^5fw`=SA=+dukL7&JwxdZ22C8Xh4mLnG;slsJa zTUbM=mOe{G`_X9a*{DOkZ+281ZL031vXNfLBv6>>9vo?Wtd;MJ$CeSLi*hHF6+V3AI5ZnX{#Zgc;6+ITu(e$g!+x{ znj^#ne~1f8SC{|(K%8&Acxe6Q)z(q-ycv&?Jm;?X4Gd+SWcIKJd7M+rWKeK{VwY`& z?vCV{`blQQ>Kp_+^IvM`=Nl||6Z#P-12gy$D0>*ZdD1=sG0Di!D84ElbkC6=ddMf8 z5mEGcJPshmG{;Hzf8X20Gwl{~sDM^wWs3U4Y_C>)x%ZlwDQOU?TU%o?)#|#6hRdYx zR(E3j@_16eLQvhW<3=s3bSwG z|5|YPyM>lol!+2ekV>{$=%>b^fpA!J@%6%MIqr2$Zk`Yj!Zq`!=ciZa@8#X&VH4B* zvOKY;U!H>j84X!hbw*B=Qr=HUMpar%wWMy4H)px-ZRW62_%LtS4kL0@H$NY(yDnc# zHO(`GBZmmfxyerPZxRMi+{8`k zm22=<;-;xN9@y&|>T8T?49?c-HbM?Ob2orj`fP_Vp9~+o1D*iy{B4+~cA&MVrG{8~ z-6@;^oS&t(FzpKOLRuh7Q8Z7d&%_n#7D$$-2ktoO-!l>5xw^lP@22kkzVFvYKL`kT z*NZ2K9J^^H#Mf!b96J|fNo=oDh$W2C3VLCd5L}P)#p#$gdlb^->l@SrD9^1}k_+g* z_>`4>!xhmzj+}*bUoo(1CG@|_L`jQ38vDV7%2X-I-@ljyDsdD4|L8w@yl|oX(e%Cl zY+>QNP3V*w=Zvwoa>C%KGhM>1tenEZN0rptRhyI3Q`<@+bvI^@qc$#B4>@TVD=TGs zP^5CB1I8=ta6UK20wyyY01i=dES%C`mlBVAfWV}2J;)M^F^Cey`#}Rt$*>fqVe3Jt zE+b*NFf>$NeW)zgRko)+><_4HFE=^CM{rK#*k2XH8;gdAlr33&k^lUna}#(Oqeu}v zG1LG84Y9IB8973ukbziWOSEK0FFFnc1b?xVi2XK3 z7@+c!>F$RkxZ`rjJ?j6e_@EnJaT|7BdpfIYGng%*lM^%{k_KdBqC$^mHww{pV ztg%gXLgOKc=Kp=|L}+mueK^A7BmrttMM4&r>eaiIdu0{+pB|XAuFCmPmKi&j+srWi z($XH$ky#XP|07bg?Z=<35sj8UMJi(%oT5fpRU_2L5phLFF}e3=If!A-SuFd_r9Y?3 zINYZ&C&D5WWIwJ`pdAyn|12z!=gNJEewATEWoSuQ?hOrc<<4t_3L@F22HVA4$cz$UFJ5a9v_$A|d7Qccqpukrk?P3WUkO86k}Zr*{h` z7ZC!c8WRH66Yc9q(f%wkOJ3Y} zn-%u!Bc@rlSn?k)mq6RDNHc>m_79n0p>`GJr=UgM%`mO8!uaH&GJ->8Ikv%iCVN%3 zO9A_}a<%#=IpJ8oOa*}c-9*BOG6-1R~E8)bvhVjBxHOru3 z)nN_6Q=LGl+~H8!IwJN%c^-cm0q1?zAg?(HYsgkeK9dM7Lqp|pF3XINFlOLYhL)7> zECF&wRbGAfuTjsTwjYq6M z$yqk%M)?Wai9s1#ozqcF-brQ3=5|fez@JB%NewVNPpfsjD>L#g+f|%17$ZUUYsIR8 zE{mI8`ATZ3zQ+4vIG=S2yV`=u%D;Y6um3!`1p%Q5~f zzxP}ZlpA_Se~n{TMNtMe3UG&dM6eRXqyDffEp^__#+R`GrvxLoU%ZFE&#l=Y~>IA4VH9#gMZ4pRRMEUj_- ze|7SGyz`E!XLgfOqdZ=_oAd2!RqPkz<@4iU=fF@M+BE;0;4NnU7tAuQ9Pov>6~>3| z9@djW_RG1&wkeumpRyd!K2qCex^9J=`;eE~EHm1|kC`zW-8Kv{1VkE`rawyV0XKQt zhw=j@I&~GBk})G6fnBVLFG^bKCV=LHh%xQUnIjVr4TC)TN~_xT3J2{~I_vvRuC>;! zH)H2V|4^4XxNNOphYLh@nqTLW7@JgcKCu;+qPRLWQjnk+%2IP(k8sxH`pXn!(NCpSwt(C-K#lPvhn1V2r~E4jMPO?*T7?S;aX( z%Xr9_d*QLz7a-4?&yRwak8A<}EfWDJli;36uG819Rl`jVuqFhgj7N5r09GECce-Y- zm+Dr;&i`|YX*L5(O*C`-9;Zf`zhR8PlMHVcnlq4FB*zhGTa$b~&*#XVbLMI<8Yl7K z5jk?>JX4e>e}s65AVS=~cWU!v!_y>JV$MdJJJsh;O;b?f#Ka?h;}uB(fd4a~e+koq z^riTRyx*7T82=1q`fptF=qng-`YNsjf@@Vzw4pn^H92&HH3KqdnRU5)gVTRU(+WK~ zFTFGeRD~=mYlWbK6K~GkfpWpeb-MQ$E@Guu_Mb6HP{cAsabVR+jOuBi186d1-Gi*b zG*ET(>S>t36aog%VXr*?bLeAk~L*S_~66^}X+p;w~i7cQ|!ziO}5 z!M!YQKN5?JE4YEaM5W4=Qy5-QG2JS@mYQNs=w`FvB z5&AK;uA90)na=|a?!V-j-7R0g?o-rTOCNq&pAb8kjy+%z`ZXP1#@$Qio0<*&v;={- zY>aSkv!}Um?!<1X6QOROni)Q)=E9H8=k)k1ykC;wrdLz_ZuBqdT*P+rNsc#h61T&E z9@hHgfxq5&OI>`i{Sit{xh(Vl%8xf8+wtc-^mxfeFXzB*S8 z_B)Ta2IQbaCc>IXsuRxjfXQ!-P3}AAyFSa-qI{tDetnVI@%sO2@YKiTFw%o3j-B^) zZ1z^eCg^(575n8XOT%`9O)+vkE(Y(Bk!oj9^}KQ26O)?_dd!-4*8J`<>|rd1@dm~e zBRQW@nA&B>$m}Ph_I<=%j52-i7?~o}KGe|liTW?3bC6ZNW^Nk6)UP+@ha>|^CSWsQ zOj;K5BG%!9+BPNj1l&%b>o{CnhJ$KcDCwJFN1P0-1*Pm>>6TrbM$|vtZApw-VK7T+W{y=szVxSNX)Frduf8g#292Z`bc+0n z%Lsy&7A=5XdDvf{h4dCGJ~Ix}R$R9xH~-U13GOQbLCp7xLN@4^jVAggQ5XcZ+-N-? zJ%fot7QjnVsZ7}4xzZ9rYG0{?qqTORDvO+X6#*i0b3p+yTL3D|)*AX8=6(mo%vWVl zK+I%-{OzoTgRR`s0!I}rGNvmtkl316<@EWf6jTec+=6aAZ*pOVr60( zFrS^u3H5}dRpaFmJ7o>7u`oDT<)IChv^>28L4S zVOQ6peuZgd`eF2fePxiJhChw@VlEV>YJq9e2xWJF(qLw(ks3SJ9+zw}a*Z6eFLD3!oklCe zCvY2enxWe+)CSTVaaO zD`6&gU!^VdX=isaOc8n~EZy$A=3e5dqr02Q>VS9>=0T2vnP+tD+^(mfQnr%T%8qxe zR%ypO8BubvZ6QiqzZ`{W8jcN%sDB<*uGJ^@8D5N;&HhJmsnv&-{c3 zCqLZjEUtP>R=g#vU9q+m3sA8ST3j9m_xR2KZ`IMb!Gd_$3;Q4e5+UhIa_82=;rlpA zW~JcH!u2l@<6dz8?N~sAtOEb@nfHm@8-~N5?b*RMCI)tS{+ z`}UNy#$CDibIvhId-~-&$M0Xfk8@SQM>r?QzrT6h4gUQXtoo;_bOs3yH9&6Ot#JICEG^OHRkdrNYdS8C=aI^c zr;#QfhO-E8$IX7pJLQOOr{HJ<=pe~{)oz+<;8-J8htL8f|B#k3X*dSlgVQbUcVws=liLOnl*dUw22}7_^IY>-WNUd@6v-S5afA*#Fv2g?i0 z*!3dfoNQ@uc({7P{id>U&NuB;Z^S2`gl}*d^?|zmvNe|A)~~|L2KXvLEFt&zbbi@f z+xYGVTW5Y=gi2+pfks*Dm zR!Bx)3zh&pvwzrAt^s{KHFQ}~a`U0USO2GnNTAR%e*g%CsOE)mCc?j;{W7{0V8 zqkOn1KTq{2TJMHdjUm!XKF)+dBSyaP`hkIc>1IkVfz+#fk$1UYb(>&7&j8AbXpipJ zs-zh7MeJDTXbgXD8C6vOu9Yw3E^qVhkHEFmqhinmZ*nu0%O>Brz5u| zW>tl{d&Y8lL?~b)ap(V!%Kq5zU+@4`xc+Mzp%G3y2SW1ubxI{o7N{o9HSNmAe<*DO*tYywdiOB_Av^u@0^WT`^i6ti+uZ6@ z^wQ%ps|&5y&-l`fLxD<7SI-0UuuOmGH@2_UYOVhRU8=pq$bbFY-hcPhP|4`;zYw=h zLBpfo!}m!AeYR84mStsYKB4G`#?VpgXndI_%CZRQIgT?>QbRFT+* zDFI=HeYpi%Tf%q0q)babEy35fWuzsc%}ZPtq$YHhUIaH)4B6dmE~Q%zLt3frAMiac zDg8uZ%doZ4TOG=I3{;XuCDsc*Y8)WKK5iX{lnh^67?9xN2LtvsvmC6>`j>MQ{T0(v!|PpI{*~4b9ghRPKdP!^cc^VmqDIhBU&KZ;GBZ}njs;(V?XQ%ckHR4mATMoBs3$o8#tOd zuX76`Dp*`OCI~?(vk!9#krsz0e4h%bY|?@NkggmbRdXgb#f&;s?Z-PNm*eDc`*C)Z zH7m|-iN%OBM43n#QN1{vB-AH2dL<|N!G#O6zS^|~vtvdxY-Q8E*~EIYi5WIn!NZmy zK!W;5=DnqSpW(fw<;sd0mK#pdv6nciBmZ(9ydSuCoeOuD?$kPKOJ<@v0ahpp1-jf? z5F%Oi)w`BdE#fwnP;ac*G*?GU*fix%QP$#lP%E%@q-G~sR)SlwhJBq=Z^yYNZ0t$o zOarp(;z8kXg^X;lpSKs<%=upDTflE+z8U4!Ej5rQqO71IklLxE)^-<3s9BQ?)&{1(UX5b5LCd1&?(LQy3BNME= zL(Vpl)sa^;T2_@46}TNUL9?D&13LhXtAuB^034qRX$EOPUewm3nV@RR%&yY?2jj5} zm=>?^O0MFI%TAj$8vv^NK|Lz~Av-uSa|lI!RW18)uU>${2o~w29D;{Z>do3(F*?+=*Ix%Y@RH* zVBYoT|D8lgY|^D>B-uV**Cn3!UlW(vbb@f<-aiun&)?RTu{6;_WF1v%WFZSi*eyssy1DskOwV8pFsC&IO?9aSN*RHnxznX@ zU8%jzn*!EFtt>S+w6sf>khLBA1OvHd3}zl#-ZLxB`XXjaUDIp$%Sq znikPILkh7vrNDGRoasah-Ikn2!;jg;ZfF&~K!u2-$3Y3(2i`PdF-mg+LjVA{`R)aP z%DWGsB=mk(-ou4U`au|PYm7S;t&>r!ZeIb*){%Hq^_dMMjz|e2{NtQfr{FCY>g65D z6USix&-BIg&|BMNr3QxZ}`1IC$eX;~xfhgx(%>T*|4rrXYJo zt+wFcIm}-G%I%`CeUyShd2>bAAOE0Jztf~rGQ*YEIXv~-nke9|u+8!_0r2=FzbI*l zwAc|!*cSAGZmb?xEQeHEbd=R;4mWZ_T)cE~E0O04bl%7SW ze0KcmLr98qx=m!QB1_94>mB}k(&>7ZDh<0*3RX{HqD9>RK8_dZ(d5+h)O#0sW{Sm9 z{GJkFSG$KpfT(YWf<3Gt6QvpN)-qF}%e-R8lrfvLBr%n7*=g`1!I@_Nxgh)$gvj$m z--iUej}(TLRUV7OAd#d{s?@ z-h$$Yi&|r;DHd9GUdS!P4HHMPs|8grSUOnoeY!1$<0a~Iq5g2&&XRPhSopCmD<8WoKK1pW4A<>%5ZK|&l@ zhzZ(TD=fzxpgz@5sTB(F zzQlAUqMjuUq3Zm+2+c?lz75cMZb+k2W9mBct z<#rMIPoVWXh2=(cm2w}I9z3U)nxX&HQ{GxtNPEpR*|BHBw0w?Gtg6p|o#$9}qNT^u z_RZ3lLe4%%o;N^IK0A}RSkr#%qt0ur>Eb>cY-R(*dem!40@WpvWl&KR|K50+)h=C~ z>b|EHM1cij*1R3$-s>emh_10t3mdJYIEHMZ&G=4j;dPFMh(_gAlypniDCv*!e%jv? z1u(Z+`8=yy)OJQnrLy#MDn38!3 z`Vg#FgZq3;o<>Z-yb=BUAft0P&D>~=OcIz)P*2Du=27}v1lm1CDpe08 z{j5mYjuZf({|hx@V|-YxsmAgY`*bRWiO&iMm)_n&U$F9{jpjo%0pGfKwsX7*(Hx!3 z^ErQYp_l%M%{g3r=PW-OYfvu1q5Ek$J)m z20q#`oHbhB@>wFf9FPh50CfNgxtNNZ>~N!?;v%lXxaf*)n=Mw14C8Foje>tV6C0QXbOf`1+-YI1*%uKxp(}%n@xQ6N1cuyq*rW9KpgK458s-{ z2-S%isy`{T*2fOjs3(WeFFLE8X>AKfX^F8l7hG)p#|iCKC4#hfO3_CH?C2}{MSngB z&4d`|NZs%V(pQ^Iv0W|g7r10yUZIifj1X)$%UWIXMbqVTy^X753p#SEp1EOtV{O<- zGumolrpASyL=?X=n3LgRd>K=xE0w1NE!2|m5yh%z7WGaL1g{L&3ly#76+4eH2yt28 z*qx4KeKK;_wN)l*{o0Kmm3vOkDq*hnMI;&JWJ`pGF326h9`{WE6yH|@xY+>D$9VSf z)RI?Yc+ShydY-`J9>RTUlFN#mO8(F%09I^Y|I2xQAw48IIZt!bxNIxZn$X?_k^Y8^ zuY$aXv;&nzo$2;*=p+7Q^0^dlXNI6-)=+A8TUx|;k@_>QOByvD+W%3u z1g}W`$wm9+Ii_s+$ZMAL0ZC)rvft|+huzWcZ5Og6h0UDB5!fj3Ot4GRa7KE524dNx z953z)Rr)JhG<4*AR_nCbaBSVY&=ObV89P!;>+JcYv8mHs+_;6g^*;0kHK5@m+b~zM zw>}pQWTuQl& ze0Sc17gJX+4*xl2@mHQ0mY|#9Gvv-WANtLh>v#H9lvGb92||5Mmk$jj$cj6UB)mbi z%ic^3cxUlRj}y9rHZXRPAjwYOB)WRh|J7zY=LY~WUTh6>?NUn`Ex<{{v)DvxTgnp? zu?V0^Vw_M1rrsgQuso#T4Tp0ARrsL-%xaMY$Ro@Mp}uBUZ_%45Rep;-bT;;_9R2*I zju?{yMW8SK0$tg(-a0=CVI8KJw6c&yHcMNeeGFrD7u(>e43pi!T+?w-=BSW%paim1 zn;G&z(+eN{=)Y7MdnlPzkq}N3roW7(6UM$2OVOac=q#gh+5HcwQwQ`T5~L9zmp;B3 ziqX$sd$GZfwfs+m{O?Mlzds@AyQ-BK>}+KgBT8exzv~-1O%~&%toav;?pg0iqKr>U zLZCoFt!CR6^{N^WfG72rKkxp^^V;c|w>23{HkLE7Srb%scZ%=tz9e8*p(N;4)wC&* zH&Y?}asB#!aAl)Ve|#8X78@0LGp!c*+m7q?NRTg-V1K>dg$Wm7xkyo>#fU9PoOlTm zCH2lXXy#y9fJ6auMGkz#W}IX6%;G)$?eoLyC^ zE)5nA9_z!%J@eDhF>1!d!p<5e1ukB_wkIGYA|}a(l#HB0O}3O&)TPtV(v?A9CPV%9 zFN=v;tvdA@Sh8bf)0jOw2Pan!+?q6N(aNJuJMl-WMli?1DK!!Tg~1U>HgYwC<^DVi z6krW0W$PkSTD5^j@0ra7nrzJ!o5SVtYY4*cX$QD-|Y---VqFr)%#tBE^XR#bS%VF(~nrNJ+|) z@(Ie)dZFrS%BEb(yPOJSq?p81O662ZRY#DPTB@f;YNnR+`~h83spBu}rk*mKB};`S zj&h8PT*A}IoG?#B-*aY7d66O*Hff{^o+R~jikud_rOwCV6XF}S^^|K*iAFi3zCJl6 z!YFU}G38sjXyH3}GD_n#Nz*h-a|-fI%d|@Cv{55J>EIDShU{dK%>WBBWuFe|NP_P3 z)ymCp{Ej!+%0F~#ryK$~2tNeS3J*lN=4S39ga+CPLX{qHxM7$PINI$j*YSZSPlpwf z-pZNHu=Euyly^2bGSTU;1R`=`W?%+oaNf)ivg)5H69dbMij|}dy095-iIh?$vV6wB zS6jiac$Ar$q!LMG=dDc1R6ijlS84Ld=YZ0)APaq$OY}?$jEb^iyug(iM^;o#H%$G% z`z2k^PY!jwuH_ANyW5}qhhPN7a6;O$Ojb}2s?qvRm)j$Is0{>d5AV&fc)|wBR63K* zy+>;a3=?zAc84jMmqL581rx6Vu0}~4y2Nw^YfC+K0rDWt3YCJEh zE^2ai)v8mkfrXV#BRdBt7q=$OTD0c?kvKeoNFqZ) z?iY>DV6xa8E{`t|ip0)oHILS4tE)b`beGpQwszj>V$rCqR;8Jz-`5(>s(R9PKY{&KdAdKQ9&GJIJvZuOfyM7oa@rsTom{($Cii_qkN@p-xYz~*l7YIdS ziBu+6)F@SIjaH{O7)@sE#1mG7#cFG`JDe`JY&12uw0hdwJ370%y#NTo2#VnZNzn|; z@dBS^eOXa8cjc{Hwxgq<5jBYxnyR`%wdnnT)uN9lu$H}^qmIRupRV z@|Ad@8J5H4@yEZkY^R%Qx*4mISuJL_!&O>JMis0S>WE);wx94iL2c-ivLC)7i(t`Z zS6z3rm-**-Br^ZK;jO&g`m$8XAe;oe793s73RHZQ_<#sYc!|{0GUCiS75fzo7N%gg#mAmT3s*$?XoMC1eY#z~GQ0LK{U;Z0?_M-FD z%|O}7AXbXSv!0>^H}c*taRoX-_IhtIR?sIJ@)5UJ-q#!I7ga*NtT>FM*p@MhcTQVK z%thAUb68XL^<2e3F%0ia0g8izAMD)4j0%Lk?Z}!wNq~F>lxP||6i`Ct8)1Y2SrkKj zJrv-^tLW{XT%k^o+{cm2(t>!5W-vT0i<52YHzDXd1Kt-5s+s7EMoeLoVD|ELM`Z3_t# zmkGwulIT$$1WQ?2jeBWP{)cQ~|F)ceVKb|!_i1#6JM9?bGh0!F(%;G2P5ZNjtXq;i zuBea$X(nGHtMAgL#^1kgBs#%RxXp)j20iF+`V8L48AM z`Tvl*Rq#C(Quu;4OdNWnft!fi##~i-sszKtTaXobnpL9 z#3b}S^+qXrS3#9~shC1Z?1b|XlL1e-(kr-#OZY1!V1_UEMJSnB`yjJ(X@TK>pofV^ zDv%3i=5g6U@loGL$< z!FViFtfzg^SBLUdkG95`QE4?TPRZ3x^h#6=0%v<$oY?8d*W7{=%x=m>He4^}9>K;A z_9?k9AnV>B#^?i&qi}TKAOLW{Fx-;D@pE41-fku=i6a3J009@M8+8F!F$=YLRJXp@ zN6ek?ZD|IH>LPabRtOiJzKI$am!&`46rpV2);?J5q$Xy{A8wdcYlLM31!SvSr~OsC z^1?>WXeatV$##JgONzs>cK@t>GG3tf138-Bqg_Mit>m015y=n6PSSBA1#3LDWsy zJTswb!_>50s1FC{+A3Xuu7%2c5e=8k4@ks}1-6a1qBdc8I#@O zCtGE8C&dqTVMgmb5d`2|!Z`}Rqi^|s=zA8&8(p~yb-^V!000U!q^d2c**abQwgFn4 zrCzQIX2;|?LuKEq@$Wa}Q#Z-vQ|HhEOm)Ck$%G=?@E)d+R1o90E}{$mqB!V%p+A(6 zd--#Gj`spgxX>{P7huALjJlFtt7kvIS^AXjPVJJ?M;!zb6`KeUVL}-fQfcEg7F_^{ zFrkbKnR9L*l)hn(D?p?Ce*bT;`xgj*34RHEz~}h20{`~wbgi#D6&tUkhrIYw01+mX zaUrvQ-tte!lVc-%8K#gqQp$1w8?jdwl}%qWDecxytZuFm%HpzfJOEhbu}~4*bwgrSH?j{ znPwV|#(^b=Zh4ConF^k9Ze^c8D*#DnOIdQT#n7VDG1Ga@lWG12?(i<}p(AfQ1C0%! zK!F02sc6nhmaM5tl`5r6mo9B$FC_y5%`_T!xKs|hWtP-iU!vw;-0kA$-@`p|qU$ry z6Q9=P)t7?A(_J@n;KUuTm!?7Qo6T0nTbYkN$W}t>?s4hadqwH!zx^_O341+UvGF>R zPoEu6X2cZ~X7Kl>FOY=9b6Vij(akX3IYApj*RVY{htS@ghDp#T!~x%^Ya- zk{LK~qg&oW@6%uKE`#WpiCJ*b1%QY$FE$wwWzi{2WK=359h2tTc(Lgok%2*(7c}H5 zhmcCgWV?`AXM8vt%xq%3*ql__cwKb83jh%&lyM=IHePJ*1(;CApW-k{R8s&ECY14v zpW~B-j?N@eSCIEmDs8;jtMN4}3xw1;=lmf4C&CpZQ0lqM@pk=>k92Q;lo|8amRtfT zOaG3G&K{^(>B^rKU$R%NQKQ6C1>-_09WyP9F}Buk#m+9Wh6pBZ2AQdVL}-fQfcGGX555ti?#y;oee8ioJ299Y3Ej< zZ!h|v|q|(NV&36GzIzxkog9}d~lyMu7nN=UMx>Hza*~>1~0Em9G3*{3UzU z%9Sfm0cBiBr7zGC%5_8PYdo zrsq)MKGI>-H(jdmfW1AAAzF-;u^~c*tGlzs>^mZvGXe3D)*#>JwMcv3W$W^D`*xeF z%&871R4ez7z&d_mdcoiNQfRw{@?w>7)l0eU20x|z)!WtSg@5SyU$d!7aolFwpjUZN zU=c(okk$ZmaVkJ3YUr8}ASKxu&~T6t3J3^<3iKP8o-f3@k7MrEL1O~?f{zFQojkb>K#qx#cY3+Y!cHZ3g-y)`o5Jj^@ z5?;+JG$M^uy%OnSkx2W0?w%ojZhtQqFg7YSB865u3C<>7^j${^Ro^!+D&R92= ze{=p#MQ*tF3Cd!;>-ZWb@UnJxa@PM=bSf*gQh*EqDEj^WvwP;;_jWe`Amf-+bXYM; zltAE!$^)Q_Mg3js6oLs+?G``^n!pZ{60qi<=cB!SJKe8t^(@h{ZiOOby$ThQ^Eiw` z;lN>&P0HYKT=IY|$s%c=+Zp`!i&&z|m@ITxNVU>r`OF$(fGB2g|f!pHgK?d-sI zoqb9CpSr65OA_XP2{p^Cv)P>w&j+bhRbi%ww$KdA7>lSxn!ZSMPiBoD&qc|GTo47vD9m$Xb2pR7>ONsmuPQ?XUgU{D_WfD>zs{%CwwCUO%Qe(KUUs zE%8F_Oh~-wNNR-A*_RrQalkl`%kr>^L;X^%2fm*hs~fCMJ~GC;3mOC!Y+^K6l0gsy zZWA2Lmu1;h6Sk;NrV zMDFf=K{o&UQnjxA@%x(}Xuw8`_6#_Y@K|GNvSxShf)ArKOQW(1T# zIuN8ZHYtyb07(r*$h#7qHCb~BSv#9FQ?npxTG6#iVUp}gS(9Se5YjEg!)0&B5YqL! z$7_t&^YZ-v-Rr0ghR~N)?WAmIn~?m#V!jR^f8!9Af99 z)TL0mE5Nt=umBcIQUFOwgwjzLQot?%et@K89q)%6yPQfp7mbV79!Zyec7@-#wXF9x7>2@tK^CXo!TUwbNN6v_OxTI18hZ)h`Lr^pyxKBSpA% z&}#bH$nkxs14ZfaCv-qDYlR@7Z85c4j04~uIDY-IW+xsYcHI=85H}6A zN{xI@QvbSVr)ZjVDSSdwWQ}gfawUau3jcAM(xg7O1!OEX7C~P^g;4kY`)9|pvt)Oy z38yZ|DRM(l!wO)FVF;>aC3ThmGFy^od`m~k$81-OT+25+rYC%6*@ckcYx~f9vtm3Ik+;y!1^;)A^O*7W97W(;YJ*W@VYjg&C8+@$Z(J9c_EG_WZVtt@-)rP?1nvH?Rbz1_Dn>qpwKYJra@W=pM z=$KgGMSReKmW_i61R?;y001!n5Ca0e83?KAdF{;hcy|Yl5x~eHGr&3RVzB{o7g$z; zjTarQ0Jg_A9N1pw6|jW@Kw@kF6&%XyE?dB0kh5l~t&yN!bk7-Jc~xT-u>Xd)T5f+U zDPRvi6gcy^#Mg14cz_@PUW%Y&mktr;uXGsGy1(>S&;e7TV~b%Q-&fDbM+w zFZqU-{J>9O4lICWum*_06&ZC5U>IXU3^vqoBaJr3I1@|~ZmI}Trkg3*CVOnM)2Gfw zp-rPFNM32pwbofxZ6j(XI+JW_O$QhhISZU-aQKPpZw5+U}Zk*R`zurFxMo^rjS&kP( z$uKQDUi#Ddx={5vEr(usb3R88K$Yjy)%?+_?9V8Ly*`JK^Mf zX2gmQxrAH%1qgK89e3SJ$WEvTKcz^OX1$0j13+L14330MY-WzwphVOhZB2D&*k_0B zbN+MQ|9o6<(WT(-&3*iNJ`j=I*P|tN_hC&Kc@o!Ai1d@Lmg70!(G|u~*=DgjSF4bv zR8Of5_1bjk(xcCSp&pUFG2j&8A*Z#*(_q)Bmg(vWGUqo+if3e{471(;T+ zl<>Dn9!~Qq2m(++!yrtIBqn)ER9P%1Y-0MEh&vcbIgw6GvaM)Wl&RWK8k-tuQ=`Um zI?urs92M;ro4eWqwX_BWu4BwR6A8y7<+QA9C5NIyt<=|GFkuqY&qUmbC|Vokq-sNH zY-*rMjT+18JSSGrbJlL5mUgc&W9EE%Ubex-#XaVBCsn1 z6BN_!?_{jj>huOP&9EFVh?2$O^mywVO}ip+N^bJ6hhv{qt5vT{kG|ufVLYQaB1$5p zG?-*t5iymi+E5xR%|oOGa}h$Ft689yCdinBoK0Gn>js7x1t2gC37J@%7*SJZ%vsuz zu)ZR1?F(}Kh9CJGbDM$dpaz~j7JP`xb|$K619ciSY0+U-F)Ph?wuR;`*78`Glqgf7 zTIyebaa9hC30s-Y(ZGsYEN2ax>vBSj0uUI6giNf$#@ck$0K!&5+~;HtI2S30f!gkk zpgBkJuBe2^kn+54IlJoC(|FvIxnnMU|%NCVo8i_}jGq0*I%@VQ^>6f!a=HQytEfViTN_1i8+47TvTB z+ej(>?>KCqV-C^910S)qqLlj_{^!75sP}90oxiP+65~pSd=qfSn#Dqj+9EaS@tkF)4)XH(#(!Tq@c0RyMZ*wjSpPJ7- zJApu2H)mtt`kflo)Siy-JusoTnzwo^Q`{R03{BZpMPu{RX?Y{Um(R?bmj8(>xZp*i z-5s&=f@U|lBV{}ZEK*z)4Ch?+*J6{B_dF1T=?W)ovd0l1YdfhZ?F}jwE=42nL-h{& ztBP$B-5%3wdu6B7v3)h)N4LJt%W^Y4iuVWgAe6crZ?BX6VWiz`R_euT${vs@mgQ!q zH$?bU%0$O`O8cm?qxQ=5l}D{R&2N?ei?L>zZH{@8ES4%)o?<2H)N8cFQmdMfAO$An z8S#wZMv_h5S!70vDhtOEqIf$ckuA@K?R3ydcOP;F?F?CtMDUZJiBoE)-1*Afy@94? zbdO<1yV0Oz4~YAmNu9Jo3^FipE8l!Xd_?de{2~Mqp(2PVI&m-wbW&i_=w!j<(5VDd zjZPhydUP7WG@;W1rWKubOf(EcK{^zqM?nS@WJEzG4ge!Ez}Nv`LI#*R0L;h$b3(v^ zEU+X3Y={7RBEX3V*h&O!Cj#7vfL%m@2NAHJ$e|rclw`R=u2iaYNuleCP@xGOmayRn z7oPBON)zgoG_B4s>m2jmV8NR#dYe1mWyv+x-O$t(XAHyy8eFnWqA}%Trg_Zxm<7Z# zVhurzgkDexMTW@uAU*<+0KpfHXRL$F}P;MEOx~{PQ@v%#VhW`e>}J$z4=DWi9zgN0xWNpV#tQ5 zBcUa9A^_POpymQ~1gPvA$@kx&zNRWOWj1SN?YKU`00{s3S^?BHAZ-WK4j>%> z(qT|L3To%zb{_dIlq}Z8EY+o12Khk-SPK)BMezrbMX9MW>a=qEOO2)t1DGX=J9wah zLmT0%?BD|p92z(@aA@Grz@dRd1K*)JY%rQ_hrAk$4wBIoMo%&uh1nz-ePIkFV=j(` zG`xiImdt5k&Pe90Fy|!mpD^bo6Do^vS!4>6C7Enta)kLOnOtG=B$F>pfn*AWDUwXF zFePbNN?9)oGH_z331RAlX%MDSGA+WiN~TW+{W2Ml!JtfrWH2m~5gClige`+{nM}wB zR|%$NX7=9kHY~DNA~&qCS5i0d*ek)S0AeidH5h_f@M{=^u@KlO5QPQ8#t-qcaMu6Hf``7EvS-MKbAOZu27$OO*($w8$_2;n~`P<+>s=X^z10 zjgWIQ0>!VxTW!<7?Y(3ei%iYtp-ONN)y@+lPM$`_GG0>f4A(ciL<#D}!osSe*+j;A zv7|tEt30_I+p%KJYG>_sN3=VNMZzF;w6jIhu88f9q&*Sa8%g^jwm*^%L`DZA>CkD! zoJTm#;yI5ISvua86HGYCq|;10%j}mC2S&sIq$RD*{(n3xMTo&Rz`vP z#JvLO8>?=V$<5e$AOM6QNo0)BzWza;7w_i<`tGcah00C-DkZq9C+Cd)Vj(#4vb>QJ zI>?zfO8DsN%lGYW{IIR#%&v_gmN;@T^|0@J$bWf--}i|;Og@nR^NEhR`yK(z_=3#4G6zsUO>%|&6K2dUD47NcN zeZ)`VuzHt7||q-pE4OdULN1$6XuQs>{|Kxc1TsjH9L=G=YVHa+~% zE)VU+#D9Pv0hk0(8Pdpza#Of>`-=T17V3=#?Jl_hL;7!W%cR#VE$cFsaCI98-+y7Qob_y@mVhhKl}j0?;DR$B706U`z*i zzb@3T`i+42{ZPMU#sAwFy*Jk12pyJKS=hDRiA|j15hz+O1~E$~;}w0Vq%p9PMbp}a z1ShgS4QzO0Q|VxPV_9nO@7|-mNPJR~m4f5A@PflR{NI|TezleNn$pp{mb9u3Ngkci zcGjCrhABT({>IKW%JvjdMDF4hU~kRW`HiormvIP(d}xQc zAI%ZfK#wmE`v}Kk>_%!7j{fLI=HvX{c%znwI%D*tWPOIsezobEfpHnH@t@GOS*MAf zL<&{#Mo!UG>`mI_9Pn$iwxC0uAn3%@P0LB0!qxX0n;GFw(N-zwo!W&LkN-s9?*4snPe`yU-74G+_qm*xX@92eejjS@ z_GMLWRj^s~;?C#GZEFwNpBB04^Py^Yht%IJaVb0Z_UHbGw$hh%N$H4p%U!{WS7zCl zw~cP_d*nyES*2&81qm@W+Z0}QA$5Tn?8dk_M{CS50=8AXR!cd6}=ga=)%Y< z$Sof@93u&N^+VF29XLp(T6Sy&1^Q$6qA&3QY+l;s*m(E4Zh%imUi#6ICt&2uoE0#_ zsPE57X*4hb<}?C&^Tn&X7C^!)TEh{3SMN(j*BMDE>jdz>0!M)QHJoh@Y*Z5<$3-04 z1-Jq5H;&*7fPyJVK&9jiNyzAlvpE7UoU6XNJxm=t8^ak6pm$w*11VitZ13){jsRkT z-Hv6BxEmti3vk?=XM7p!p|>Y*P9C(ek8U4_fIfh;pxK;y^iSAL2OECO^A?~Y9`R5q zt^q7Nta~!st0z5YC4&aY8I80jgR+ilt_XDVL9Jm4kou2k9raSF=URo_R-v9SnKVdM zsM3a_j-sWuze%|Z(caxEMD`F3a?1F0X_AxB{FdKXdMFX`a8&o?23XG8xJlb8<&FZR}P@k?)2uv6xq@sQB4Oe*^MjPT~M zqH=sQHdp}6^E%_Q1UEX}$P*SZFMw;@%DP34k5T!U1YZ&23(!+~l5YV&06Ysk3pBvK z8ShXO|5PuabXFC%HH`d{WxxVLC;+GxH>Dy?&u&oZl5?tjpP6|DZt=I2nkpy6?yiwXHR?fk7q44Q6C<~G9BhP zkQC3|?ZAsdbbWCspC#V8Fc&NS_l1Bl>?AOL(6@HVD1x432 zrSE#uXRvD47PrkLww*&L%bm8^|L$b-mzyFAl z(7_x{G}Ee;c!?H!&uZ&!mhFtQuHm61tCkP63q9U>d)n7)9qDNAv=R}bKtY1)PP^=O z&SKl`w%=inDojUDY{Iku7cNBoYU_MJUfsV6kysA4qeC6;-Bz`xb;y%UD{W?ZLY|}k zCWWe}S3}!rS=QNNYihQUBS+eDw7n!j1|X`HLNaKBAk=YeppP;D5A{Ya56l98VZ~h_ zbr7urQ0CoT@+98rYYMo9vB5`k#3gfr?7S+T=!mThTgD++t0kC+goSu>>0H*S!u<^` zcSnMUh)HhQLqU+v0%ihy8Q6L-iNzMK+|ZKNkdVOI0OXXJV=@&ccdATn`7lRi+km&| zuOYb0{Pvhnww8XfE9tswIOt!_nBQlW12oZm<;F7fOWdPK*#hv>H-uS);sh#mVG>hS{;C zO$pgBw~-}1-4qCxHxZC-vcSXCf>1}c@9w$%c~4auBa;tN&^BY;B!FF0Nn{7x4az!` z!c*7V(vA*yBW5s3SsQ7~yXMoG6J^tuQ{$xKq>dnM z;c(T41!)@Sho^|7Pf;Mdd#+8;gKcR8eYXvl;#aCh!lK)EB-3 zH5fw(cJR`l6%YmpImiXTq_1YRb#W@8HR811x1SPbuz?di03q1iOHz;(7Zsoh1t`1Q zoAeRlJk;PDI?#s^OtHNJ*056r7um=j?(lM6jsPq&f8QrV@ru|aBspnY=P(8P@ygtg zUob@}MFpx+heouBc{{q$t0DhPD5FK_WFphDlQ}jM6YGlt;LIk5OB{6G%h5=@*u?>k zafVCW;2s}%!Ye)qQDW&oi^}1TsDf$d{t8_U&PrWc(v^XXWhP5(9x6Ezu82h`da;UI zf)baEl%yd&naD~Ga+8k&6|Pvp%21w4RE4s63$>|7Lz>W>4z!{zZTd_%dNNWdQ5sYG zzbptKqwz;zNC}u2o87z?-dRSDR1fvhp?fJimC?+Cd0(bCf1VT*d>ljV(6)cq%P>70G}n?t>yl4d~4 z<#_ROR(bDsCDmOEOjACmrq4a{D-o#|)4Hc&WyF=yE&5dk&QJf|M5*m%lZ8)c_t@0x zP3RjQ2gz>v6ch&Zy|~%0o9xP%8{gIL$;!i&RBv8JJd)H~cKG7erwXNFU+G17d7in2Bv&vbYp5zac2DJC??j&}x~D`NEY(sy?-7+7 zjL6F4>^m!M;4L50GtORRP%xR_re3ypfY_#;?@S73ngVZJa=jmOurXNF^qqFHZ6H7I z-awBO@}!@Sm4k)Z>Bjrgm8$mT=&B4irQAKwbD+@FV^P$j;ULBeXVOx;MT#-5<7c^e z-_ts=mwN3j{g@z|Fj2UHL}x0tds0$&ioHDiSS6zCh=D6f%gfLi5oI>?;lU(q+Bc)F zmpzrPRAmxsXSwvYO6_1lXQ#ML1-9Lp;Ym!z?$5rQ$!R@_GHO;TkiJ>}eoV>Q$K-da zuRf)_^KfUA4r-*AN?#DfSlau0E>&Q(3qF1Z;9uIDk=C|noz4zrOGZ1Mox2&~2ia}~ zpLeUCejYnH>+b$_XXoime7dXr-0?uTC@;MA!8a)~CYoX__TnbT{)15jUjZ*7mnt`6C7X^HmpiNm zJQUoECH@z8t}`o2{9nA**$yvO=+_tekCq?uP>Dam1oqp-ZcLB$&_)=5`P&; zR{ht!(}WF_cVVy)AVWjR%#%PJ4Yab2QYsXD2KkJ_1a)xepby?>cgSFh8VEoR+u$xVh8&;!YM9r zjXONz1@HJGKwE8HwgdjCvwjB>O4uS4xoAPm5+}9NvmkznN=gb+!`cB#M@F*fitOYf zFZnA}(MnXBa#W-WF0M{3>e7J5H1kzld!Um8ztV#del1=q|24XCO>9cjo7LPFw76w1 zq%^yR^=x7*J0Q2-J`QxaWA8N#zo8*JGRG0%4ClGTRc>&bdpzU`&w0gLKJb}u{1ha~ z$R_^lPH7s2*E^sYMWl zWd1&^RB+i9rRMPARu%lzc_V9x1Kx;X(Hi@r3GYq*jz(C2-XD)Gc6Ac^?rcW0e@B2T zc42dU^?Gjldcs$}9-n6qxr@9tTNlS$UyXDN3u|tI*(fxwl4=Cqd zH70!U_Kr7d+#@SOBhf(NlVtm=miHUKqqq1LR{Vok`dPlhVcz(s7~_zFkH4y%DB+B7 zZ-T8OH@oqP2J$~l7Yv(?idQG*FZuhG$!-;+9bQ&Aa8*Z;qYFelhj6ko9XuG~>#NTr zyVW<6du4EAbmn<#{| zCWaZaf(*Cueaz3a(cV?9V{49uI#*dF;38Gai1!rddM2bh~e;B)31M)B25kI5IDG;<}uw=`dfkh#Ai%!?TWVL5Ng%ogov;e=+r zIo$1=?>f)NZA>ZPOXT|9O}b7%XiMffSG*jV|9QX)HPs}p#0Va5yF1~o@|<^7=G--! z#>2~Q=5`P4)}?&`!=7=)^Yfa7eSD-FZ>(|}D}$UNb}~C=n5ZA#ZUs+z%7h!~iCLw{ zN8<1vY{uCoeDzLlw9h)TZGn1Jox}p4XPRk*&eXAT>)1ep7j~RO5!22yqo0PvEC87~ zX(MBD>20(HWoc*+1nNz2oCbA*3Z2-*Z&2`|Zh(^is)qg2H2CH4|DAXH@@pCzQOM1Q_hXdudA(D%9ha5M739|-VUD0>K3)S^_qQJ^*}6^W>H zo)@fBp6}+7XCpl;v30~~hsGVmWV}+Z?R|zg)bo*WK(FEDv5DhSP34!dktN=UuZBG6 z!Kk#WYWDzf`v~1}|6>RKn-6qFEk5y3@DtGx|I@%D%|kTrjgU-aAzL}iLw*WTq+*pM zl(LnlVhw7$rZlSqTG9!v>YT1{iwB@;nES`%zEHp59j`O%&Zq*|jHZ~Jw}Tu1pKsfM>g6~OKNVpmbe>wPApK5Zk^-PP**ldKAmd}{UQ4=FAXyGzc- z;rg+0=URvOu9@LNS!@lwqD(q?;3tY0GBoMOgn-tcAQ`?nR#WYJ(_IEYH4!f(Upk82 za3~I~`G!h!%C*u1AVYx<+D3?+ZWrRwl=AXapfj(`AW*1)4a7kp6*|I*)Rj<+4`0M){mG1mD`quKc`L-1A<*%{0KSY%%@R#`al5T33=A=Wr z4gN1z$(`~gBz0O+Hyk7yqNdHT_WxJWOf2%0s8Xj%hn`Ig7%^eSf)!g1HrvL<4!e2U z=b%H5I_@NIXPk511(#fL%?&r*65zJGf&_agM3~2(itZyOS^oMb zPk|yO%2ldXt6rmKt=e_!)~ny3VWY-zO_?!o(F$Gw3MKk5h!Kn%WQbu#7$wYD<4rW# z6w^eCHbaaQo9(y79-p}wA8ipUVam#DsjaPW%wDk>w%{w{THm1tQ-g4qn+uEv?wm)7 z@6T&PVb1?xz$Z$O8%D7I!it6=1{t-{ZV`yPSB*IN7Mw7{JEE{9gB5S4f#R4>B9l0^?FcM5~_|s}x=NDu9Rwk0cCn*YhZ&gN*=P(A(3@ zWFbB%p=seq8k!is0ZnL59W{=3!4r;Hgeq)z4D!~m&xb&L(mESPGcbT*X|iRYz6``y z0gpG{fPld?0C_hc9|hC|pw52)y-)z<3#hQjZKU7e*3B63@y<8ta+O;P$EZX_mf7TP zHv{k)N`?#{BgK2m?OZ#-5eXQG&`^PuS(a&~9}ep>jJ4PX_u1pH%l671nW2nqtTRjg z!4W`&6get1QGhkZU0`Ps1$+0n3+$t)fSafnnE0$HBw!5(9aojXx<(scQvwy+;D>mZ zYegA#HT^ZGDqV+weev7)o@-6v5gyczv&nHo5k9W16k-~kRK{(1WytYFd``I5MED7Q zBQJym<3sIU>U0^NkPsG0a!OtAB`KzZcX0zA9{QPg@_gi6FO>0#>#1k-Yy4~K#63?3 zfqWAkRjzZZHOf*?D|5{&GlMQHB)ZBK|^{bCJ42W;UCv?vE?ebH3eES%yCRO?# zJ6%1B|CFGJ|98Ew%)rwxf8YjRC_qFuK>)DfxY13!ILZpp79Vg-z`P-|g+w(1d(kT~hvUN+$tcRcX zpC)vTstg_A~+w5wN&m3~h z38!6jb$|?pA{atJWknER3{b+vnhVSV;z%ILJW@cCVY)@+kPlwDBq&m0Ba|&oIxDI(_H59BT;;LI{xyabCS%Wg|gQLSHc*|h{Tc7||Ls6oG}rHGpNq0A^Sw%(mieoHuq#ROBV*6NH6BaYF&8I`4Y5AA=k<9?^S z>wqRb?;5h>SL(w#tcHw2`Qt2pf&H;OR$LoGBSE}j`{h0O`N4G_UO>1~{MeMmd^B~k zM_-SA9&dRJ@OV4n-2o6c2+>DD8w0t~5Y&X})h43$_q{sMk7EoE3(sgy>W_&7@f~~* z--n?#*L~#7{qQ{MlW%P9uf?rLdV6!cV1ujsi;04WhW9tmf(nLF4WkUkOIK&0?ON(7 zap;gIQ3heKGD#biMzzTbi!fe>*^#_T`(3%6>P+Xl(50?)t?PTS?+gbJ%gau7y0e|{ zVwbyGUJ2wrrIbUa5-L^DVNy#S4MEa)L+RKR(W;5N5qkum$~XXa=*$G5eIIuo`8}8J zE%|v(fqc@=xXB>7gMwT^9QyCmfc)er1^}BUZvmjkY}sF58WaF9{iKS3fLGCV|5M_+ zJIHV_0B9V%I?mXsI?acBJ|6;>Zg%Cp(8ZRutFu4|f>01TqPRY|&<1VzMlWs)mbtQ3 zu4V1pysg{5TbHXXDji2+~@a=hiPzAZnGTNxx!F>0*=$MNF~B=1;< z+xf8}P#Y8va5Q>LK8x%#WT?XIq{`I%*nS|lMQ$7XNxz04xcn7-R1ebeG5Jj5UmtU= z!UkM2F|>M#M41--8n3N);+nRmTfb3jdGgyt_u9~%W%p(0FBJVswIJ?8kjMN?{68HlRlg=r2+e`aM3tGb=+KU_K!lJ%`eaQTLa$ zr+z{IE+@hHe}?@Ozh8#?o>o5J6Z)+m+}EDVpUa+a8Ndc=-`P(O2PXmewWHe*0QfWS z-QJVzzxSb@w*dIIt9u6k3hC8=UVO{ECEY&V5^nF}UXQs2-R|A)-24H}u#F_@rPo6(BG+RD&_fEj8KhfA0OKH+X1vIw3i6=1-|-csQ^=DG^;!D+ zzsU{iX?EqmA>6p{sBI&@nj+sEiWB$~^P|3MpAjs7e~!LgsD~$r@OHT0$u#`e>qSTo zRcK)fi?Pb&-ZYim!!~s_qCI~1bOb-~spF|B0)CNTpNQq5v7<=~fEO_^y;7+v z`Pp@9{8Hh#HmA!QBD_%NP778X9MQ^^sZiig#u%5t+Lf#(ybV^j#dALIdRV{mO0iX? zGuLmED9W+|3iNz(`O$(B5k-NH3L$bZHrmDJZN%Zc$CtlANBmYSN4^Gyai|G}WrSig zbN$lJtTe@#T=$gNZQk1kXUWp{3IA6x%74PJ3`^-Y;DJG^%Un&hDX2dufrrGgm82dVKtBd_@$Ei-vw!-Polv_LhwaVqLaIwog>H+s##;?0P z=stJK<$4bZZ=J|CZ6T%|UiXlf?Ge`_;`@WoeI%`KB=^-R_BKYv$dEe#zKjIfI|v=q zqi6bbZ4(1Cg*{6~X3o&e>a39Ic``WAi&p6?D~wz)lUAZ|Q7g^N zg*1I3d`{_b)MzD&@gTVYbrZEhgKAsK%8d$M^S6+rMR#BQ4SdXVs~c@>i|r2(1qpGK zbAlptjDrI;+zeOZ5M6Y19(LaV$GeBv6k&y%inqu@Z&>UbE2K;@T3c#}kfjALrDQEy z)lM%w!3Eh_9ZW7`CzC5@#Y&j|9GfqVyO8q?FD{W^+v6YEHdyC1ZM|Z4l}<(F&XO(t zUC$5p`%ao2E_(jken{Ap>wexjhQI&@VK9bZ=w8-=2;#F36{LY5{Acz?BmnFE1;Bpa z0JQ!CK<>-WIrN9G2m+vJM1^q(1XTbPdeAFFfgo6|IPh@bF=;tY=D650t0l}$Yk-ev zOjH!poVi=l^29>lL_Nr;RA{SWDeXYj%4tFDyK`bZ&!p@0luYIUH(n7~hMNLrReVfp zWX{1RumUe22r}lv<&a9PWi0|4Bt$Dq|e zTCa>k-Bv-`l-&teIP#=~`Y?6hAb8-M(7ciI$S-XpMF#EGs4Ojr&mnqppL~pIx1<=V z4A?5lDg&2fdz@zlke0|^s5^JhgMK?IS8NGsftzwO84FcuUx@3=x^rwv!X^yEf=yJ& zEbIHE+P+G;j2lr5SOSEhrcFBzv+plb#Ru63qa7#xPH2;(wzp9Z#)xl}4PD$-Mo@r)BK zr*D}jMFbBcE#z9;mQO8CAbJv|U_C}>KJgsqzf>B()``addD6uYo3r}tI5MQ#tLm~S zk`{oe+F>?Gy>(|J3^mj@z#j1Txd_D#nkDPCuM@ffRsxU_#;Bw%vFk#P*IO7?Nm4SO zmy(jh9HbME3MEi!V4xkq&NqI^vwvJXZP)FmQ}omsb$12?FF3uPbG+WUMC0tPu`J6Y z%i3Q{DFH*LTarxNIIh$5MJ_YhBIHUkS-5Nnc03~QQw;#TUujDq1B|ElpUqq^bzs_w z+O}+oYV(0z<22Tz0f#(RT6nFQoEGISNyp~z=d(KfM~_dU6DOh- zA@{oDX6FS8m!7giXO?!{Fwvb+6Scuu`>9Cc|ORTUPvc-&^BVOFO9{^<_e#i1Ya##v~H}idkgzF#tQlYcT02 z4Q^Pp0N^la#%e`i#RrbB@s_QRW7VzmKq>`nIHcFTg;t{GIx7kd}6<(i-n7o*zYX`R3IDa)rkzm&@5)O09Pb@2RLi}BYDvE}oOgMlD zLPAK@t1FO8o`wJ-t@L;{lSH^{jB=SN_9TV;BI5zfp{pws(yZ^+971+b+dxE|kt8bV z^oqS-eN`~$8_+t+3m<3)vU!2%Bsog^tDlQ8&|evhZAyxz5{_XJt5C=s<~fW&U%}U* zk1Q*&mm`yVPqxG}B)PF!1GQUTD0uiZgPKwB)MNS@`MCB>-C-ife)`|Y;&kw|0rTjA z0QMUMPM^&}8PUfq^zLWtdP<{;zMJ?i^^4vH5a-=V9#f;Or}wi$)x8 zLx9lUm`wxg)B40ekmv?s?PSU&KG@{oPx(@JMs^_cWo-Knhvcw8kM$f`_a9({Z?RxN zF8Q@6QV{R(A(=fsn{N z2Z5>$oX&~NUBNC~n~dLAqpS8@`&fA53R0kEp-({ZF9aupsk9Z!DBGPrZi&I-<-ZP; zC!meD;85Up#f=G^1(j`ZIn+-J(?TF<5ZX5(W<3Vt6p#?{=x}nOl!s~)Qb*?0Eio#x zvhEL#&=^QAVUUoFi+)9hvINk_Kgz`th%hX?J`Gc@AX5$6c>9e!gD4MyyNjIT(A(j@ zt@zljr1n1Ld#eN)>%hj)2G#YQGMb>Mdpm@wF7?*_Jj9_~Ye?uf6&1WE&Av|;y|v`? zOsmavEm}TD?d4{+d7R&vfuti{o1EUsVL?`QF*uqrEW++%XiwpIap!r%*H*?(4E8}p zMx$~E+wu_Cc&5j8c&X}?eV&0RrozrreI9_ivc4*h$0qdnw!11$l5u_PK3TTG85t@T z9G1qyQjMS$=-3B8fdC^w+`l9hPE&iAy5TC>i%{vWSh-Y{3~L&H7+C2aCTeUfAt;k- z7KW`lP&{eRAO?;YMd>;vq{0 zN-?R)$)jxkCX+;ecn{aYwpyk(w~Us)K!3?jU*M~6NWS}iZAwp8xjZc=DuL8CB6dlC z1~j@EU0#}6Ssz3{mEuVzjVb@LeV9i7pzV>E`)w>{Gj1yQ*KL#5j{0N*D&E(DCXC!e zTtPvsk?e6e%KDvPNPrr%5$G^)Y*<90EgF) zO2}||Wd)!D!dksd7G*CTU5h_jE%ui@at)@FuE_fUu*Vl8rF~kEfr#@p*xoQp(fL7# zEmls|Kdvb9mM2|03B9^`&wxa+1A_Nod2M1`!# z8fN!+7K^Z4kcDpzuawCTNzBCREJwx~17ws2jN{p6)p!+1;b|CK?Ug8kjH~ zrkE;=FYh3lKlj2&^(Hn*zccsHm^ZK#x*#H(>W&$ZOnOS7@NUQIkk5(JFgMU~j$s6G zYz~a%g2q;^6`F4feLqYQhGAp31}pQH)Cvi8nUt+D$?L0f%-?iZ~LI(HtO>J{gnr#NCxv^LrK0Z>zcwEZ>46 z&-dLl56*+BN6HjW4$-Ke+^qF^D?eZ$*EWq;ZL69G5*)k0XzqbW2{6D7E#)be_o`gj zZV0jp2FfD}p7ZP1t9|G9hO+I(GV9lCzZQV5YO`?JddGB?85V|=cCC*Id)m!s0kENO9kzz zP@~81Q(L6Xhi`nbvGJfU)wuWLHq`>f_~kt$~MK30o6 z#~A6!mWg9ka2|o&!`f;n^cL@48tD*6W3@oRvSiSLBVR$W;Vhq&(M_IdMJ`Q{7YYWK zyS}Oe!;tv=7u4NN;1xu{-q=3_12iTG#{RVeE6pjlaj*`#i&fl*T^)|QWXj!Yh+(62v2|aVO`}3_- z*U>*dLr;;md>_toj+A}(pQ;758+x`WXJ&)OjKYH1>6rzSFKGo~{s@O#p2Ic+-~guV zDe5q~vq;mOmnY?kEnS$a)GHXf)H(dBNFGdLpGFJ%1>QqMv38}~kN5zQcL$1)Psew- z6X0NpdU{{&yD>0On$XiO`!zY8z9KLQ+_WiMWy{((>xFht&FAuAB?D~A2g~(hzRrXy z!C7I^a94vO@!QO6qjxA|r$e9l7M7fhaf~?KOI-LTaY*?ITxoKY{Z*ef8KJSj!#D12 zKRrdl2we!je##d{$LqY=lC2OJODxXq2NALmUZ5!T_4Z3P?Bp$+n0rB+WvS2Kus0%C zj@b_;iplBf&-2<5pHab(vRM&}x%){jZN~`=YG$X<C@?K5G8(je8OFgFvKUKVyvgIG*}@ zWNYdDCxR?9dBO#G(`bRJ0G$GJjeDgcTkR!|c5phm>z5WrKocS(W$Drv-CMALl1i~5`Yayb*4tw{} zt5|9?vTSN|BuRp@o+g|MPE`YTP67{a5twI4iW8tZ4Ug0u1j$CyNQ3d4DD;$f#=V0g zOM%cr>-lsYTvA^#Px(}cM!hIw(xMaP3EbRRhe~qt1TE8j@53v2kJokjD)lf=mc1im z41NtLtm{$R^%?3UkFF9h1a*lvu{FuI&^CM|gguje+(hn8sEGyTxqF(PHTT0^l0dDm z*{X~Bq#J^;Gkqzss%h%B&BfR*s(5*pdc|vx?DmHe<7ThUZ}}*%H2J&0stAr7H(;q9 zKY~NAG&XKT;3$gcY#s)}UEAOJHa1FTKEQ)58EM`U*PP#O2FyyW6Wq!T=c|YWHjr`~ zyYrf8{V9wf(nVXx2>HJJ?iH>~fP&9|nbI6clQWLQFHW;nrm7%^D>b$^01OcD3f_Br z#CWK4IP>|&n+4quI>4gkD}gc0->$&ij26|`@}^i*h5rD7%8C2D49|O`7}Ns^%`T0r z(^3u>eew5AQG;ix%Iy?Dp<02z&oQ#A%q3~8)^gDIQ?~i39O+0=FGgo6&2G4=QjcAj z6>96XI~*DMhx+&Fda%9X(tEl!N){mg$rCZ4Equ&YMmdyu7bd`{?cI+tU)R^07{nn$6|wEU|y=zb*7vg`0H z7n}7w96+G+F$|8z4BZRu5QRALkO^9SVM}nL_4^* z!X18d#+UYiM!SIrpV`ZU3pv?`+>yHh2KS%aN9f)g3d2v~5o#dKi-Ohe6GOtw_LxnD zc;aBPDSC~YeT&f`WF{7nq<8`+{wR>r!2VkZ)e;T+LA@5PkhzHev!+IQx(ww7Ibp|4 z9P~Bh+8#IJESI$MYAVOgK-*K?7OMdf>Ap>t6rHiCGNEDSu{!=Mfyyd{*?24i&kzMf9P)ZZAOx`3)mTEsC1AZ>|*nOyH^ zY&L5$ZPUu4q}Qu$BYH`@A3T#BfeipQ+lodGF8@WEhKN@*wDfI~)CzyJ@@r~j`R_Lk z|KJYPbb2rBLTF^xO~i%&gJHvA&??g@o}fIHj!=}3b5XBrWZud{>hSO2TE&~FOik3L zN@tB@7$vY`TEVpwFih*ZXCy52-ikq*lIL)2vLXX8B}Uc*@%YTZXc9IR_VP?`W!juU zTlgoiice@Wb#HNDNLFMOi7f#Svb;IAKo^dc58==(Sf0oiVWkatw=j1ViHc)P!fx`)7%MGzHnYb=Q-z zXBF`TP0CsOIq^d1MR5m;7zBfgvjfyQb61!3&qYn;_H@nA$}4V@`$cZ&=noGx4~0kJ zlcWjsw7y~JU0G{P=!2eX)Ycut2kbZ#9au{3kxK6Zc8c=Tjd)AkNqyC|S@bD9U)?O` z`x=QeiLBi?Czc;t9XzC!)8G%?h7ZQs6nP*cMu8kPi{+7n%4+7k+CFq$?|7>YhJD_7 z&E#429;=4Z>EJ4s-0eW!x)Y;rcYtSziRE*?qOZ3xQ}dH&&BI)J_Y8*9z^r@py*G;Y z=5>R6&6spcjJrz~n=fcnHc_tO!$CIuSLUhXT8*aVHD^6BJ0skgo~KqLbu|ew>ou*0 zJFW#@{wR<}=&mUJ1MY+I8E0H+nzMnBplVA=5r9Qy=|=a@&Qkd6ZU3<+wW`f8mJ-nj z2Bq%i+8Fdl<$02?-XGkwnlWq+I?uz6Y-inqJF7o{er7C$`XD)v(0oV#r3b|f_3p#R zGs6+_Ab7chaWZS0)8r;)!bG>~H{4>n+A8SK76yH>dy?d++PcxTJ~ zvLmT~4)!j|*|@m?cGqg3je2W?bY`ibeU;Fqivh_K0S$%=Ti~*f*Xr?Ho5-_TEHtE` zk3Guem59L*vYWM%3WEJZ)t{?#Y*AhZFFLJK`=oKZ-f`weUBS+C5nt5G{koSlqR(LeN_l$| z)8X_%-`^>0kFM57yh`Ssd$I!8yVJ*RPJws)L~*o*P7TRwGo+R|gBLhNCoAH=94C^$Gxtqqs@l0g5$=kkRC1g4=Sb8czxrFD}ZqY<*8|k2Y$&6eqMz z6DB5?QtnvlD~F$MtUJeTKVFiRvUy88o-D27$r7hESt?Kcu_%2{&$+i8=7HG0YLOOO zhRa6{OLT@g>=W=Cs{O<&O-xupyGEEc1iAK6sUBZu4kttVBB zn7lEOAT%y%-GkyI&n89LL_U3V_BKavezSa$*U4P^a~sohM(&KF0})+&|6t$2?zmm4 zMr{G(rq0LG0s}A|ngT8bSt>Iy+m5EEjm8aJ&klpS>9SJgzXoq!_gxO3rVHD|I8EtI zG22V)J@{l9*zRnDKf6GqffyMh5MUF|F)By}j77hQ2|Ynmu9Fjcch%~NQxF2M2m3>d z#b$IPT24PBW}MJ9nXVIs&I`N)?z6L zL=~vWYNG1uCH$6}V@;E(IqCbXlKO4xTxCq9_MH8yts2E*m^3dU0qYoL@^F6NVdDIL<@I)| zF&X{VsZH#5m)kf`AWz~87k(o9*q;(hcG}*W%I9kN)2NC4#@XI| zv2P_mVn&Ky$M@L)P037}=&I`t4}&rH?qN@~Ao(O$fm zPPtffLW;S{xGSA6qHU*u29eAiy!!tM<|}8Dw9Xp5I)tfkJCWy&jD*^H76h5~p`*%j z=Z~>&Lzu3p0XdbOZ*iDenYeh(k)vGwoASqXfN>u^{cHSg45|UH*>ZN<^_(TqE!h$I z6U*mtH95%a@SNW@O6pci!X;^#1pOqPs*}qUeeq9&Ue;lea5Fol&Z- z<#x|59)Dd;^?chw!spQ3U1%UX4I_~6e)sr!&0`|wM@MWY_Q!K#{qCDb@&f`{G!9Q? zx2_7}xHWqmMm`Q?mIHTg!}OVsW`niBwPt;d4k?2CUdHV=?@oUT{`=iw@MRb!zT?ke z^3P8;o#bEZL`j9Yfw0!O>l@>?)7O^(zns;=Y{}1k8nJ49=COa`9pBn}24Lzj+#Xd2 zuKiQCo63X+fSjOH`gs#);0Y=!6}9N99Vm`u-=7+RJGZ*=!Fnb;Qy4IRW-?VNr&uu_ zin|oEz&A=uM~A2u%i*g{=8D`t00RmBR{d|l#KCVfR621H`5`IMC-6tPw6S3U4+q~8 zFVRrX^SIfI0vpwmW-qNH5VOET_}H}(*6DzqLoAUiqOt_1xKO{uO_S-AKf1el%+n^f z4>j!Di^$BAgog#IT~A8lQ~19$)+##7#ClrObG=O#m|itYxU%f(tcZsDGmMPSrKq^G zflWA!tktW}e&v560$wh!l!qGM^y+wU~Ov<1f4of)uY=hi{_)_UXJG)G;VB-ecdnoOf&S;kv5C0+b5y+qNACtef_Vw3@$SQ>ZK8i6B~NVQ~DzES{||v#-5A{o1@xy+|8m$c%ES3HJ+p&EJ8a zw5I((fd;l%bp?h`;cMb6NOdnCi~J8km|?TgEc8|YIb0?a%+Vja&T4`t?%9Ad0~htd zMGaFrUCXp^(BRPe0|{T;+j}yh?vPop8SPXb@FAsJk0D0@EWFk zQbtpi;nXi-{3`jw$}ieVl-FA1Wp|DPMEe>1e4QrxFoT!UnAo@@^kFigd?8u4)iLo? z9%J$4GwIFQZ7!p>tmp>&LWabN=9xDcz+*I7&z$x;9A34oj&ND*xwZy{-?NrStDT{3 zcWLMSCj3V&@g>)|&)L;mzuqd{n7PUC<^XT{lWqtlE()RIRGAjs-UFMrWMg^`2iL1P z`1t9D9tb;hc}6>brnKH9L|&^YTe6eYw#+!kx}qC!?67N5k+Va5%4M)&-}tc4o#rE6 zrG=TEUNLajXp(22N(lPQ3nP5=xonN|nx=u?)&>Akee$^bG2pd|hV52DM3x5o#Jd=f z-LPFcL~N;VP^_yGGGz=EUQw7B+EftMh;AzmO)e<{GB3`Si~HwANnOn!CHQ}mY`F#h z4wcl@y)4Q5cl3+>Lho8Vox8SRf0MUPukT(5aEAqVhP17igUY!7K4g2^idG+T@A&f> z`4CrckR<)PMtYvGd;58hS)$mHQ1v7+voDKJcR`UVC1d!w%Zbb^?7FOTVckyKve9t` zOm>bSd_^eMR;WbuY@yF8;8u%C1CgoR}{e)7e~jyYQs0pZ;4@yA|{B zw$vR(-j9)>f&C;t8l!s%b)9tT&!+Z{zvIZKuA|y8y5-S(>=&)Y$C{P@Pyc%UTUW>I zw>RlvQG%e-3R;-`gKPs;M%Jf&Qd|2zDeDtM)sWjT%$#GFoW?!6r{31M(%aLx(x$#d zd5k+f*WAYcmKU>#1hvy4n^>Dr&(v^>^+tPG0^@y8Ydo`Q$!0l^^4UuX%RW$?=BFt6EDJW)aFSXP*< zYYj-SXHQ4!w`hkgPHwXB%|2UsLi_TVhcPf?aGlZpkC}Ub2b;e~eEviH$wq0_9lX9j zLi+r?{8kOzaHz&$Zbr%5dB>8wBq;A^*;jgPyx^!G{`%g zYJXYFa4*x?vig6aNW=0T$1&Po=4RbO&0yJ0t##GJm{1OONdK3^{z^|KZs0{kUCf+m zV+yn_c?KShYc&tAZOH{0`kMOM&gqxUDpz#&+i1{4>b!R$`DP@76D0`FM-gzCNGE$j zP}7B3z15z|s;{3HGxt0x%{c;hPbfjt3x^K@XN527$Lh6y7psB(SfaHT4w&}pRG8jz zySA>%tF>5$u5ci7gB^{Sfjs!O1X2H7uE*`6OhC`zHm(DA`5dm+&Cm0Ij-x=-Pi|yW@+8TW?1=n=8k9P2pTiDK>*=eKgd`_a!KPHv$wCzmq^p3aG zFvnVY0alSBkS@;Utp?{6EeB`uilxV-@wM4GIC?f72t=>Bg?x#nRIJ6IpYi8s7X$;G z2Erq%PRf}pz@1C1DYiD4 zkk51iro8WN4ULb+qr;!4sx*SrajkrOW_5A zHU*N#Gz1SBF61k~cY%x9#qRE%hF6}MJ>z--pO+L98}+ofdhO@4 z@s`fFfXZRB&sXZdEIi!!Gt@x14;0EVnXKH4T^K4eEBm4i2jE3ZdM5QA(a1LckjjvL zvEe6U0g)(F8loW9p6`LEnt>K^pAC)vHk8L``G2ECSHT}XVKw!_V%*~rfamb;tlASP zH2_zA{A&cxXC>ldgtf?kxSrP8H_D|qzPR@Av0q{`Ha@i|)qU(RG?6yro1Z@5qbIQB za0BDOyU#_QW^NyhaqOswO3k7MM7qDBy4vvRIY5X%4s+KwiGv`6(hF>kJXP4 ziwGGWPSG&nbpxWy5ez-ODsUwskqD~;f^nV4d`GJ)B$Cv{?|3R00znZd7u(x*(X=GSTke~XObfJ0^0F)XN3qhkBiH;bEB}?>#_I@Ee5Mg0 z?&@3n05@}Gq+d{Qx)@roio~MPvyrf_MkgaegghO5Da*Upof``)_P3%MQm;nl2WRwG zRz#AVT{9isd~zrJEH*{hqu5=@D>p2>Zmz9`ML8Q^G?y{f>D&7su+bJ;u#Kn=wl+5A zgC*{znN&49D;RMZqJkqZE-3h^S2piq2;8mGY};#y7Ak{Tw$NNpU)T|$mG#qUc)b9f&eqg}&g*v+5OU-sqQ*-) z?X8B_Af_`EH+&tcv(c*|z>NRhRf#&QotX|ZYntRCT&!?N%orc~5^#flGT{I9kT|oW zuq6ZTsY@^tVqyFmbHQtFwf^;4i>fy;kAI|jzv4eOSH@jy3L1uASGJJTo@l85E$KVc zEEVPT&_Cp3m-LZ~2h`7wacq9F@DIDq$TDrpq)JzJ#IM7b&sXpJ6cFVTgXRstpC2VA z%rY=!@7ALL2bp;o!Zf9<|3X>RAM5K%X6%Z?R9V`li>169NA1v;lsGDL&QM%Izn{7X zB8g`M5PvT4m}2~K7R;}xpi0#1%4|jv%gL~UG+G)gKY0aVGg?<(qNbjfsVbk!S&8;+ z3DA*fb6caAb3!HoE?M20sV1MySw;jjLp3#;l9u?DoZzWU)x@+?wYqZaQN&6zJU^9| z3NJ`rMp!%R$^dNS^)&D(oo1#0&+!xhrUFxe=Xfe}7I>7-f_Sy9n#?A8If+BhtTDF> z_VKa{29OQz&p$u;YNq(gd@$H?F(4@g8j+k5a8aCujDRL1K|v9mo+%o_6^_Vkn~p}e zuG8ax&@^fBKQ`zs`PXBUxWXx1QFtjS1yz7HIt|s-8lEmdfi3O-tFP2_b0q&gjQaDi zB!~|hWEn{Rf`H|XVpeWZ{Yo%iZ|Cvw~2U{;B!1I&Z-G0x0{k>=kI{J>S|Co zcPE%lP&c;(EPl)U(xy<2gwXxg-mQq7oXv=qUN{|r82X~6XA=sYThP`Xcoh9lyo$|h zU^NLg`_O%Y%_i1RJ-Z4H^$&x`R;Hz+Vk_Zc;r;+Uf1ZhBf}z6*$ay2TDn?-mjega1 z#R?uhY<<;iqPD2ChGpn_c|9I(w4&=mp~C)_l)GA)SmErx(pAaUvW1$2RuLl8Eu4TImYHsS0w!6 z^OO?J&)^WzQJ6s0;;-jzu>lb=dFumS0YrPq4857(Ok>e9`I&%Z!(`TQ_?!x6g+v9b zVp>NHt40F%^NWLG(_*!P+DYc*{Q|bj%P7yuAp`B`;E?8Mm*M1Om!4*?B52-3dXA$h z>#9kX^HtLvXIH;{Zmz(?KUBNTI18tpnrnj1?Z2R%OxvPpYmtpjl0c-duU@f(-VWJs zkexHEHoaE!K*A3c0T!PXjKkL(T!-u|@H%Fe+Z6U{9(F1T-rpN1=J#diW#-36VY1sy zXDshe^ZHkBapk8OQ!$bw(9}t$Ak8ngK>rG{D$k&N&J`?P>y+7H?DZ;MzgZZ+u*El9 z+hw0Io*^Xp{%97`tjv1t2VJUya_Q0*)Ayke%)Nyi0f&`%8W2;047sxfQq^~mwN3JjlQOPUgTCZIfd5iXz>cp*6cyc% zz>E{Hg@P1aolaeEVm@+kHar(M8;%^zPeS+Pe{9q3nb_4yE+Ho;6NuorK3%lK}3SWl}1A$~7}<+BKy*8J1QRsV-F05d!KTcJ!nTy2MiB0$@a6 zHNCpEYIDRR9Tpaz0`>7ujf94wB2SzTDoRL5%1;OiEr?D|z(<4mmeej(US1C>)kla7 z{Wq0XGMs65U31fHoe5Vcul$A{c`6$Ddv^A(Xe2&6JNrwKBn%r@Sj50#Fbo{Nkc9)v zE9V8BAV$y$0Mq+Cd>0%P`OA+S>TI?2eJC&Wbj$7P3t>m*xYg{7iOL>FjQZZj?H-8x24POO|k@mhJnw9i@(jH01Y;T6ieS)yT!ifiI{H)uugELDs%Zvniiue`&^kb~(p8KX zgu-7+U!gPu170X~@>?UY|4(0UMK5Y#lHXxzD=RU@gapIlVW>YU{`h=9Dxv%b^W#^` z&N-_@*Uw_kP_yC_lAw<&9`*HRE3cjz732|RW7$s4@CR+5sV6D{_ia9KhvzD=7Vnk> z8F`iwLL@==$v#m2+Wfe4;nxvWe?R*SE#XWl_m45z-V<+X-vGmKwVLz#yIv2ip-ij> z@Ahl)C#2}zySRqT8-aN|=@PD74mB^ch&sqDs}YdHq52>i#*z~?DnoklCguEmH7V$W z7P1o`GODsZz9UPx{)9VON?h&$G4nX8q-sVdI&4x>clHKoB!*Zn$cY?}C()MHQR zO*uh3W-iMll?E#yAO0rxu7EF?u1>x_y>Ki4=KXlU0K29a=zRK%8f`o5*24V8f35&a z{`@pobRDO=SmWa$*Cwrc{+=C+3r4yFUgsT-7Y|rb=4&PL=nAfPgO+(dx~h>cBvxn_p@h| zOgODDk+DS{M}8Sgbjb9Rg!?t~zg zsqSfUeg507S372z&ErYo#X82;CvdVGNev*yGTB+#hwncgXk9;e%`34gotMbY%qC09 zxfOD=Mxc>!_3psLF0hyR>YFAaWq^8_3>TX{;2gow#)4omADM^}x@A`s%*Uij+=X zx6aKS9gy*5qP4aa@DoOKSK2KCul?Z5?Ogl@5kP=J=J?a>-#bhij+cVzQ1gB;SA8f2 zN84s%epel*Vg4*1U6p&7vO9PwxmCN&>_5kQk0;p=5fh_=@z4OGeqM@Zjec8TNg*^i zs@PPINF^RmbQmg5iVP`)nhEr9d72%1?SVvm%Ov2=gVKcV9!{+#N`A+hvfNcK|1jXL z@^fU2eKtMwVie(plfhw0FyQ$k*dTex%fAv#FvyJ+Dz*}_U_$Y`yrqr356H~?k)Dkc z01wdc7M9@&f8IW~nF%C}dr8ZD2>(tP>GsoksaM({C>ErLxH=-cm6!r*|G8m!HitHu z*t7vX<#ozFj|LTI1A+0Hp!~X$4)eu%9<5fPjhisdC8rt55Jl z<52BJkh)3Trc`fJHz^yNCk{br5dr{ns0G_-@s8g{HNjF%p7ZNL+zTE&%lBll$~g#E zIKu?rUELT5Q_qkrSD5RNPrjqMLW5R^$9QZZBrRMoc=G*q zK?X#Kmz`U^V?@6iFrx6xr*CGhUN^q-Z+4hFbpBoW!C5aM>cOdlPnl2Ym!CZ!&C1lu zi>%&NtiDUXq;;n$9-!+KYG*x>WjfamLN6CL`$trcQ3D@mkz!ulE}`QF;K)wH`zdy5 zC%*DpV|DyIGNN$6wi9r9HXRlmQI~dJc$MHjnh$lslV`!F)1A*>9obKh8?Rg~NPS+_ znX|u|l}~?y#r-w?l~ZRU+1h1Wef&Q)ihSZJ4^mi|1E(M=1Y3nTPGa2PEL3H3#y~)o zeB<@tpn6ewf2nm?L1&UTFFrM5jE^MH1bM-m#rB1e*W{t^UIGO`lGCTwp#2JbCu}Py zRS`%G9X!dBDJ4Wn#J&$u#pD-NWw<-$6}p9x>$;hS_t&02lU1bUJ9yh0P&EHB_x1EN z$2$dsf)>4IdCJ#AkgBo%=0ny0#y9`3FG+pFow?>S_f;UhuL*I5pbdM@;7?%B<5Qfk zW|1pf{`vAS+0!2cd$K-1lCq0DNIK=!RC$ubCF<$!lK!xdd|LkZMuZBIcuT^0uXGdQ zKv^!Bo%L(4vX=F*(pO_2ZOHn)M`bb}Qhn8N-qA$6;nJkI*peh)n0U0xez*h~Nys?R z?Rk_$|JtgoDZP!hFxo`lKqJ9q0XAZXg1vVz#-XD)Dhf%rI^m3y<@;9?@1)>I8;Yi1H6_N4m@-m3Nlyol)dr5ZTC?zS>-(FV@Jckv$>&F+^O`{9--gP4j zjZNbVEpNR;gD_#i91HcPR%nObh%7=#MdLRI%_@YfVj2)!rI*~6Ax7- zZ8W1JJc*|qkNHhzleMzPzg1#Tf18h^)!*x7F}KQ5A8U_LkdIai+G^v9pw=^?M@p@a z6~@KJ7h|no$J<3&8Dvr$3wY4Cv4zyW9&eSVn@{Z%viX$0Zf~`^H>y6!b|-VH1w6Ky z!lu4sd>*vt!ZuiBx8~=znIp&*5ugtIJ$#zl235!3L*?Rg za&UMQ^2D-u9-#JYFt#ax6XSsJk-&q~xhjtK5iQ}^2w1FInaxg&V=thD5wR7!OR<7m zH3Pg_0vP71!8*XWzMs8+U+&nDs)eduss+q3|R5x=KrJdFJYk)O#4jewy z!YnPsf5P%X>540=8!BW28c@!6sWb0i_qSbsa-SPQo3eEMZBXvG+WVi>)~5|52tQAI zEz(S+#MKHsJJ3Kg77%BdLX?qQZL^wX{l-ZGhjQp_p#Azgi^HL`-L>88zHtr^PzL%V zOKM;4`T1%9@_s$6Q@kZ`s-z()sBy{Brx*PJu9)7eRCvq$2ts<*R^av%>bktqgGj>6 zO3NwlDFLJx1g3`uVgxjt)CJ7e%HK)U@6|;O@vDH}AD~9Db}KlP58&N+aI8;X+boKt zfOXuet0S4v&Xz-RK%spm&-qi>p^2%ppC?nk*8@e+?LlQ&Ipj0K3z}HY>vVMBi^H*I zYF2_LvDbgcjF1+Jp%aTu?fw71?$cS|7~DMI$+#WhXjUq@OCodF{ON24X&RoAnYk~C zM1lJb1#EFY|77&~p7YzgjA#{wY)~<11_hZ?q7YK!&~b4fE|GF^z#Q570Ih%e!a4f{ zvns_^wN)}909G*^fGHdcjbeuL?b0)mXgJ(F8Iz!0dgQkDB(138CGR?QAtt6dL~zj6 zGYGAko0b&_V8XnbJyO;;_N7Mr*Sazcm@LSN*dBMT(XqV<7M0BS)${aOf5~r4@w8rr z0vVOf#%*ctpm+w~FERZnlCM<*4{FDZA4rJB)){(MvN0i6g}zKjq6ST4H72DoH#~yu zuR+u!m%%$E7N6{kJi5EwRG8X(p$N} zO;H$aZ;kh_b1uDb*H?w(AH(qVcd0wquS&<2fR4E9xUy&1P8P=aC zG++2XAvkMSy>S-(UBCh+mbovB#u>B)fg#oFS|VU z$*p2~=0GI6`SL<+V4bA~^OGz^evOUyI0zLTT%wnXbNg?fAbE_*oaZcv}=Yy4V}Av?9SNzb182 z#G97B45GbH#wbJe_`!u7w}h-3C!h4w-Bv($r{Yc#)Y%$&)O3D8di}@1yNcFVI9V|n z5F1vI7!(@l=&9GQSC=4=klXs#d5GsnM*p4n{J4YNEG}g4XK~bo@cq`sg^EDW$U#gs zrcy{qcI42Wm0u-9qv}wZiqIhpr#j5Tt7jH3M5TC?SQ}dru@v!us!|I9395Ge2?q9Q z#>Bf#j4uW(zA)c-q~+cBn0tb@J~*#S0EmSe`|j?^5g4b`+QRq$BZA%+%wigak_i60 zN+Y89DJdg&5{V06SMPc!jb$0=PMMLHdTdLxudl$1^X@}&!+1WLURF?0MJO%pETDiI zSO$&4L}wIKr^t+^CtWY-r+ww&S`!ux5Qdm?SB(?8p@P+Aju+MfXhj)0xa?R@-^7R% zI4;;-5FSq*_s$-D(%Ir1MuurLo>S3-lTw&7o|v>5=kzKh-xCi{O3j1W167odDO-Sd zpiM-l<)hR7CYvzQQ|HPS8k)NHr`2Q^EAS!X@UfZ`Ow78r7s*CpQ*!YDUVmoWvtuLAcAXFe z(^Zx9EPTRbTI|n>LI_n=Lr0Jj2=OT~TR_3{7*ct;(a=D7NNC;INChP|lpVsKxTCx^ z?hQzK)6;yy!!1(1u0PS7YwFsC-8t4)#LqF^e>1!O(N`M-c#d#wbI&5M1=G`*?yp~S z!4njI^h8E&y{%z-0JCnXUw>Fz+&dPm-lfr3oz_e1SRnt@G!xc!tRby}-<{8^tul5u zH5ty8l`UO2lGh)cWgvH6t3*U*nAbbJsv@+$*BS zkvB$ai7Rj1zBCT4Y@mfgV5_;$cU^2tt}HH!6GnPS;FhGHJk{fye()sq`aMeaJ(XJ_ z(HLgWZ5ey8Pc@0(3$yP~r-zi60^c8vaKy+nNqkv{OxQ-f9 z1qhFOo$Iywyo$`xcfTG+8!D=1mi>&(X)H09HTuGQ4kLDm*{EEWh$}MY4woh!PSWQ! z%J_16p5AXHWaQh-!$%W0C}i$Q8WGe$Jrip;Labh^B06JOZJ+A*R~x4 z$WYw;E6i>3ntS{?m~J7P`ruM$dc-fcfQkd`B4EFRoVE=fJ8It(n!D&RcP8}{<;wY@ z2xZdM{Yk9TYlyvvN0Vr$N*jy5l%^jo&btsUsgum~~=dfkViQ z*ma^uJAfE8#Wd$#>`$);x(seSEt}U*1*bOPz9%4r0(Qa~loYmXJ!vo=F@X=NAJ~lh z*3RCd@d3T1+xBDd`u>w4mR6a?1{fo#c_iX!(L3;qt6Z&qsRn#d^T2BF#97Y$1Ue+5K3GMUK6`*b$MkVa zYnPpfOZ{37VSLZu3Dv_^BTG_JU+ObS- z{w;X#eYWHN-wv#<;kwIzLyQPu$G5s5(vGbKcp-2~C@j#*58y{uq!&`9H96MsRFC=; zOQbj>GN6v{&x4Jg)FV=9_6SlE$3qNgk@kF_B-e9e-N`TO?H_No92%Nk8J_>(|2uG8 zGy7WFZUA|IU zKFGr9#nm+iF331_%(=4#H~)ERzypchN@GA`brvISLekpCB}83!gZM?1PrAKfl0GqQ$HVA0PZ9<$4#;R_e&pe}FZ4G8Tc(Mk zlggRtZ@Wp)C@0)hB?PI|n*rSR$hoYXc5s#T=2DYOlas|HNx#`s4t$Ny2NIBfy3h%i zge-YZY%niXoEEi3paHZiM;Qb*3KlF%lcWOoAIkb!46|3C_6kY({%IyIVY7E_%beZb zJh!p7%$ruErqc^G-c%41ba}>5?&Aof8 z%V2H!1=rqHe|OHT@*Bn(HpnkcjdLZ(b`;%xkv@=Q-gsJM(!;y`GlX}hS<~u7l{&S# zNmR=f7Dt=%)4aI?kS};j!epVM9NDPYV%0|L#$(9tz3@-GQ5<+(1Z6KtO9M1pDHs3& zO&+dxw^54{QaXkhREbOTlJJlDx)TUZ8INz~fvJme{_S1$X8ZI#USVXwisy-APoZsd zLat~oe;;Jwkm;!gf<2pYps1bM9r&5(+SJL>*Z<#q`w~QbRrzVw=EU)$wbI$`k$N37 z&%$;`9>-sO_({gLSft?Qx5f?nHOJZOMO( zaKPt*bJ52RFg$X1${KHQuAm6{BS8MmZ)lxeXHEIwLImQyN9{lK<dHAI9-ie{SFmrHOEUG65hti-CS$^IiL=KTN&fKig}n6i zvnaLyMq7Y$TBm&U zAhKj(HQxqGte#8Fx|aTbGwg;f&q=~~C9=|3CNqm=Hp`jH=Gl}8<(FFJAhLu*;)ZU} zl74o%ls?r!W8rFWy{1_G>B0<5v1G~fE4j?JIVUY|tvh^|I5gWUQ{smcg-}y>idq~D zzG2v?SO8c+r@u;l>jERgY0;dA4KO?G0&*$T_q4hqE=U^&L-S?VzSfode@CLE><}6# zg$y>#ge*27bozIaGH;D-!&WmgX@FCh+om_Q;YpMZyrC+$qlioH&8JwUAXe|xCU$L} zlVydm!mqN9Y=%oj@zDSLAW@K$BSs*xS^;-~8C^9>O~Hx9xuAT+G8l@NX&66ku#RoWH5H6~9l#^z|nj(m?jp78dZft7#IuH_!X`M-AMK!%niM0^kqQ zeohQ6w4ANzUz6ph@UO1T9kwqgs@it89B!cJ{ux7#ho@10eiV1w{-4PDm7Gx*-=bF#0?w;dy3Ze&uKxVf;ty7L94(-41(~4UqVndSIh^1Jm zSx;5?=iNmlQFIt$69_*<$a|Am{P|w5z4~EwBU*45SV=#>9YycCkHx69VcQaSr+s#Q zH?=}Px!+5ddNdl%8817b-7xt6*- z6VXA|FuJe5Zf>xv<5p+`(h3DbV$uTa=|8Lc4eeUQwqG1dr`)>C!PYE+E1_O0Zt`va zb!f?>3M9hlKZ7+hPdlgk<-Kr8L;xq9QOuWZn2(^+^%%Gcv zSt^wA{t$Iq30H5a;h3sXp}LyV*d~{XU=|0ZP2ZFiW!x0SjDjHJ3M;~WXp2C|y@Xp^ z$Hjg85XP*2&FN+y(BIGbP$m0wgFXZjmK>kQ+ zHDgU}Lf`+1hBKDUi&o6dol^M0OuQ6DBBD^lgG9=aNE+RnPz3;h?U8TKD&N4YHL;VC zq83fU{{7H6zfEK^tG3dWQSQd5sbsSoLv~b~U*-huR5P`EwN@uemM!j#}IW=w$ ze3#>Jpe`k~X`?+|RLsLO_$4=OI#e;yjUGPO7c8U2XHU)a_I7r6owi)vR~?O5`QRHH<>Jx%gnNPnfIJdE9=E@TQsw^nWby z=;`qg2$=bD!Leo9JMU1QckzG#nW9d5IW5~>98XTG4JxE`hb%&u`*iyoK4-ZwA$z?c zHCFoXyXH)}Z$%4ZSQYP-209l|_4>LTdiE?%P4$Av6A=a^Rt!kCE4eVxII~dvQh9FZ8k>`H&wEC>uj0HY&SovZH5o zX{vGi9Af*2_kjVKHM~UaBG`3O%RCtca!hP1Qop6F)xQj_e-N9Ck+K#~hwoeJdOYh1 zK4OhVtsc%a=`TAm?Q}alJ8MqDPs$-xQ}E{8f(h9PD3!p5(6O6A(Xy+U32?tG2~&;L7f7pIJB#-(5Z0ipf5PY z+~vCVXJmHQtbBHQmbd)q*@Nb0cmyvi$stQYXM?1sq6}k}*wzo^U$BNMc1#uqw(*Pm z_-rAmuZ=I+HeQ1m!jc433ZR4z_Zz%ouKY`)B zzm%Z&=6nsREQ+K=IEE%b@)`;7_xE{hf>9bMIP6vR*jf!ObS^h%&J}8E@^!J;{n*tJ z8{1y`CdU5Pej&s(9|C-WlGng(BqnotRCYAw@VhK}Saxp+9q(UMg!d1n_hy5jwfD!Q zH`3c&?a>@ z-{pDr_~@wneABtlU(9C9$q0mA>I@bm`%^(7Xx0_2tT zr3jf^ID!_viR;{6pY0scYr=Ha*PFt@T6pblalX36$~~J5PH}Ab=MDPTMGAr-$r(qX zh5qMF|E48))t**vmfQ^J9Y4Q$tLrD$_Rg?^VlgSFV!)nhU=`-UoYA#?I`+UNpCp-2|J2Jey)>;A>@?l=2tSUlwAValO4Xptt6}#gzEbE(2UloAG<5pO(Mmm<7vhI+-RO)>CoQ`53>H z>XE9*ahB(OCL>jiW4#SGQk7W2AB;#9R%i#K7|KdAJGvpPB+H{4x=J!Wx*@AH`-e~T zdadcR;phfYLUXNX8kW4=ty_+?A{&w2$;;EHYsCr8v*IsGOrOTBw`N5(Afrn&#xw3j z8_{T(1Ex-pxf<*r3=Iel2Gj{+GM`8j4JZOFd$XPnnrvuTE1ro?TJF{{H%MBZIa4d5 zbE0KOXyX~oSJ}K3U(E+oDvU! z6^$i&NKbEua&ccSdRXeyPt1VGcO%#fxL%UIHCfne9>nvFYeDEndy%XX zQuREZyl(@3FD$ZVSWr6Y0YG6KJ#yjyd0}^;gPPJWpWgno0tl~tOpo>HFQ*AYYgWlV zkU?Zkr-mLD1eTjn=Vw6( zQ?ZShlA7X7;TjUCOgdTmo}h(NyE%N#8dg>g{K=~L3EyoOfBAfEQWZD1=7Ib2*e9Yw zEt#I^wA)H=XL#RL_rb)+@osGHVxZq=d{;A1IU_2ESfMO9-OM#?X*hR0;?{|s1q-%T zPCOk+-@)lqIW?X2n)Wa^3b%wiE+$k|%hyqqoi2H_L`Tm}$;P-X`4@r+d229srITrN zYBnh&oe>=inQeT;rp(hDGDgAqg><&d8#SDOx03Odo!Zo~|8I49YEyGL+i6X3u$DZm zYp|d__)&|2zF(t6gzn|;FMHJkCxfNBvr>(iL!UuO2y<%bE!E5@XJp5rm1;39i-#v# zP8bYGvYITk7CXP%QgRneTR+%}TVp>lxt3@j*=#}#{Y0IHThD#Qt=}ZDt^gS`9d0F! zRzyX{!}(=Ljuhqjo$QmKg{nGZGrl4cE+z~k4u){p2SbJtQUW}ZXfAKBvwbc!yeZqC z@60b<3vtrQse9#@))B++F6>ChBIJ>Yi=wDU3YHb0%89r4g)zqM_1n~MT-9FmrH9~o zUE6|K0La~XwpsJ&A%}edYwdR70fDLZ_*zWm-nAU!#GX)-YQ&;t5G~9?pDk{SC!BvU zKhU03j{=qF0=xTGeyOIu+`K>zX!FdRb=D)Eq?hCp5|&XXf++LOrgPQ}EgL_4A7>WK zD=4kNbnIh@MIU+yp5L{#e08fee@veZG=G~?7BnQF$`hUOZGF55u2lDX(cRTFIiLCR zfH^BUdY!?)IA1MpNpUV3KrWN!`DC_p)cLzWgfk+t$8!z4EOrxv%b(Wk{BUGxosYFS z${8VJ#x6zqM1sIIQIoK*?BbEh)s^*YzF^bH*Y19#WYh+8M%8t(6X}3xR~9RmI7K1} z5oQBqe8(nniIo`c3@>QNtd4FY7`FQ)75;04);DZMQZ_X)y!D3?N#BVtKueY+3Mrn} z$f-_qCXtjZYBQx@+T6-g)gG!+tkfPn#9PS7;1daz)0ckn_3;yv@nzjWc#R8JRzqm* zqSN77#*)ClZ*#||PL2fXb>;XlXE?qYBcFB9jM?oU_e;AFu+Loe^1)}NwV#u_%Ho#x zjg59r8__pGj4f^6D`K?6%#ocZ+m&-+H%o}~@nk$ArjIFZOuJbItVLoto77H+KDqM2 zMua_Rb`B_6x4q+Xs4*Ege?#IFGrv+{ymHmm3C0SCJDxq{bb@8cZKNK`u_`8jqx0sK zhJNIT!^N&E-`2#!sqm{CLF6hK)6}JSxZ6qoRtt@WkG=r5D%ML#i=$tT{BqIs^YvaS zEFdp`d?h4aR^GI#I+J?G3eH%Cj^f7maDA9pHa$vT`+>WC*(9>IXbEbEj@g3jL1Q+E z9U_RZL}KkXtY;Jds$DVZg1^#MjQJ+4s)bvnzew=W@V4<;vLRds5 zC5=_VaZu~@?agK7oz40;>R^05$|rU9bPfT(q_~dEU<2!Yj8zn<`g#1a_>gWQ;Uh^_PvyT9Ml3Gs|&IO zjnzRc5I}fcE9~Z$U;16%^&0b6FYj~>kM0?c4BEx(I|ZGKHH`dItuDhA&`(u!#xNKR ztNF9LC)jt2d+r_0d(F+w4Onjd|E}(8><%&+VCq`3fx1lcD~Kob%MiyPY*^R4d2pfV{z}TnF13TdP*9MJt>ra(Ty~ z#;|51X;~O&f1nLy4hCe)e=`19AzOi=(DG0Vb@Lyae{JS9QR`S4GaHbn$7F_-s@bWq zSjI(at)~Hg$nEjR6qSb<3TXwCrtiT<5{~b}gO1{Xplz#4epVvI}s$ zrhd`qf6Yw&@t0`7=*wSIvoC(}@4a++mzv$$@v;Nko%#mM)sXr)t;K|v);>}%r;R{p zZe!baL_3Dr+B$|scg&MY^1}eW0tR4izI)o12tLJ#zoKa`pn@-XS<@P!5?D1#AL&uT z$z(Pw!p8zl{ew-}5V&_=XfqrfmLvXngV7O+uDa;bh^}t$JW8^^sob3mpnO&WGrj6N=VFtVh8D z{{rZ;f-axX75UENX)f0W@3u2f92d^Tn1{-A2}Y1B>wl91(D~YH|FVIQiCjbNtuOJw zYX(J+a38!zi~ZnGL=gAbZ9WA$eM`GQLj;-P>g|M18-QNJ`LN#Dpg%W{VM)ZhFnA!QS`?ABo`Xx(Lt4auJz}I>o=2-TmR!alaXPyRa~X55rO6w-JASI{$k7 zDsvTfUZDt42nrTzH)<1WVNlQ3ETW$@aV*(WBFNEZ(On|dGOB0)eJTo7KS>Cis7wKn zr56RG#lAE11W+o*oc1B$UZ{Hnt$*~|I!21ed8{4 z+mI5pgrLQbNV&v5kUnXu{z#_dfd527a}`+0OvHW^1@xTnv&^P;pJ{?+iPQ!QXbMG> zWVGR+O)xq}pu=x;^+A`3Q1Wbq$1(C?XCt5>Dpu3*9p!=FscnC*0wY-n(;W)dmZe*} zZtbK=U_Ds89YT7~OS+sJBbe348rD~?Bh6bsYav)~EWU9y_snZF?cPm@NJ0QD+r$){ zwC}V2ODXwiRIWACyaqEKz4wuJPP9$9F@MUzN0 zO=xTixz+p)QG>%=WdFPz9a9@uO~#+pWT9&mmbAkXqgc{+>XDz-5UjuU#p?cYhlryJ zZ3|K_l+1duoT``dZGG0Xz`x9g(E7^9BOPy@|GY=%%&m z+FZun$~&Nm#lvF|Y$Aui-SR?*f{ycUa9NJf#9D@^tbHvw&&uuc@Sa0a92Ec+GMmS} zX8RS~qppP^JopzmBgaU(exugvAuG}QfS&f+Mo~$)CRrqt6L{J=w@bCj75U390C0>n zxl`;MwXgUiQnY#Axx> zG$`A}f1vXL5CgZ0#K zlC4Zu*Y576n=U%%oTM$g&U(-0*SArSoe*-y1@+PnnYOw1KI%4q16w@2^yDJlV&76z z)rkp^c4=6X=~~E|acmfbHW|I`v1jr>zYf6{r~d-5neLNIdeN9X;ybwKRdR^v30;bt z5jd;ckC*3C+d?EfI7OYAmSx>tEaD&t2XxYK-{x|;o&yIz?h_P`%?@es`T zN&U9u-Hpw|jjmd6FZ0{gAOC|-cJI*Zn^qyUgUWv;mH@7}lDoVxuA{AVBjBqTNLS?-~`1>}#^G%+qAW;{%)@g2Fw zgJEiI)YYhLwCjLNhy`yWR(wgeQ8a-AbKm?*MSqAOqv>%A>p}J;XglnE(Jj1qRX#-A zrdKCdD4J$8zFg8Zywd&jZiT#FQm^s7PQH;RoH_p#XF(7-OKMIMEAM^K8hiWKwd4p#HbIM29^8usKmX%P1J8}{-m)A}Gqjp) z8lI@f{@-Jg5@=FbXeY3Ylbm<_y}k%;u@IsV!KO2W4^39}=5W&#Zo%wwEaeh|gfw(G zr>_|p2xAsJo!AE=8K0|%7Cmc5|76t-=WHgaYYo0u@SuN}G5cP*aR(fr^T}D>=79j; z*7m1YPfLIEoLk$5Xo7MbdN-x?_RFhzKYw}AJnwZ}xs=}Te7m3zPElpeqb~fnO3sJ2 zsd}}Uw5#VYw%if82z0m^(W9vX`z^^ezptArPws2fT2nsUXYnFao_Ney23}_MD?)OfcWeJzU+%tIT+De{qnEBJvy%b0h7WiA3r5^$ z?0>aZFS@0U;B39TwGMFpe>CPcBxs~$%}VqeI~PvN5&?1bb{B5pHH06s9%t^yZI@3I zpu$@F6AuLgXj?Q1hWFh%d(8Xyw6=Zk>E3=kdp2f8J;;Ht6El8Gs&T7aLvy-;ne1nO zS^+qoSa5@ErP)rigL>2dR_PKD`%QAbZD`5`^l#SB(uVWogAuNGZ3yAq`=IVTevjuJ zMf}18OQNf%PEh{OWn8y)!z;sc5o|bb7H_y8PuNe1C*KvnA9HM#z`_C&Y8|tJ^ zy%gY-oM@0s>i!Up2%4PMlWxC_j^abWi8uW^=LK(C7AF#|UdU;gkCU z-hBvPb46bXnNZIMY%!s*aOkW*=8LmaIl=Wuld5C$L_WEa-#n;#f%76;pbHnPYCa_eHYMnDhV#2iZ5Z7c9BL!^><7aT(VQ|BH+&a4~3Lnr^? zFuQcX)+Z+Q)uW>{K>z6J$K#`?XD~BwXpjx>4}jm(87KqrO%}X(gUB18L+mjLS-?LK z6A|dOt+8SFYH|goj%T~#ZNm~vhw&NLKYIFcxO{rPgXUEf+DRX2-#QA?Tg>+(bTFx(+AfI6?>73eYcd!sTXDXgJN20dOd6mxi_Qp38o@ z;VW#d^DBNk4jXn^(>-n+c8#*^1O`6sfGd0pr-ne-(8$Z73h>??6AMUyx(X{)Yz)WI zP4Oj$KZ33-8KlpMGOzHgm#d>GqI6*8@Vo8Y_~@U|XkdKwZ+zv@b>01SpV$4pRH!n9 z7qwE*o3NoI9BpRNHQifk#4206KMJ~rc-qn|TA^HQu+IY<4|L~4#0yz^3DI!GYpHag zF~s;7h&~3!!vKsJpnsQ$H=1y9$HzcOGB6GXA|;Oy2!{{G1U0)m^$~^04^(IDpnHon zf|DY(h(3cD3m>)d@uu4R4#{bG>BK`a4Y`*?ZGTJ9-SIdch&?jh_rJk?xYyq}oN$E# zC&G^tCe{o++;)MBO5b)39OGkP^8k=m7#BvP?IAd|<(v<08`_rGO%!uQEV3?K4&`T^ z;=M(Q$76{thGvnrke#WQ-f0B(zLBv|2BDhX>zby7#GjDH4y2fk!mF;;i{Rj>oV+t> zeO}QM%BRoRqZA81i{rz;b}I&X(L81QHO<$z(UpGhVmNuxGNr7VmWztQihp)D(F<~& zvimg{LNw4yS-T#CIt0+D4LvJQWcy^ApU7^L_}SRD=v24R(_0>>Q#8LKgJM-5YiKV6 zcCfvzGGq6sSxnm9D>;E-@N|KPr}n|mS9oEkQ}om;@x&|fv@@P<#skRM2NgdaLbw0^ ze=z06p)X#7m*Qo31zw3)%~?IUv^3Y0DPgDK+%>Kj5yw?Q|L?~EFm{$Fk1&FdPK^pr zjW~E}zAykjx@~-|YdMa;eBSU|2<^+ie9j|~uMk2~aV$<<&AMGxi+Z)vO($WS_U=Ds zV|qUV7lQbA@2)+$UE;O%IzK`D|2%;g10E6AzkmEf##G0yt;>F~{CCu++xLJ!5tAegW9uTZV!m01o(iYex!1VtkNF5au6G&euPQWD%!0%>6Sk{ue>Kk|lC} z6U&#^cmFwl|E&7CZhy{~``qe%J><_a;qUtX8Bvjf7axE3n1>7T;BMcqpG%TIJ*D9P zF9O=0V@m=6Inw}C3rN;6qA0)@nkD^mSUw(_Ea1!hSl)^qvJp z_`w_NKRQ$HuJ-dILSRFNC`Cs4<9m-GO>9E z9TmW!gMwg!$I?4JX5d!JcH==*6+G9I^JT}jq(bmY>w1#7ufJbj6*lP#`X23x+_Gm= zfx+c)?-;mrrw|x*ZY7QNMBRXTng^(tIU5zlL`XnuSuxjriSn?&m1r!13&E+X1BfVFuhorXQ<9bF63Da_~sbCZppnE~Kk+H&DqDZKhY%A+>no2Se zd8gRlEXWM7)_36J@QXDqMbylnb!R#F-chX3tQ$ zH0VZEs`D?0OUH!$ol5tX6ET*Ube(Am>24ptUc<3JYudKp0)kgzG6Xp07*MR4DCd83 z_(}bjVbbhD%++kmr=A(;;s%XoWj{0yFH2Y$U z3Uk>0v}3k?i%5kkx%0CniLxBKvtxH-*U7yKvqgY)l0?7mnQ6e|q($ySM;Z|jy~hT* zvM!yy6SLO{kWtpBE~uKOsWCM{nf3N5oI;8xXA!>4ID@wi+>x)dvMzNR^m57JuqSQW zC7Y(j$daJp0GuH}`X|P#keAdjC4Fxgcq|TiG@y=m4O+;@qu@WZ7MT@dB8pKg1av+2 zpj^24$&OA2&3;Cv;?K^=p}HIl8eqJ%@cUM56WG!3egQx*D~#yQcWPeZ3COa}6oa0! zO~(!NbGOA&iQdj?5f+H;;8x?*5NOh@j=n!H363q7*~-2IlVqU<$!@?j1YJ8e8QS4L z4&klT0JQJN-Y9?Oj@=*fUBjlssxXQ>-@GJ}IBb8*Z!?kCON#bDVv_d+=Cm*KJqUFx zl^*2mN}4(W$xYV7AnoJQqZ$NQxZWE0`4*cS(0FN)O^O%7hY_0feN5F-Zbnp0`H4YtAoXW1$Y~G_O8x1s>TP zIgr_P#%LoO8+wSX%?-dQEq-a|y;vQ9z8@SMKcm%%z7yw2eauntC1JMZ z>w1TIwQFXPFya}-6M%YkHC;pn2tC^&kdsL}+Yuq;LIP&)3};Va;P~ND1Un#qY-m{l z`LK3q+ZK^8S6BjPo538e*etJWX*Nyv`F^nSW+H;+_;w|)14q+?sQAC)w2yCXL(`M$RwwJOy=%JmM) zN!+$aj9Ol=qy$UN*EQW=1jl9#o^9mLyS|(};rE7Ecd#0k)OB%ZtYttr$HWH!?};(E z01x0^YTc}`eAMb{*U|}!MG`CWePVLo)-+@3lM#$TWXuYOlA|e^j@VA6Twn-)e>e42 z$kymcfIREF$#ZRFI$1?TI~q!J62)Fadce=fIO!u9(Tq{XI!<&so-02$+^?3=roTm+ z@opml9HbF9LP_iIDzb!92P4aIEyG#s=Fn-vTCnYv1f zg7d6~!qCa1gK?Ff5yhzHj5gN-`Lb80`Kk&(MF~1Zug+L%^Jb0Ea8s>AklK(SwW&d( z<4kjqgFGQm$P@C!esVQQ2`Tx1%$1D#NA0ja-dP>M)6;wReFJQIRV+VaDZemqOaOny zWM+ae0Z|p69Rw@upCLCvFf>N4nXxjtZ2np7me8=#j}C7EKG~sn9s8p45MUa~W~%)M!y;e9OOZ^Z*Ufb_w^{9cQZ=g^XYSc44Y8Umm)b{B7<`3Tqa{;v z-myhq9kN-diOQX>J-+H&y*GY!csJI&2bckT)oglLqyY1dwzC2vEB%%3GEEW-Mxabt zx@SU4b$5dl=*Cx))1-#B>ValOss+)OuS7cw;$BP0(Ns@pR)6aAXbPlBSvwGp*W$PY ztoAc@^&N-ySOxS7qMhEe0c9#{-!-+Ks@ixAdSd^LROx%lRQvkqeS9(-kYD7U%%tJa zeMj4vZfu~E4afPS;J_Y8m)<)&E1FpM_zJ^3wx6D6WLz%x_5ZRqO$*(bM8mZio2@7O z*1sYNQ4u8Xwo3cyT$GvL%-bF7F8?8_xkv~i!j2gM%z_H zG#y?ofLnO(?y40O6R7jT=gl0^^3}!A!3akNM!$2dQA8_A4~DFo8xUakE?E^JoRMlU zUpXL|xc8U#d_KG6AUQ}5Mh|*&0zQidY}y~8uOL5Oxe2M2H1CaCc-8zX%(L#2c17~- zQd=1@ZNE#-ez7;(2^98hI{{&c1b`%0<*VMRVw7Gv+{<+jSJp>UdeS@^FxmO^b~H!% zrg_ce6Iy;~@RQKMt`k?hxgr0IEdpJzIXgB5bLG4L7jOKe7`ts*e>7+BYN-tBn+&(_ zp*gGr@R4?$0Rg((T9HvGtVSa`^45n$$Oz1ADvFZO>VT5Kk_%)j9xWkp3mFk}5u4_} zsHxMC$f?VD6-at?0V^r%00~ekn(~MvD|*odZ!OHb@}sM6Jtd(KU3iq`7K~zK?+D|K zBCi?cB&KlWZN5~<6B?yjYG<}9%H|_+5vbAyZstbJlfIF8-o=j2JQ~Rw-fWszW09B7 zo(z2HnG2#YjG`^Ng3sj26gm@`?4wZ#t~~WFhj&$Uh7v96cm)&zzS4CothPHWntDH- z#6hc~d~_7C&4(b4Ttu@;j~L#4+`Eqh03pP{PSQLGfMJcx*x3Mp(JASCB9Wt@40ErI z9zbC@QU&CH-ICxQSqk%0EX{p1CzX659-H#<9k$;jL)IO~sp7c+0QFk<3iMr zUI-Zg0C@Su(1b_lC004jh{6FT#0>uM;5W-i{pZ%o46{_T) zy)kx@`yhQ$`r|v(V@l#zk$xjR!dPJ?d&Qd1>_BP*+4za7HGoEzOzS-g48wnjTGjcB zC4zB^BB7l-!@r`RXgnHphyx73cbE*Fw=@A7AR>cEoclqQeJ{cCO-VA2QqcMl`L%U3 zc!MuRF#s*ASj$+AnVy)Soe=^JMn<8-2^v#|twd8&CO!J}$X1mvouk~P>y$G`qGuSV zMjB1p82H>uc(@}S0E(-UU#O+9i_l?HpIjS`(D@b@d<{AYLH1^eifuBa=y?$$?rkF!y)kB`6D~|xG2}3L8XB#BmcB3yl7S- zC%dE67*T7+RPmW~bJj$7a?UOxd)V{^MY-t2qf=7dA30lGtT{>kMJR$0%WBxN1aekk zaZEVX5W2$Oxr7@%I37&3<}ybiQs}5P(JE4;QE;%<#myFBi80o{RC1S=GaQK^ZAl`f zY|%V-vsVnEh6#YQ%S(OD2p9Ozc&&PcrEqL1K$<6U`KSkmD2DHB@54CDjy3YLZ7~n+ z%%AK8W=mj_ti9DuAct0SLR_kV+4N4Mn~N-zSaaIfr_=Ckj^wcPE<_usO z-}x+R6i!GVWlef63Gz8d9)Hg-aXJ;fHU)c)aL(s24t$G%pI-wernJG-CR%KGirr@R#KR5ANVd|F|-xgygHS zmbO@4;(2HfCi+8DgmNBi9x1qFa#V73p$!yj>4X=?}SDosNTyx z_M)u8fN`Xb%?0R9lYKC-Jjqcf|BkEh8v|b5NlXQaGM>cVc}T@50_I5n!aJGycaQDmkYe_9!r%^u0T`WYH5pBX=saUu;iM2aR6?(CU3^yUYpVg2#O=~ql zKcQB*4vYw_yGPz9U*KQWt*I(%TOEkDm)C-<)AbZ8&+BF^}9dTJCtD zr-+Cc5TD7t^eF!DTVlD%kDh4<+Jt(5E&(tSRUnDhLz|$aozPK6$~Bj_k{hyi$4~ic zHp}ijH>049qkE+UUVBe?At0q4R>O7$W5#mn#(e-#56>@^fu&aFp&IX=Gvi_bH1r4KX= zV=U-)LqS&*9{7MD;LTcPiY@9b7`1SKUr^{B^nRMO0BB(5p%co6=Ggbmt-3#|qvZFa4X%R#cierDwbBUgfmA0a! zlyI-ZmR*GNaK{)P-wL%^0iiQMeKMnQX`C{L;CPk<0Cat!F9Tsw75o*vwdg&l$3wpKUJb4vT~LKf^mV6@%S#G@cX9;~ zN&x_F7MN#3KuG;FVITl!%G|6zat$ab3d_15NShpzYV>f-V?&CP9;A0LxJ`A$63#&hfy+$P1&cBaTir ziMo_9P!G$f45C{@Ry6!b2P^Zr95Pv_K>#5v$}+5p7>GD(FZQdEqmgX?pZ+*!Aqb!F zGqRT`sQ?R7lstr;sJmzHT0%Z#uq48Zv_!<{0{V%jG?YdMOBm61iIA$BPp9m}Gd+j} zT2deb4yfMxT`cXaCT=K;ktF0J#6o1avxO+wI!%DSQrEiHufFU(& zR_G%4Vn7C3hG;q8mw%E@G{;rC=8bnD9FjP*gxQ_$6f`O-ShpD`=v8~rDd$q+!TkKZ z@;$-dZsxa-f>Ik$Kt#eQQ9)TG)X|523_wZz7=mN@Vg$Y?XMkG_6k?E2gAFm1rJ0DM z+_p1ap+!_=EkU9gNKks}r^}GZSkAKLuput$@#M4APKAmTD^ZF@GUX~%szNih8nsk* zM7;*8I!<*bSm`7+d0B3Sl~!rej8@gwSc`UbTC{3IC%g4F*l3f@w&;)s#po}AZYlJd ziXhPvOD(fptlUbmLLKxpfLA-MW@8g1#h|ul*2<)==Xkf9hF;nr+eVw@5LYu#YO&Qe ze%8*W7SZo81})ibkG=MJ&3+6!Dc3;;OJS8Lbm@*dhEZqbD{#U|uQO2&#$9%X#`4U! zz(R{?s+d#Ko;7Li!Zp@ndqhk9+cD`wOu;>m-`)1uYoGm?^&InFFy4^Ej*!)B$7EyC zw{o0dIIfdUVefQ5aaLGgIp=NPoO9j<7hU2^e?swZS6$;{|H^#+&;#eU0c;#aL(zX6 zSUK#FBP?0#Fe;d%b$tPFcdpRwo>olsm?VTu6#jB@NB&5Na96ktq;%*U1zK$8vyBvh zi!N<5Tp&Fk3R8rl1@Lw9q)M4Wkb;mK6gIRB3AQYx(83BQcQQyUvZ$hi6;mu9h%c`A z5=tzIY>T!oIXKHxFO`SvmWI4&pM8PlW zmxBulD2Z!kK~K0v$cmax1QKT(i9ZIoX*W50VocdFa+IjiqQ^jH%viDG#O3k4xDIEh z8{>16pJcs!CrFqG5kb(8RdVLcoA%lp@eARWT^`_rpIBrB6)4_*1c>y)ZVKMPD3a!v z^o8+TAu8@u^M25@Jkqrz>G7C>A!|EcNu}J!BDJ#0tEjT7Oi1E`b{Zi_D+wBk=R9Z2 z4wu;K5wx_XcWM^QYMXBkLW!=mw%Y4p#vcCbB+zXE+gf2o*kYp1vIHr!qD*BpHO&^H z$Ec>-n6aw+;Q^s3-&j+eA=1){N4~tKPBq<3dF5A7VMP^JQfX!2mxVRfWQ(xdTDGh1 zdg=v6bPP5`jCf~eHy)>nxJ@?IbTiF1*L({tw$ySft+p1g^$2dn)KVy+30?SvUj)z* zBJ67s0i+WkwoDHl!6RgZei~un5n>nt%Z$rRNF=pqDXD1)Bnq9Lk%_^#SUKvHOU%nJ zC@jLG7ln%z(OUK~&GKSS=wi8AYbCz!?>~P2`pt^5%gnaRsvovoNToN^br!45UfD=mfHOKY*AdKQ9&GMqG>Za}bVVq`z_2blaKkxUma)SZbaNxp& zfP?};gWeO?7QtH_B8lFTp-_1?4_5}0#pZB%e1T9TmPloCg;J%~Xmxsnv81%D++1;F znatHSwRIM&&0gQo*wozOXl-ln=mbCrMox)B>+82jmy)TX+ieIKuR82Qb_KV}V z@E0ct=`T)_;$NJioh*3@GE@0j zX3wE!T0qV|H`C$GB_#*o@H&UOKyIiP@+Day?(>kxJmp!(gwC9F^8&;!ha$WWt=ER` z)`R-{MBnT!(WV!^0#w#;4|1_18!`O8NB8o)`2S&aT7JRl{w=D{#r|zGt=}JyV_5QTNp42*Q2EXTe#*NjOjrWoTbu(9Uwvt8gWG&bg zC5q+!VoZkxTboZcJrgaSUV%;6Hr6Px3C_M3d$9+*xE8m^rK7Xi#b~$IRJq?8pBswA zC3djHuhv*4#@zKgywgbRU@w;V3B!K4Yc_TkYxp0Ia2x$9V;$V7j0bcaPp>b&u42nc zv!~;OX2YnL;?o z^qWKc$CmMM+q_(Fw4iAAWud8;s__<|Y>K*c{-Pd+&bf?j7+~)5fNF`aBy5%-=IOQ- zb#n@TuSoNO6sL9 z4Skt0eN1Ry>Q%b~->wPkZOVA-N1xSdyPTx8i0*}i#VsbI^0ay5J+>v^72Ab7Tb3(M z7qK8mn1ZI_th}oM*03D04k5otIP01uw}uC{vOUAM-utkwq;QY6L8ppUvJGr(Nyz5K z?b4_-Z3mYIFhW!5nP@S~0w#F2_@$b02f1!FPk$zuFe=*&m0d(#emI@@~&#r>QX8!t~7jm28M%$vw+#CFO3 zIQJgb(y=SDY4(mY zjB~`AZ}qepl85U?rC{SAnhm}LDZ&2#;4)6$=5_lo5>95khriEaSx#PiYy-CgGTOk^ znm#G)1V95Agwsg0Ik$(#mkWg%u_Ax~0tY10UBGReMK@L5ZRF;NUFUC`zQii~H2>K2 zx?EU)oQLVIG5q+2?=|L4N)h1VCoFl9VFaSW11hudXOaeU;iRh!JqkF1{W?;HF zJgXC`bO4-ZW23=-3{Qh=q_)N5CACfJ={XkK}6i5$WcYAJXNnmnmzaO=lCA)1(T65RjP6 zfB*mT^T(;~KOp!5zCd5_*{LPy)P>^_vtP#z6wBu31wW!tnVNAHz`+}^}dT^ zeC(1-!uL_$?p^oQ+w;OnGWq*4?KKlR4KAa;*L%hbk)ch9C;$thLbxy~LW{CuytpVa zQz~upoi_HC8#|k6by8cl?Da0Y3Sg0aMp3Ob&5?M&_-t%yWNEEwnvEq#ost$QG8LY2 zZdso{uK<$HY0HwsDS{TA&P@57yVlJc9C*!p)JWR0X^wyb1qw`7q8nDSWKC77R4HA$ zbZHa&Ny%W)TGJf(q;jZJY)O4;OVs?s;UvEQ-khDCF3vnpd~QQteHBPNU3Y66JBOxz z(lpeu+-zmMXY;X#IAu_}TU>hfsiJiBo4;CL!tMtvHup(BeRkZno%`|ytkewp6c+vb zdCmd#Fxz|SUE5-J+60=N4mG6mO6GV6?YXG5DUj2D}e zN*k}!u6F?tVL}-fQfcGG=3amaW&9~NOH8!_5Me?Y&-lK5u+ZU|BI*M24yDq@i@g|M zva&!(opbhg;{PICA%RlQA;AavuTOMqf0Z5P!cte{exR6R4FZWmfL$;1ht1bz@?#0E< zPP2vtCX{g@mG)xuA>t9aZSwtS13LLCR%%{%f5>y*x^=Jjb?6bBi_iW2vkM@?lyM=I zHePJ{1rT9E85dG%W%3S%zrO#aZ)=^vwYyGBi)4C>{@QtV;cjL>Y?aYn1FjV;7Am6WVo4kF; Z^oFao>rMntlLHQea6Z2d5kX047ywQhkj4N2 literal 0 HcmV?d00001 diff --git a/godot/thirdparty/libdatachannel/LICENSE b/godot/thirdparty/libdatachannel/LICENSE deleted file mode 100644 index 14e2f777..00000000 --- a/godot/thirdparty/libdatachannel/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/LICENSE b/godot/thirdparty/libdatachannel/deps/libjuice/LICENSE deleted file mode 100644 index 14e2f777..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/include/juice/juice.h b/godot/thirdparty/libdatachannel/deps/libjuice/include/juice/juice.h deleted file mode 100644 index 06bcc139..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/include/juice/juice.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Copyright (c) 2020-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_H -#define JUICE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#ifdef JUICE_HAS_EXPORT_HEADER -#include "juice_export.h" -#else // no export header -#ifdef JUICE_STATIC -#define JUICE_EXPORT -#else // dynamic library -#ifdef _WIN32 -#if defined(JUICE_EXPORTS) || defined(juice_EXPORTS) -#define JUICE_EXPORT __declspec(dllexport) // building the library -#else -#define JUICE_EXPORT __declspec(dllimport) // using the library -#endif -#else // not WIN32 -#define JUICE_EXPORT -#endif -#endif -#endif - -#define JUICE_ERR_SUCCESS 0 -#define JUICE_ERR_INVALID -1 // invalid argument -#define JUICE_ERR_FAILED -2 // runtime error -#define JUICE_ERR_NOT_AVAIL -3 // element not available - -// ICE Agent - -#define JUICE_MAX_ADDRESS_STRING_LEN 64 -#define JUICE_MAX_CANDIDATE_SDP_STRING_LEN 256 -#define JUICE_MAX_SDP_STRING_LEN 4096 - -typedef struct juice_agent juice_agent_t; - -typedef enum juice_state { - JUICE_STATE_DISCONNECTED = 0, - JUICE_STATE_GATHERING, - JUICE_STATE_CONNECTING, - JUICE_STATE_CONNECTED, - JUICE_STATE_COMPLETED, - JUICE_STATE_FAILED -} juice_state_t; - -typedef void (*juice_cb_state_changed_t)(juice_agent_t *agent, juice_state_t state, void *user_ptr); -typedef void (*juice_cb_candidate_t)(juice_agent_t *agent, const char *sdp, void *user_ptr); -typedef void (*juice_cb_gathering_done_t)(juice_agent_t *agent, void *user_ptr); -typedef void (*juice_cb_recv_t)(juice_agent_t *agent, const char *data, size_t size, - void *user_ptr); - -typedef struct juice_turn_server { - const char *host; - const char *username; - const char *password; - uint16_t port; -} juice_turn_server_t; - -typedef enum juice_concurrency_mode { - JUICE_CONCURRENCY_MODE_POLL = 0, // Connections share a single thread - JUICE_CONCURRENCY_MODE_MUX, // Connections are multiplexed on a single UDP socket - JUICE_CONCURRENCY_MODE_THREAD, // Each connection runs in its own thread -} juice_concurrency_mode_t; - -typedef struct juice_config { - juice_concurrency_mode_t concurrency_mode; - - const char *stun_server_host; - uint16_t stun_server_port; - - juice_turn_server_t *turn_servers; - int turn_servers_count; - - const char *bind_address; - - uint16_t local_port_range_begin; - uint16_t local_port_range_end; - - juice_cb_state_changed_t cb_state_changed; - juice_cb_candidate_t cb_candidate; - juice_cb_gathering_done_t cb_gathering_done; - juice_cb_recv_t cb_recv; - - void *user_ptr; - -} juice_config_t; - -JUICE_EXPORT juice_agent_t *juice_create(const juice_config_t *config); -JUICE_EXPORT void juice_destroy(juice_agent_t *agent); - -JUICE_EXPORT int juice_gather_candidates(juice_agent_t *agent); -JUICE_EXPORT int juice_get_local_description(juice_agent_t *agent, char *buffer, size_t size); -JUICE_EXPORT int juice_set_remote_description(juice_agent_t *agent, const char *sdp); -JUICE_EXPORT int juice_add_remote_candidate(juice_agent_t *agent, const char *sdp); -JUICE_EXPORT int juice_set_remote_gathering_done(juice_agent_t *agent); -JUICE_EXPORT int juice_send(juice_agent_t *agent, const char *data, size_t size); -JUICE_EXPORT int juice_send_diffserv(juice_agent_t *agent, const char *data, size_t size, int ds); -JUICE_EXPORT juice_state_t juice_get_state(juice_agent_t *agent); -JUICE_EXPORT int juice_get_selected_candidates(juice_agent_t *agent, char *local, size_t local_size, - char *remote, size_t remote_size); -JUICE_EXPORT int juice_get_selected_addresses(juice_agent_t *agent, char *local, size_t local_size, - char *remote, size_t remote_size); -JUICE_EXPORT const char *juice_state_to_string(juice_state_t state); - -// ICE server - -typedef struct juice_server juice_server_t; - -typedef struct juice_server_credentials { - const char *username; - const char *password; - int allocations_quota; -} juice_server_credentials_t; - -typedef struct juice_server_config { - juice_server_credentials_t *credentials; - int credentials_count; - - int max_allocations; - int max_peers; - - const char *bind_address; - const char *external_address; - uint16_t port; - - uint16_t relay_port_range_begin; - uint16_t relay_port_range_end; - - const char *realm; - -} juice_server_config_t; - -JUICE_EXPORT juice_server_t *juice_server_create(const juice_server_config_t *config); -JUICE_EXPORT void juice_server_destroy(juice_server_t *server); - -JUICE_EXPORT uint16_t juice_server_get_port(juice_server_t *server); -JUICE_EXPORT int juice_server_add_credentials(juice_server_t *server, - const juice_server_credentials_t *credentials, - unsigned long lifetime_ms); - -// Logging - -typedef enum juice_log_level { - JUICE_LOG_LEVEL_VERBOSE = 0, - JUICE_LOG_LEVEL_DEBUG, - JUICE_LOG_LEVEL_INFO, - JUICE_LOG_LEVEL_WARN, - JUICE_LOG_LEVEL_ERROR, - JUICE_LOG_LEVEL_FATAL, - JUICE_LOG_LEVEL_NONE -} juice_log_level_t; - -typedef void (*juice_log_cb_t)(juice_log_level_t level, const char *message); - -JUICE_EXPORT void juice_set_log_level(juice_log_level_t level); -JUICE_EXPORT void juice_set_log_handler(juice_log_cb_t cb); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/addr.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/addr.c deleted file mode 100644 index a8b2fab9..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/addr.c +++ /dev/null @@ -1,310 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "addr.h" -#include "log.h" - -#include -#include - -socklen_t addr_get_len(const struct sockaddr *sa) { - switch (sa->sa_family) { - case AF_INET: - return sizeof(struct sockaddr_in); - case AF_INET6: - return sizeof(struct sockaddr_in6); - default: - JLOG_WARN("Unknown address family %hu", sa->sa_family); - return 0; - } -} - -uint16_t addr_get_port(const struct sockaddr *sa) { - switch (sa->sa_family) { - case AF_INET: - return ntohs(((struct sockaddr_in *)sa)->sin_port); - case AF_INET6: - return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); - default: - JLOG_WARN("Unknown address family %hu", sa->sa_family); - return 0; - } -} - -int addr_set_port(struct sockaddr *sa, uint16_t port) { - switch (sa->sa_family) { - case AF_INET: - ((struct sockaddr_in *)sa)->sin_port = htons(port); - return 0; - case AF_INET6: - ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); - return 0; - default: - JLOG_WARN("Unknown address family %hu", sa->sa_family); - return -1; - } -} - -bool addr_is_any(const struct sockaddr *sa) { - switch (sa->sa_family) { - case AF_INET: { - const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; - const uint8_t *b = (const uint8_t *)&sin->sin_addr; - for (int i = 0; i < 4; ++i) - if (b[i] != 0) - return false; - - return true; - } - case AF_INET6: { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - const uint8_t *b = (const uint8_t *)&sin6->sin6_addr + 12; - for (int i = 0; i < 4; ++i) - if (b[i] != 0) - return false; - } else { - const uint8_t *b = (const uint8_t *)&sin6->sin6_addr; - for (int i = 0; i < 16; ++i) - if (b[i] != 0) - return false; - } - return true; - } - default: - return false; - } -} - -bool addr_is_local(const struct sockaddr *sa) { - switch (sa->sa_family) { - case AF_INET: { - const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; - const uint8_t *b = (const uint8_t *)&sin->sin_addr; - if (b[0] == 127) // loopback - return true; - if (b[0] == 169 && b[1] == 254) // link-local - return true; - return false; - } - case AF_INET6: { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) { - return true; - } - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - return true; - } - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - const uint8_t *b = (const uint8_t *)&sin6->sin6_addr + 12; - if (b[0] == 127) // loopback - return true; - if (b[0] == 169 && b[1] == 254) // link-local - return true; - return false; - } - return false; - } - default: - return false; - } -} - -bool addr_unmap_inet6_v4mapped(struct sockaddr *sa, socklen_t *len) { - if (sa->sa_family != AF_INET6) - return false; - - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; - if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) - return false; - - struct sockaddr_in6 copy = *sin6; - sin6 = © - - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_port = sin6->sin6_port; - memcpy(&sin->sin_addr, ((const uint8_t *)&sin6->sin6_addr) + 12, 4); - *len = sizeof(*sin); - return true; -} - -bool addr_map_inet6_v4mapped(struct sockaddr_storage *ss, socklen_t *len) { - if (ss->ss_family != AF_INET) - return false; - - const struct sockaddr_in *sin = (const struct sockaddr_in *)ss; - struct sockaddr_in copy = *sin; - sin = © - - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; - memset(sin6, 0, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = sin->sin_port; - uint8_t *b = (uint8_t *)&sin6->sin6_addr; - memset(b, 0, 10); - memset(b + 10, 0xFF, 2); - memcpy(b + 12, (const uint8_t *)&sin->sin_addr, 4); - *len = sizeof(*sin6); - return true; -} - -bool addr_is_equal(const struct sockaddr *a, const struct sockaddr *b, bool compare_ports) { - if (a->sa_family != b->sa_family) - return false; - - switch (a->sa_family) { - case AF_INET: { - const struct sockaddr_in *ain = (const struct sockaddr_in *)a; - const struct sockaddr_in *bin = (const struct sockaddr_in *)b; - if (memcmp(&ain->sin_addr, &bin->sin_addr, 4) != 0) - return false; - if (compare_ports && ain->sin_port != bin->sin_port) - return false; - break; - } - case AF_INET6: { - const struct sockaddr_in6 *ain6 = (const struct sockaddr_in6 *)a; - const struct sockaddr_in6 *bin6 = (const struct sockaddr_in6 *)b; - if (memcmp(&ain6->sin6_addr, &bin6->sin6_addr, 16) != 0) - return false; - if (compare_ports && ain6->sin6_port != bin6->sin6_port) - return false; - break; - } - default: - return false; - } - - return true; -} - -int addr_to_string(const struct sockaddr *sa, char *buffer, size_t size) { - socklen_t salen = addr_get_len(sa); - if (salen == 0) - goto error; - - char host[ADDR_MAX_NUMERICHOST_LEN]; - char service[ADDR_MAX_NUMERICSERV_LEN]; - if (getnameinfo(sa, salen, host, ADDR_MAX_NUMERICHOST_LEN, service, ADDR_MAX_NUMERICSERV_LEN, - NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM)) { - JLOG_ERROR("getnameinfo failed, errno=%d", sockerrno); - goto error; - } - - int len = snprintf(buffer, size, "%s:%s", host, service); - if (len < 0 || (size_t)len >= size) - goto error; - - return len; - -error: - // Make sure we still write a valid null-terminated string - snprintf(buffer, size, "?"); - return -1; -} - -// djb2 hash function -#define DJB2_INIT 5381 -static void djb2(unsigned long *hash, int i) { - *hash = ((*hash << 5) + *hash) + i; // hash * 33 + i -} - -unsigned long addr_hash(const struct sockaddr *sa, bool with_port) { - unsigned long hash = DJB2_INIT; - - djb2(&hash, sa->sa_family); - switch (sa->sa_family) { - case AF_INET: { - const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; - const uint8_t *b = (const uint8_t *)&sin->sin_addr; - for (int i = 0; i < 4; ++i) - djb2(&hash, b[i]); - if (with_port) { - djb2(&hash, sin->sin_port >> 8); - djb2(&hash, sin->sin_port & 0xFF); - } - break; - } - case AF_INET6: { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; - const uint8_t *b = (const uint8_t *)&sin6->sin6_addr; - for (int i = 0; i < 16; ++i) - djb2(&hash, b[i]); - if (with_port) { - djb2(&hash, sin6->sin6_port >> 8); - djb2(&hash, sin6->sin6_port & 0xFF); - } - break; - } - default: - break; - } - - return hash; -} - -int addr_resolve(const char *hostname, const char *service, addr_record_t *records, size_t count) { - addr_record_t *end = records + count; - - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_ADDRCONFIG; - struct addrinfo *ai_list = NULL; - if (getaddrinfo(hostname, service, &hints, &ai_list)) { - JLOG_WARN("Address resolution failed for %s:%s", hostname, service); - return -1; - } - - int ret = 0; - for (struct addrinfo *ai = ai_list; ai; ai = ai->ai_next) { - if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { - ++ret; - if (records != end) { - memcpy(&records->addr, ai->ai_addr, ai->ai_addrlen); - records->len = (socklen_t)ai->ai_addrlen; - ++records; - } - } - } - - freeaddrinfo(ai_list); - return ret; -} - -bool addr_is_numeric_hostname(const char *hostname) { - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; - struct addrinfo *ai_list = NULL; - if (getaddrinfo(hostname, "9", &hints, &ai_list)) - return false; - - freeaddrinfo(ai_list); - return true; -} - -bool addr_record_is_equal(const addr_record_t *a, const addr_record_t *b, bool compare_ports) { - return addr_is_equal((const struct sockaddr *)&a->addr, (const struct sockaddr *)&b->addr, - compare_ports); -} - -int addr_record_to_string(const addr_record_t *record, char *buffer, size_t size) { - return addr_to_string((const struct sockaddr *)&record->addr, buffer, size); -} - -unsigned long addr_record_hash(const addr_record_t *record, bool with_port) { - return addr_hash((const struct sockaddr *)&record->addr, with_port); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/addr.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/addr.h deleted file mode 100644 index d4bdb746..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/addr.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_ADDR_H -#define JUICE_ADDR_H - -#include "socket.h" - -#include -#include - -// IPv6 max representation length is 45 plus 4 for potential zone index -#define ADDR_MAX_NUMERICHOST_LEN 56 // 45 + 4 + 1 rounded up -#define ADDR_MAX_NUMERICSERV_LEN 8 // 5 + 1 rounded up -#define ADDR_MAX_STRING_LEN 64 - -socklen_t addr_get_len(const struct sockaddr *sa); -uint16_t addr_get_port(const struct sockaddr *sa); -int addr_set_port(struct sockaddr *sa, uint16_t port); -bool addr_is_any(const struct sockaddr *sa); -bool addr_is_local(const struct sockaddr *sa); -bool addr_unmap_inet6_v4mapped(struct sockaddr *sa, socklen_t *len); -bool addr_map_inet6_v4mapped(struct sockaddr_storage *ss, socklen_t *len); -bool addr_is_equal(const struct sockaddr *a, const struct sockaddr *b, bool compare_ports); -int addr_to_string(const struct sockaddr *sa, char *buffer, size_t size); -unsigned long addr_hash(const struct sockaddr *sa, bool with_port); - -typedef struct addr_record { - struct sockaddr_storage addr; - socklen_t len; -} addr_record_t; - -int addr_resolve(const char *hostname, const char *service, addr_record_t *records, size_t count); -bool addr_is_numeric_hostname(const char *hostname); - -bool addr_record_is_equal(const addr_record_t *a, const addr_record_t *b, bool compare_ports); -int addr_record_to_string(const addr_record_t *record, char *buffer, size_t size); -unsigned long addr_record_hash(const addr_record_t *record, bool with_port); - -#endif // JUICE_ADDR_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/agent.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/agent.c deleted file mode 100644 index 3ef305ff..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/agent.c +++ /dev/null @@ -1,2553 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "agent.h" -#include "ice.h" -#include "juice.h" -#include "log.h" -#include "random.h" -#include "stun.h" -#include "turn.h" -#include "udp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -// RFC 8656: The Permission Lifetime MUST be 300 seconds (= 5 minutes) -#define PERMISSION_LIFETIME 300000 // ms - -// RFC 8656: Channel bindings last for 10 minutes unless refreshed -#define BIND_LIFETIME 600000 // ms - -#define BUFFER_SIZE 4096 -#define DEFAULT_MAX_RECORDS_COUNT 8 - -static char *alloc_string_copy(const char *orig, bool *alloc_failed) { - if (!orig) - return NULL; - - char *copy = malloc(strlen(orig) + 1); - if (!copy) { - if (alloc_failed) - *alloc_failed = true; - - return NULL; - } - strcpy(copy, orig); - return copy; -} - -juice_agent_t *agent_create(const juice_config_t *config) { - JLOG_VERBOSE("Creating agent"); - -#ifdef _WIN32 - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { - JLOG_FATAL("WSAStartup failed"); - return NULL; - } -#endif - - juice_agent_t *agent = calloc(1, sizeof(juice_agent_t)); - if (!agent) { - JLOG_FATAL("Memory allocation for agent failed"); - return NULL; - } - - bool alloc_failed = false; - agent->config.concurrency_mode = config->concurrency_mode; - agent->config.stun_server_host = alloc_string_copy(config->stun_server_host, &alloc_failed); - agent->config.stun_server_port = config->stun_server_port; - agent->config.bind_address = alloc_string_copy(config->bind_address, &alloc_failed); - agent->config.local_port_range_begin = config->local_port_range_begin; - agent->config.local_port_range_end = config->local_port_range_end; - agent->config.cb_state_changed = config->cb_state_changed; - agent->config.cb_candidate = config->cb_candidate; - agent->config.cb_gathering_done = config->cb_gathering_done; - agent->config.cb_recv = config->cb_recv; - agent->config.user_ptr = config->user_ptr; - if (alloc_failed) { - JLOG_FATAL("Memory allocation for configuration copy failed"); - goto error; - } - - if (config->turn_servers_count <= 0) { - agent->config.turn_servers = NULL; - agent->config.turn_servers_count = 0; - } else { - agent->config.turn_servers = - calloc(config->turn_servers_count, sizeof(juice_turn_server_t)); - if (!agent->config.turn_servers) { - JLOG_FATAL("Memory allocation for TURN servers copy failed"); - goto error; - } - agent->config.turn_servers_count = config->turn_servers_count; - for (int i = 0; i < config->turn_servers_count; ++i) { - agent->config.turn_servers[i].host = - alloc_string_copy(config->turn_servers[i].host, &alloc_failed); - agent->config.turn_servers[i].username = - alloc_string_copy(config->turn_servers[i].username, &alloc_failed); - agent->config.turn_servers[i].password = - alloc_string_copy(config->turn_servers[i].password, &alloc_failed); - agent->config.turn_servers[i].port = config->turn_servers[i].port; - if (alloc_failed) { - JLOG_FATAL("Memory allocation for TURN server configuration copy failed"); - goto error; - } - } - } - - agent->state = JUICE_STATE_DISCONNECTED; - agent->mode = AGENT_MODE_UNKNOWN; - agent->selected_entry = ATOMIC_VAR_INIT(NULL); - - agent->conn_index = -1; - agent->conn_impl = NULL; - - ice_create_local_description(&agent->local); - - // RFC 8445: 16.1. Attributes - // The content of the [ICE-CONTROLLED/ICE-CONTROLLING] attribute is a 64-bit - // unsigned integer in network byte order, which contains a random number. - // The number is used for solving role conflicts, when it is referred to as - // the "tiebreaker value". An ICE agent MUST use the same number for - // all Binding requests, for all streams, within an ICE session, unless - // it has received a 487 response, in which case it MUST change the - // number. - juice_random(&agent->ice_tiebreaker, sizeof(agent->ice_tiebreaker)); - - return agent; - -error: - agent_destroy(agent); - return NULL; -} - -void agent_destroy(juice_agent_t *agent) { - JLOG_DEBUG("Destroying agent"); - - if (agent->resolver_thread_started) { - JLOG_VERBOSE("Waiting for resolver thread"); - thread_join(agent->resolver_thread, NULL); - } - - if (agent->conn_impl) { - conn_destroy(agent); - } - - // Free credentials in entries - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->turn) { - turn_destroy_map(&entry->turn->map); - free(entry->turn); - } - } - - // Free strings in config - free((void *)agent->config.stun_server_host); - for (int i = 0; i < agent->config.turn_servers_count; ++i) { - juice_turn_server_t *turn_server = agent->config.turn_servers + i; - free((void *)turn_server->host); - free((void *)turn_server->username); - free((void *)turn_server->password); - } - free(agent->config.turn_servers); - free((void *)agent->config.bind_address); - free(agent); - -#ifdef _WIN32 - WSACleanup(); -#endif - - JLOG_VERBOSE("Destroyed agent"); -} - -static bool has_nonnumeric_server_hostnames(const juice_config_t *config) { - if (config->stun_server_host && !addr_is_numeric_hostname(config->stun_server_host)) - return true; - - for (int i = 0; i < config->turn_servers_count; ++i) { - juice_turn_server_t *turn_server = config->turn_servers + i; - if (turn_server->host && !addr_is_numeric_hostname(turn_server->host)) - return true; - } - - return false; -} - -static thread_return_t THREAD_CALL resolver_thread_entry(void *arg) { - thread_set_name_self("juice resolver"); - agent_resolve_servers((juice_agent_t *)arg); - return (thread_return_t)0; -} - -int agent_gather_candidates(juice_agent_t *agent) { - JLOG_VERBOSE("Gathering candidates"); - if (agent->conn_impl) { - JLOG_WARN("Candidates gathering already started"); - return 0; - } - - if (agent->mode == AGENT_MODE_UNKNOWN) { - JLOG_DEBUG("Assuming controlling mode"); - agent->mode = AGENT_MODE_CONTROLLING; - } - - agent_change_state(agent, JUICE_STATE_GATHERING); - - udp_socket_config_t socket_config; - memset(&socket_config, 0, sizeof(socket_config)); - socket_config.bind_address = agent->config.bind_address; - socket_config.port_begin = agent->config.local_port_range_begin; - socket_config.port_end = agent->config.local_port_range_end; - - if (conn_create(agent, &socket_config)) { - JLOG_FATAL("Connection creation for agent failed"); - return -1; - } - - addr_record_t records[ICE_MAX_CANDIDATES_COUNT - 1]; - int records_count = conn_get_addrs(agent, records, ICE_MAX_CANDIDATES_COUNT - 1); - if (records_count < 0) { - JLOG_ERROR("Failed to gather local host candidates"); - records_count = 0; - } else if (records_count == 0) { - JLOG_WARN("No local host candidates gathered"); - } else if (records_count > ICE_MAX_CANDIDATES_COUNT - 1) - records_count = ICE_MAX_CANDIDATES_COUNT - 1; - - conn_lock(agent); - - JLOG_VERBOSE("Adding %d local host candidates", records_count); - for (int i = 0; i < records_count; ++i) { - ice_candidate_t candidate; - if (ice_create_local_candidate(ICE_CANDIDATE_TYPE_HOST, 1, agent->local.candidates_count, - records + i, &candidate)) { - JLOG_ERROR("Failed to create host candidate"); - continue; - } - if (agent->local.candidates_count >= MAX_HOST_CANDIDATES_COUNT) { - JLOG_WARN("Local description already has the maximum number of host candidates"); - break; - } - if (ice_add_candidate(&candidate, &agent->local)) { - JLOG_ERROR("Failed to add candidate to local description"); - continue; - } - } - - ice_sort_candidates(&agent->local); - - for (int i = 0; i < agent->entries_count; ++i) - agent_translate_host_candidate_entry(agent, agent->entries + i); - - char buffer[BUFFER_SIZE]; - for (int i = 0; i < agent->local.candidates_count; ++i) { - ice_candidate_t *candidate = agent->local.candidates + i; - if (candidate->type != ICE_CANDIDATE_TYPE_HOST) - continue; - - if (ice_generate_candidate_sdp(candidate, buffer, BUFFER_SIZE) < 0) { - JLOG_ERROR("Failed to generate SDP for local candidate"); - continue; - } - - JLOG_DEBUG("Gathered host candidate: %s", buffer); - - if (agent->config.cb_candidate) - agent->config.cb_candidate(agent, buffer, agent->config.user_ptr); - } - - agent_change_state(agent, JUICE_STATE_CONNECTING); - conn_unlock(agent); - conn_interrupt(agent); - - if (has_nonnumeric_server_hostnames(&agent->config)) { - // Resolve server hostnames in a separate thread as it may block - JLOG_DEBUG("Starting resolver thread for servers"); - int ret = thread_init(&agent->resolver_thread, resolver_thread_entry, agent); - if (ret) { - JLOG_FATAL("Thread creation failed, error=%d", ret); - agent_update_gathering_done(agent); - return -1; - } - agent->resolver_thread_started = true; - } else { - JLOG_DEBUG("Resolving servers synchronously"); - if (agent_resolve_servers(agent) < 0) - return -1; - } - - return 0; -} - -int agent_resolve_servers(juice_agent_t *agent) { - conn_lock(agent); - - // TURN server resolution - juice_concurrency_mode_t mode = agent->config.concurrency_mode; - if (mode == JUICE_CONCURRENCY_MODE_MUX) { - if (agent->config.turn_servers_count > 0) - JLOG_WARN("TURN servers are not supported in mux mode"); - - } else if (agent->config.turn_servers_count > 0) { - int count = 0; - for (int i = 0; i < agent->config.turn_servers_count; ++i) { - if (count >= MAX_RELAY_ENTRIES_COUNT) - break; - - juice_turn_server_t *turn_server = agent->config.turn_servers + i; - if (!turn_server->host) - continue; - - if (!turn_server->port) - turn_server->port = 3478; // default TURN port - - char service[8]; - snprintf(service, 8, "%hu", turn_server->port); - addr_record_t records[DEFAULT_MAX_RECORDS_COUNT]; - int records_count = - addr_resolve(turn_server->host, service, records, DEFAULT_MAX_RECORDS_COUNT); - if (records_count > 0) { - if (records_count > DEFAULT_MAX_RECORDS_COUNT) - records_count = DEFAULT_MAX_RECORDS_COUNT; - - JLOG_INFO("Using TURN server %s:%s", turn_server->host, service); - - addr_record_t *record = NULL; - for (int j = 0; j < records_count; ++j) { - int family = records[j].addr.ss_family; - // Prefer IPv4 for TURN - if (family == AF_INET) { - record = records + j; - break; - } - if (family == AF_INET6 && !record) - record = records + j; - } - if (record) { - // Ignore duplicate TURN servers as they will cause conflicts - bool is_duplicate = false; - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->type == AGENT_STUN_ENTRY_TYPE_RELAY && - addr_record_is_equal(&entry->record, record, true)) { - is_duplicate = true; - break; - } - } - if (is_duplicate) { - JLOG_INFO("Duplicate TURN server, ignoring"); - continue; - } - - JLOG_VERBOSE("Registering STUN entry %d for relay request", - agent->entries_count); - agent_stun_entry_t *entry = agent->entries + agent->entries_count; - entry->type = AGENT_STUN_ENTRY_TYPE_RELAY; - entry->state = AGENT_STUN_ENTRY_STATE_PENDING; - entry->pair = NULL; - entry->record = *record; - entry->turn_redirections = 0; - entry->turn = calloc(1, sizeof(agent_turn_state_t)); - if (!entry->turn) { - JLOG_ERROR("Memory allocation for TURN state failed"); - break; - } - if (turn_init_map(&entry->turn->map, AGENT_TURN_MAP_SIZE) < 0) { - free(entry->turn); - break; - } - snprintf(entry->turn->credentials.username, STUN_MAX_USERNAME_LEN, "%s", - turn_server->username); - entry->turn->password = turn_server->password; - juice_random(entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - ++agent->entries_count; - - agent_arm_transmission(agent, entry, STUN_PACING_TIME * i); - - ++count; - } - } else { - JLOG_ERROR("TURN address resolution failed"); - } - } - } - - // STUN server resolution - // The entry is added after so the TURN server address will be matched in priority - if (agent->config.stun_server_host) { - if (!agent->config.stun_server_port) - agent->config.stun_server_port = 3478; // default STUN port - - char service[8]; - snprintf(service, 8, "%hu", agent->config.stun_server_port); - addr_record_t records[MAX_STUN_SERVER_RECORDS_COUNT]; - int records_count = addr_resolve(agent->config.stun_server_host, service, records, - MAX_STUN_SERVER_RECORDS_COUNT); - if (records_count > 0) { - if (records_count > MAX_STUN_SERVER_RECORDS_COUNT) - records_count = MAX_STUN_SERVER_RECORDS_COUNT; - - JLOG_INFO("Using STUN server %s:%s", agent->config.stun_server_host, service); - - for (int i = 0; i < records_count; ++i) { - if (i >= MAX_SERVER_ENTRIES_COUNT) - break; - JLOG_VERBOSE("Registering STUN entry %d for server request", agent->entries_count); - agent_stun_entry_t *entry = agent->entries + agent->entries_count; - entry->type = AGENT_STUN_ENTRY_TYPE_SERVER; - entry->state = AGENT_STUN_ENTRY_STATE_PENDING; - entry->pair = NULL; - entry->record = records[i]; - juice_random(entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - ++agent->entries_count; - - agent_arm_transmission(agent, entry, STUN_PACING_TIME * i); - } - } else { - JLOG_ERROR("STUN server address resolution failed"); - } - } - - agent_update_gathering_done(agent); - conn_unlock(agent); - conn_interrupt(agent); - return 0; -} - -int agent_get_local_description(juice_agent_t *agent, char *buffer, size_t size) { - conn_lock(agent); - if (ice_generate_sdp(&agent->local, buffer, size) < 0) { - JLOG_ERROR("Failed to generate local SDP description"); - conn_unlock(agent); - return -1; - } - JLOG_VERBOSE("Generated local SDP description: %s", buffer); - - if (agent->mode == AGENT_MODE_UNKNOWN) { - JLOG_DEBUG("Assuming controlling mode"); - agent->mode = AGENT_MODE_CONTROLLING; - } - - conn_unlock(agent); - return 0; -} - -int agent_set_remote_description(juice_agent_t *agent, const char *sdp) { - conn_lock(agent); - JLOG_VERBOSE("Setting remote SDP description: %s", sdp); - - ice_description_t remote; - int ret = ice_parse_sdp(sdp, &remote); - if (ret < 0) { - if (ret == ICE_PARSE_MISSING_UFRAG) - JLOG_ERROR("Missing ICE user fragment in remote description"); - else if (ret == ICE_PARSE_MISSING_PWD) - JLOG_ERROR("Missing ICE password in remote description"); - else - JLOG_ERROR("Failed to parse remote SDP description"); - - conn_unlock(agent); - return -1; - } - - if (*agent->remote.ice_ufrag) { - // There is already a remote description - if (strcmp(agent->remote.ice_ufrag, remote.ice_ufrag) == 0 || - strcmp(agent->remote.ice_pwd, remote.ice_pwd) == 0) { - JLOG_DEBUG("Remote description is already set, ignoring"); - conn_unlock(agent); - return 0; - } - - JLOG_WARN("ICE restart is unsupported"); - conn_unlock(agent); - return -1; - } - - agent->remote = remote; - - agent_update_pac_timer(agent); - - if (agent->remote.ice_lite && agent->mode != AGENT_MODE_CONTROLLING) { - // RFC 8445 6.1.1. Determining Role: - // The full agent MUST take the controlling role, and the lite agent MUST take the - // controlled role. - JLOG_DEBUG("Remote ICE agent is lite, assuming controlling mode"); - agent->mode = AGENT_MODE_CONTROLLING; - } else if (agent->mode == AGENT_MODE_UNKNOWN) { - JLOG_DEBUG("Assuming controlled mode"); - agent->mode = AGENT_MODE_CONTROLLED; - } - - // There is only one component, therefore we can unfreeze already existing pairs now - JLOG_DEBUG("Unfreezing %d existing candidate pairs", (int)agent->candidate_pairs_count); - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - agent_unfreeze_candidate_pair(agent, agent->candidate_pairs + i); - } - JLOG_DEBUG("Adding %d candidates from remote description", (int)agent->remote.candidates_count); - for (int i = 0; i < agent->remote.candidates_count; ++i) { - ice_candidate_t *remote = agent->remote.candidates + i; - if (agent_add_candidate_pairs_for_remote(agent, remote)) - JLOG_WARN("Failed to add candidate pair from remote description"); - } - - conn_unlock(agent); - conn_interrupt(agent); - return 0; -} - -int agent_add_remote_candidate(juice_agent_t *agent, const char *sdp) { - conn_lock(agent); - JLOG_VERBOSE("Adding remote candidate: %s", sdp); - if (agent->remote.finished) { - JLOG_ERROR("Remote candidate added after remote gathering done"); - conn_unlock(agent); - return -1; - } - ice_candidate_t candidate; - int ret = ice_parse_candidate_sdp(sdp, &candidate); - if (ret < 0) { - if (ret == ICE_PARSE_IGNORED) - JLOG_DEBUG("Ignored SDP candidate: %s", sdp); - else if (ret == ICE_PARSE_ERROR) - JLOG_ERROR("Failed to parse remote SDP candidate: %s", sdp); - - conn_unlock(agent); - return -1; - } - if (ice_add_candidate(&candidate, &agent->remote)) { - JLOG_ERROR("Failed to add candidate to remote description"); - conn_unlock(agent); - return -1; - } - ice_candidate_t *remote = agent->remote.candidates + agent->remote.candidates_count - 1; - ret = agent_add_candidate_pairs_for_remote(agent, remote); - - conn_unlock(agent); - conn_interrupt(agent); - return ret; -} - -int agent_set_remote_gathering_done(juice_agent_t *agent) { - conn_lock(agent); - agent->remote.finished = true; - conn_unlock(agent); - conn_interrupt(agent); - return 0; -} - -int agent_send(juice_agent_t *agent, const char *data, size_t size, int ds) { - // Try not to lock in the send path - agent_stun_entry_t *selected_entry = atomic_load(&agent->selected_entry); - if (!selected_entry) { - JLOG_ERROR("Send while ICE is not connected"); - return -1; - } - - if (selected_entry->relay_entry) { - // The datagram should be sent through the relay, use a channel to minimize overhead - conn_lock(agent); // We have to lock - int ret = agent_channel_send(agent, selected_entry->relay_entry, &selected_entry->record, - data, size, ds); - conn_unlock(agent); - return ret; - } - - return agent_direct_send(agent, &selected_entry->record, data, size, ds); -} - -int agent_direct_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds) { - return conn_send(agent, dst, data, size, ds); -} - -int agent_relay_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr_record_t *dst, - const char *data, size_t size, int ds) { - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - - JLOG_VERBOSE("Sending datagram via TURN Send Indication, size=%d", size); - - // Send CreatePermission if necessary - if (!turn_has_permission(&entry->turn->map, dst)) - if (agent_send_turn_create_permission_request(agent, entry, dst, ds)) - return -1; - - // Send the data in a TURN Send indication - stun_message_t msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_class = STUN_CLASS_INDICATION; - msg.msg_method = STUN_METHOD_SEND; - juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE); - msg.peer = *dst; - msg.data = data; - msg.data_size = size; - - char buffer[BUFFER_SIZE]; - size = stun_write(buffer, BUFFER_SIZE, &msg, NULL); // no password - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - - return agent_direct_send(agent, &entry->record, buffer, size, ds); -} - -int agent_channel_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr_record_t *record, - const char *data, size_t size, int ds) { - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - - // Send ChannelBind if necessary - uint16_t channel; - if (!turn_get_bound_channel(&entry->turn->map, record, &channel)) - if (agent_send_turn_channel_bind_request(agent, entry, record, ds, &channel) < 0) - return -1; - - JLOG_VERBOSE("Sending datagram via TURN ChannelData, channel=0x%hX, size=%d", channel, size); - - // Send the data wrapped as ChannelData - char buffer[BUFFER_SIZE]; - int len = turn_wrap_channel_data(buffer, BUFFER_SIZE, data, size, channel); - if (len <= 0) { - JLOG_ERROR("TURN ChannelData wrapping failed"); - return -1; - } - - return agent_direct_send(agent, &entry->record, buffer, len, ds); -} - -juice_state_t agent_get_state(juice_agent_t *agent) { - conn_lock(agent); - juice_state_t state = agent->state; - conn_unlock(agent); - return state; -} - -int agent_get_selected_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, - ice_candidate_t *remote) { - conn_lock(agent); - ice_candidate_pair_t *pair = agent->selected_pair; - if (!pair) { - conn_unlock(agent); - return -1; - } - - if (local) - *local = pair->local ? *pair->local : agent->local.candidates[0]; - if (remote) - *remote = *pair->remote; - - conn_unlock(agent); - return 0; -} - -int agent_conn_update(juice_agent_t *agent, timestamp_t *next_timestamp) { - return agent_bookkeeping(agent, next_timestamp); -} - -int agent_conn_recv(juice_agent_t *agent, char *buf, size_t len, const addr_record_t *src) { - agent_input(agent, buf, len, src, NULL); - return 0; // ignore errors -} - -int agent_conn_fail(juice_agent_t *agent) { - agent_change_state(agent, JUICE_STATE_FAILED); - atomic_store(&agent->selected_entry, NULL); // disallow sending - return 0; -} - -int agent_input(juice_agent_t *agent, char *buf, size_t len, const addr_record_t *src, - const addr_record_t *relayed) { - JLOG_VERBOSE("Received datagram, size=%d", len); - - if (agent->state == JUICE_STATE_DISCONNECTED || agent->state == JUICE_STATE_GATHERING) - return 0; - - if (is_stun_datagram(buf, len)) { - if (JLOG_DEBUG_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - if (relayed) { - char relayed_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(relayed, relayed_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Received STUN datagram from %s relayed via %s", src_str, relayed_str); - } else { - JLOG_DEBUG("Received STUN datagram from %s", src_str); - } - } - stun_message_t msg; - if (stun_read(buf, len, &msg) < 0) { - JLOG_ERROR("STUN message reading failed"); - return -1; - } - return agent_dispatch_stun(agent, buf, len, &msg, src, relayed); - } - - if (JLOG_DEBUG_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - if (relayed) { - char relayed_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(relayed, relayed_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Received non-STUN datagram from %s relayed via %s", src_str, relayed_str); - } else { - JLOG_DEBUG("Received non-STUN datagram from %s", src_str); - } - } - agent_stun_entry_t *entry = agent_find_entry_from_record(agent, src, relayed); - if (!entry) { - JLOG_WARN("Received a datagram from unknown address, ignoring"); - return -1; - } - switch (entry->type) { - case AGENT_STUN_ENTRY_TYPE_RELAY: - if (is_channel_data(buf, len)) { - JLOG_DEBUG("Received ChannelData datagram"); - return agent_process_channel_data(agent, entry, buf, len); - } - break; - - case AGENT_STUN_ENTRY_TYPE_CHECK: - JLOG_DEBUG("Received application datagram"); - if (agent->config.cb_recv) - agent->config.cb_recv(agent, buf, len, agent->config.user_ptr); - return 0; - - default: - break; - } - - JLOG_WARN("Received unexpected non-STUN datagram, ignoring"); - return -1; -} - -int agent_bookkeeping(juice_agent_t *agent, timestamp_t *next_timestamp) { - JLOG_VERBOSE("Bookkeeping..."); - - timestamp_t now = current_timestamp(); - *next_timestamp = now + 6000000; - - if (agent->state == JUICE_STATE_DISCONNECTED || agent->state == JUICE_STATE_GATHERING) - return 0; - - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - - // STUN requests transmission or retransmission - if (entry->state == AGENT_STUN_ENTRY_STATE_PENDING) { - if (entry->next_transmission > now) - continue; - - if (entry->retransmissions >= 0) { - if (JLOG_DEBUG_ENABLED) { - char record_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(&entry->record, record_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("STUN entry %d: Sending request to %s (%d retransmission%s left)", i, - record_str, entry->retransmissions, - entry->retransmissions >= 2 ? "s" : ""); - } - int ret; - switch (entry->type) { - case AGENT_STUN_ENTRY_TYPE_RELAY: - ret = agent_send_turn_allocate_request(agent, entry, STUN_METHOD_ALLOCATE); - break; - - default: - ret = agent_send_stun_binding(agent, entry, STUN_CLASS_REQUEST, 0, NULL, NULL); - break; - } - - if (ret >= 0) { - --entry->retransmissions; - if (entry->retransmissions < 0) { - entry->next_transmission = now + LAST_STUN_RETRANSMISSION_TIMEOUT; - } else { - entry->next_transmission = now + entry->retransmission_timeout; - entry->retransmission_timeout *= 2; - } - continue; - } - } - - // Failure sending or end of retransmissions - JLOG_DEBUG("STUN entry %d: Failed", i); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - entry->next_transmission = 0; - - switch (entry->type) { - case AGENT_STUN_ENTRY_TYPE_RELAY: - JLOG_INFO("TURN allocation failed"); - agent_update_gathering_done(agent); - break; - - case AGENT_STUN_ENTRY_TYPE_SERVER: - JLOG_INFO("STUN server binding failed"); - agent_update_gathering_done(agent); - break; - - default: - if (entry->pair) { - JLOG_DEBUG("Candidate pair check failed"); - entry->pair->state = ICE_CANDIDATE_PAIR_STATE_FAILED; - } - break; - } - } - // STUN keepalives - else if (entry->state == AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) { -#if JUICE_DISABLE_CONSENT_FRESHNESS - // No expiration -#else - // Consent freshness expiration - if (entry->pair && entry->pair->consent_expiry <= now) { - JLOG_INFO("STUN entry %d: Consent expired for candidate pair", i); - entry->pair->state = ICE_CANDIDATE_PAIR_STATE_FAILED; - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - entry->next_transmission = 0; - continue; - } -#endif - - if (entry->next_transmission > now) - continue; - - JLOG_DEBUG("STUN entry %d: Sending keepalive", i); - - juice_random(entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - - int ret; - switch (entry->type) { - case AGENT_STUN_ENTRY_TYPE_RELAY: - // RFC 8445 5.1.1.4. Keeping Candidates Alive: - // Refreshes for allocations are done using the Refresh transaction, as described in - // [RFC5766] - ret = agent_send_turn_allocate_request(agent, entry, STUN_METHOD_REFRESH); - break; - case AGENT_STUN_ENTRY_TYPE_SERVER: - // RFC 8445 5.1.1.4. Keeping Candidates Alive: - // For server-reflexive candidates learned through a Binding request, the bindings - // MUST be kept alive by additional Binding requests to the server. - ret = agent_send_stun_binding(agent, entry, STUN_CLASS_REQUEST, 0, NULL, NULL); - break; - default: -#if JUICE_DISABLE_CONSENT_FRESHNESS - // RFC 8445 11. Keepalives: - // All endpoints MUST send keepalives for each data session. [...] STUN keepalives - // MUST be used when an ICE agent is a full ICE implementation and is communicating - // with a peer that supports ICE (lite or full). [...] When STUN is being used for - // keepalives, a STUN Binding Indication is used [RFC5389]. - ret = agent_send_stun_binding(agent, entry, STUN_CLASS_INDICATION, 0, NULL, NULL); -#else - // RFC 7675 4. Design Considerations: - // STUN binding requests sent for consent freshness also serve the keepalive purpose - // (i.e., to keep NAT bindings alive). Because of that, dedicated keepalives (e.g., - // STUN Binding Indications) are not sent on candidate pairs where consent requests - // are sent, in accordance with Section 20.2.3 of [RFC5245]. - ret = agent_send_stun_binding(agent, entry, STUN_CLASS_REQUEST, 0, NULL, NULL); -#endif - break; - } - - if (ret < 0) { - JLOG_WARN("Sending keepalive failed"); - agent_arm_transmission(agent, entry, STUN_KEEPALIVE_PERIOD); - continue; - } - - agent_arm_keepalive(agent, entry); - - } else { - // Entry does not transmit, unset next transmission - entry->next_transmission = 0; - } - } - - int pending_count = 0; - ice_candidate_pair_t *nominated_pair = NULL; - ice_candidate_pair_t *selected_pair = NULL; - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - ice_candidate_pair_t *pair = agent->ordered_pairs[i]; - if (pair->nominated) { - // RFC 8445 8.1.1. Nominating Pairs: - // If more than one candidate pair is nominated by the controlling agent, and if the - // controlled agent accepts multiple nominations requests, the agents MUST produce the - // selected pairs and use the pairs with the highest priority. - if (!nominated_pair) { - nominated_pair = pair; - selected_pair = pair; - } - } else if (pair->state == ICE_CANDIDATE_PAIR_STATE_SUCCEEDED) { - if (!selected_pair) - selected_pair = pair; - } else if (pair->state == ICE_CANDIDATE_PAIR_STATE_PENDING) { - if (agent->mode == AGENT_MODE_CONTROLLING && selected_pair) { - // A higher-priority pair will be used, we can stop checking. - // Entries will be synchronized after the current loop. - JLOG_VERBOSE("Cancelling check for lower-priority pair"); - pair->state = ICE_CANDIDATE_PAIR_STATE_FROZEN; - } else { - ++pending_count; - } - } - } - - if (agent->mode == AGENT_MODE_CONTROLLING && nominated_pair) { - // RFC 8445 8.1.1. Nominating Pairs: - // Once the controlling agent has successfully nominated a candidate pair, the agent MUST - // NOT nominate another pair for same component of the data stream within the ICE session. - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - ice_candidate_pair_t *pair = agent->ordered_pairs[i]; - if (pair != nominated_pair && pair->state == ICE_CANDIDATE_PAIR_STATE_PENDING) { - // Entries will be synchronized after the current loop. - JLOG_VERBOSE("Cancelling check for non-nominated pair"); - pair->state = ICE_CANDIDATE_PAIR_STATE_FROZEN; - } - } - pending_count = 0; - } - - // Cancel entries of frozen pairs - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->pair && entry->pair->state == ICE_CANDIDATE_PAIR_STATE_FROZEN && - entry->state != AGENT_STUN_ENTRY_STATE_IDLE && - entry->state != AGENT_STUN_ENTRY_STATE_CANCELLED) { - JLOG_DEBUG("STUN entry %d: Cancelled", i); - entry->state = AGENT_STUN_ENTRY_STATE_CANCELLED; - entry->next_transmission = 0; - } - } - - if (nominated_pair && nominated_pair->state == ICE_CANDIDATE_PAIR_STATE_FAILED) { - JLOG_WARN("Lost connectivity"); - agent_change_state(agent, JUICE_STATE_FAILED); - atomic_store(&agent->selected_entry, NULL); // disallow sending - return 0; - } - - if (selected_pair) { - // Change selected entry if this is a new selected pair - if (agent->selected_pair != selected_pair) { - JLOG_DEBUG(selected_pair->nominated ? "New selected and nominated pair" - : "New selected pair"); - agent->selected_pair = selected_pair; - - // Start nomination timer if controlling - if (agent->mode == AGENT_MODE_CONTROLLING) - agent->nomination_timestamp = now + NOMINATION_TIMEOUT; - - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->pair == selected_pair) { - atomic_store(&agent->selected_entry, entry); - break; - } - } - } - - if (nominated_pair) { - // Completed - // Do not allow direct transition from connecting to completed - if (agent->state == JUICE_STATE_CONNECTING) - agent_change_state(agent, JUICE_STATE_CONNECTED); - - agent_change_state(agent, JUICE_STATE_COMPLETED); - - agent_stun_entry_t *nominated_entry = NULL; - agent_stun_entry_t *relay_entry = NULL; - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->pair && entry->pair == nominated_pair) { - nominated_entry = entry; - relay_entry = nominated_entry->relay_entry; - break; - } - } - - // Enable keepalive for the entry of the nominated pair - if (nominated_entry && - nominated_entry->state != AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) { - nominated_entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE; - agent_arm_keepalive(agent, nominated_entry); - } - - // If the entry of the nominated candidate is relayed locally, we need also to - // refresh the corresponding TURN session regularly - if (relay_entry && relay_entry->state != AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) { - relay_entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE; - agent_arm_keepalive(agent, relay_entry); - } - - // Disable keepalives for other entries - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry != nominated_entry && entry != relay_entry && - entry->state == AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) - entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED; - } - - } else { - // Connected - agent_change_state(agent, JUICE_STATE_CONNECTED); - - if (agent->mode == AGENT_MODE_CONTROLLING && !selected_pair->nomination_requested) { - if (pending_count == 0 || - (agent->nomination_timestamp && now >= agent->nomination_timestamp)) { - // Nominate selected - JLOG_DEBUG("Requesting pair nomination (controlling)"); - selected_pair->nomination_requested = true; - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->pair && entry->pair == selected_pair) { - entry->state = - AGENT_STUN_ENTRY_STATE_PENDING; // we don't want keepalives - agent_arm_transmission(agent, entry, 0); // transmit now - break; - } - } - } else if (agent->nomination_timestamp && - *next_timestamp > agent->nomination_timestamp) { - *next_timestamp = agent->nomination_timestamp; - } - } - } - - } else if (pending_count == 0 && agent->pac_timestamp) { - // RFC 8863: While the timer is still running, the ICE agent MUST NOT update a checklist - // state from Running to Failed, even if there are no pairs left in the checklist to check. - if (now >= agent->pac_timestamp) { - JLOG_INFO("Connectivity timer expired"); - agent_change_state(agent, JUICE_STATE_FAILED); - atomic_store(&agent->selected_entry, NULL); // disallow sending - return 0; - } else if (*next_timestamp > agent->pac_timestamp) { - *next_timestamp = agent->pac_timestamp; - } - } - - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->next_transmission && *next_timestamp > entry->next_transmission) - *next_timestamp = entry->next_transmission; - - if (entry->state == AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE && entry->pair && - *next_timestamp > entry->pair->consent_expiry) - *next_timestamp = selected_pair->consent_expiry; - } - - return 0; -} - -void agent_change_state(juice_agent_t *agent, juice_state_t state) { - if (state != agent->state) { - JLOG_INFO("Changing state to %s", juice_state_to_string(state)); - agent->state = state; - if (agent->config.cb_state_changed) - agent->config.cb_state_changed(agent, state, agent->config.user_ptr); - } -} - -int agent_verify_stun_binding(juice_agent_t *agent, void *buf, size_t size, - const stun_message_t *msg) { - if (msg->msg_method != STUN_METHOD_BINDING) - return -1; - - if (msg->msg_class == STUN_CLASS_INDICATION || msg->msg_class == STUN_CLASS_RESP_ERROR) - return 0; - - if (!msg->has_integrity) { - JLOG_WARN("Missing integrity in STUN message"); - return -1; - } - - // Check username (The USERNAME attribute is not present in responses) - if (msg->msg_class == STUN_CLASS_REQUEST) { - char username[STUN_MAX_USERNAME_LEN]; - strcpy(username, msg->credentials.username); - char *separator = strchr(username, ':'); - if (!separator) { - JLOG_WARN("STUN username invalid, username=\"%s\"", username); - return -1; - } - *separator = '\0'; - const char *local_ufrag = username; - const char *remote_ufrag = separator + 1; - if (strcmp(local_ufrag, agent->local.ice_ufrag) != 0) { - JLOG_WARN("STUN local ufrag check failed, expected=\"%s\", actual=\"%s\"", - agent->local.ice_ufrag, local_ufrag); - return -1; - } - // RFC 8445 7.3. STUN Server Procedures: - // It is possible (and in fact very likely) that the initiating agent will receive a Binding - // request prior to receiving the candidates from its peer. If this happens, the agent MUST - // immediately generate a response. - if (*agent->remote.ice_ufrag != '\0' && - strcmp(remote_ufrag, agent->remote.ice_ufrag) != 0) { - JLOG_WARN("STUN remote ufrag check failed, expected=\"%s\", actual=\"%s\"", - agent->remote.ice_ufrag, remote_ufrag); - return -1; - } - } - // Check password - const char *password = - msg->msg_class == STUN_CLASS_REQUEST ? agent->local.ice_pwd : agent->remote.ice_pwd; - if (*password == '\0') { - JLOG_WARN("STUN integrity check failed, unknown password"); - return -1; - } - if (!stun_check_integrity(buf, size, msg, password)) { - JLOG_WARN("STUN integrity check failed, password=\"%s\"", password); - return -1; - } - return 0; -} - -int agent_verify_credentials(juice_agent_t *agent, const agent_stun_entry_t *entry, void *buf, - size_t size, stun_message_t *msg) { - (void)agent; - - // RFC 8489: If the response is an error response with an error code of 400 (Bad Request) and - // does not contain either the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, then the - // response MUST be discarded, as if it were never received. This means that retransmits, if - // applicable, will continue. - if (msg->msg_class == STUN_CLASS_INDICATION || - (msg->msg_class == STUN_CLASS_RESP_ERROR && msg->error_code != 400)) - return 0; - - if (!msg->has_integrity) { - JLOG_WARN("Missing integrity in STUN message"); - return -1; - } - if (!entry->turn) { - JLOG_WARN("No credentials for entry"); - return -1; - } - stun_credentials_t *credentials = &entry->turn->credentials; - const char *password = entry->turn->password; - - // Prepare credentials - strcpy(msg->credentials.realm, credentials->realm); - strcpy(msg->credentials.nonce, credentials->nonce); - strcpy(msg->credentials.username, credentials->username); - - // Check credentials - if (!stun_check_integrity(buf, size, msg, password)) { - JLOG_WARN("STUN integrity check failed"); - return -1; - } - return 0; -} - -int agent_dispatch_stun(juice_agent_t *agent, void *buf, size_t size, stun_message_t *msg, - const addr_record_t *src, const addr_record_t *relayed) { - if (msg->msg_method == STUN_METHOD_BINDING && msg->has_integrity) { - JLOG_VERBOSE("STUN message is from the remote peer"); - // Verify the message now - if (agent_verify_stun_binding(agent, buf, size, msg)) { - JLOG_WARN("STUN message verification failed"); - return -1; - } - if (!relayed) { - if (agent_add_remote_reflexive_candidate(agent, ICE_CANDIDATE_TYPE_PEER_REFLEXIVE, - msg->priority, src)) { - JLOG_WARN("Failed to add remote peer reflexive candidate from STUN message"); - } - } - } - - agent_stun_entry_t *entry = NULL; - if (STUN_IS_RESPONSE(msg->msg_class)) { - JLOG_VERBOSE("STUN message is a response, looking for transaction ID"); - entry = agent_find_entry_from_transaction_id(agent, msg->transaction_id); - if (!entry) { - JLOG_WARN("No STUN entry matching transaction ID, ignoring"); - return -1; - } - } else { - JLOG_VERBOSE("STUN message is a request or indication, looking for remote address"); - entry = agent_find_entry_from_record(agent, src, relayed); - if (entry) { - JLOG_VERBOSE("Found STUN entry matching remote address"); - } else { - // This may happen normally, for instance when there is no space left for reflexive - // candidates - JLOG_DEBUG("No STUN entry matching remote address, ignoring"); - return 0; - } - } - - switch (msg->msg_method) { - case STUN_METHOD_BINDING: - // Message was verified earlier, no need to re-verify - if (entry->type == AGENT_STUN_ENTRY_TYPE_CHECK && !msg->has_integrity && - (msg->msg_class == STUN_CLASS_REQUEST || msg->msg_class == STUN_CLASS_RESP_SUCCESS)) { - JLOG_WARN("Missing integrity in STUN Binding message from remote peer, ignoring"); - return -1; - } - return agent_process_stun_binding(agent, msg, entry, src, relayed); - - case STUN_METHOD_ALLOCATE: - case STUN_METHOD_REFRESH: - if (agent_verify_credentials(agent, entry, buf, size, msg)) { - JLOG_WARN("Ignoring invalid TURN Allocate message"); - return -1; - } - return agent_process_turn_allocate(agent, msg, entry); - - case STUN_METHOD_CREATE_PERMISSION: - if (agent_verify_credentials(agent, entry, buf, size, msg)) { - JLOG_WARN("Ignoring invalid TURN CreatePermission message"); - return -1; - } - return agent_process_turn_create_permission(agent, msg, entry); - - case STUN_METHOD_CHANNEL_BIND: - if (agent_verify_credentials(agent, entry, buf, size, msg)) { - JLOG_WARN("Ignoring invalid TURN ChannelBind message"); - return -1; - } - return agent_process_turn_channel_bind(agent, msg, entry); - - case STUN_METHOD_DATA: - return agent_process_turn_data(agent, msg, entry); - - default: - JLOG_WARN("Unknown STUN method 0x%X, ignoring", msg->msg_method); - return -1; - } -} - -int agent_process_stun_binding(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry, const addr_record_t *src, - const addr_record_t *relayed) { - - switch (msg->msg_class) { - case STUN_CLASS_REQUEST: { - JLOG_DEBUG("Received STUN Binding request"); - if (entry->type != AGENT_STUN_ENTRY_TYPE_CHECK) - return -1; - - ice_candidate_pair_t *pair = entry->pair; - if (msg->ice_controlling == msg->ice_controlled) { - JLOG_WARN("Controlling and controlled attributes mismatch in request"); - agent_send_stun_binding(agent, entry, STUN_CLASS_RESP_ERROR, 400, msg->transaction_id, - NULL); - return -1; - } - // RFC8445 7.3.1.1. Detecting and Repairing Role Conflicts: - // If the agent is in the controlling role, and the ICE-CONTROLLING attribute is present in - // the request: - // * If the agent's tiebreaker value is larger than or equal to the contents of the - // ICE-CONTROLLING attribute, the agent generates a Binding error response and includes an - // ERROR-CODE attribute with a value of 487 (Role Conflict) but retains its role. - // * If the agent's tiebreaker value is less than the contents of the ICE-CONTROLLING - // attribute, the agent switches to the controlled role. - if (agent->mode == AGENT_MODE_CONTROLLING && msg->ice_controlling) { - JLOG_WARN("ICE role conflict (both controlling)"); - if (agent->ice_tiebreaker >= msg->ice_controlling) { - JLOG_DEBUG("Asking remote peer to switch roles"); - agent_send_stun_binding(agent, entry, STUN_CLASS_RESP_ERROR, 487, - msg->transaction_id, NULL); - } else { - JLOG_DEBUG("Switching to controlled role"); - agent->mode = AGENT_MODE_CONTROLLED; - agent_update_candidate_pairs(agent); - } - break; - } - // If the agent is in the controlled role, and the ICE-CONTROLLED attribute is present in - // the request: - // * If the agent's tiebreaker value is larger than or equal to the contents of the - // ICE-CONTROLLED attribute, the agent switches to the controlling role. - // * If the agent's tiebreaker value is less than the contents of the ICE-CONTROLLED - // attribute, the agent generates a Binding error response and includes an ERROR-CODE - // attribute with a value of 487 (Role Conflict) but retains its role. - if (msg->ice_controlled && agent->mode == AGENT_MODE_CONTROLLED) { - JLOG_WARN("ICE role conflict (both controlled)"); - if (agent->ice_tiebreaker >= msg->ice_controlling) { - JLOG_DEBUG("Switching to controlling role"); - agent->mode = AGENT_MODE_CONTROLLING; - agent_update_candidate_pairs(agent); - } else { - JLOG_DEBUG("Asking remote peer to switch roles"); - agent_send_stun_binding(agent, entry, STUN_CLASS_RESP_ERROR, 487, - msg->transaction_id, NULL); - } - break; - } - if (msg->use_candidate) { - if (!msg->ice_controlling) { - JLOG_WARN("STUN message use_candidate missing ice_controlling attribute"); - agent_send_stun_binding(agent, entry, STUN_CLASS_RESP_ERROR, 400, - msg->transaction_id, NULL); - return -1; - } - // RFC 8445 7.3.1.5. Updating the Nominated Flag: - // If the state of this pair is Succeeded, it means that the check previously sent by - // this pair produced a successful response and generated a valid pair. The agent sets - // the nominated flag value of the valid pair to true. - if (pair->state == ICE_CANDIDATE_PAIR_STATE_SUCCEEDED) { - JLOG_DEBUG("Got a nominated pair (controlled)"); - pair->nominated = true; - } else if (!pair->nomination_requested) { - JLOG_DEBUG("Pair nomination requested (controlled)"); - pair->nomination_requested = true; - } - } - // Response - if (agent_send_stun_binding(agent, entry, STUN_CLASS_RESP_SUCCESS, 0, msg->transaction_id, - src)) { - JLOG_ERROR("Failed to send STUN Binding response"); - return -1; - } - // Triggered check - // RFC 8445: If the state of that pair is Succeeded, nothing further is done. If the state - // of that pair is In-Progress, [...] the agent MUST [...] trigger a new connectivity check - // of the pair. [...] If the state of that pair is Waiting, Frozen, or Failed, the agent - // MUST [...] trigger a new connectivity check of the pair. - if (pair->state != ICE_CANDIDATE_PAIR_STATE_SUCCEEDED && *agent->remote.ice_ufrag != '\0') { - JLOG_DEBUG("Triggered pair check"); - pair->state = ICE_CANDIDATE_PAIR_STATE_PENDING; - entry->state = AGENT_STUN_ENTRY_STATE_PENDING; - agent_arm_transmission(agent, entry, STUN_PACING_TIME); - } - break; - } - case STUN_CLASS_RESP_SUCCESS: { - JLOG_DEBUG("Received STUN Binding success response from %s", - entry->type == AGENT_STUN_ENTRY_TYPE_CHECK ? "peer" : "server"); - - if (entry->type == AGENT_STUN_ENTRY_TYPE_SERVER) - JLOG_INFO("STUN server binding successful"); - - if (entry->state != AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) { - entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED; - entry->next_transmission = 0; - } - - if (!agent->selected_pair || !agent->selected_pair->nominated) { - // We want to send keepalives now - entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE; - agent_arm_keepalive(agent, entry); - } - - if (msg->mapped.len && !relayed) { - JLOG_VERBOSE("Response has mapped address"); - - if (JLOG_INFO_ENABLED && entry->type != AGENT_STUN_ENTRY_TYPE_CHECK) { - char mapped_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(&msg->mapped, mapped_str, ADDR_MAX_STRING_LEN); - JLOG_INFO("Got STUN mapped address %s from server", mapped_str); - } - - ice_candidate_type_t type = (entry->type == AGENT_STUN_ENTRY_TYPE_CHECK) - ? ICE_CANDIDATE_TYPE_PEER_REFLEXIVE - : ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE; - if (agent_add_local_reflexive_candidate(agent, type, &msg->mapped)) { - JLOG_WARN("Failed to add local peer reflexive candidate from STUN mapped address"); - } - } - - if (entry->type == AGENT_STUN_ENTRY_TYPE_CHECK) { - ice_candidate_pair_t *pair = entry->pair; - if (!pair) { - JLOG_ERROR("STUN entry for candidate pair checking has no candidate pair"); - return -1; - } - - // 7.2.5.2.1. Non-Symmetric Transport Addresses: - // The ICE agent MUST check that the source and destination transport addresses in the - // Binding request and response are symmetric. [...] If the addresses are not symmetric, - // the agent MUST set the candidate pair state to Failed. - if (!addr_record_is_equal(src, &entry->record, true)) { - JLOG_DEBUG( - "Candidate pair check failed (non-symmetric source address in response)"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - entry->next_transmission = 0; - if (pair) - pair->state = ICE_CANDIDATE_PAIR_STATE_FAILED; - break; - } - - if (pair->state != ICE_CANDIDATE_PAIR_STATE_SUCCEEDED) { - JLOG_DEBUG("Candidate pair check succeeded"); - pair->state = ICE_CANDIDATE_PAIR_STATE_SUCCEEDED; - } - - if (!pair->local && msg->mapped.len) - pair->local = ice_find_candidate_from_addr(&agent->local, &msg->mapped, - ICE_CANDIDATE_TYPE_UNKNOWN); - - // Update consent timestamp - pair->consent_expiry = current_timestamp() + CONSENT_TIMEOUT; - - // RFC 8445 7.3.1.5. Updating the Nominated Flag: - // [...] once the check is sent and if it generates a successful response, and - // generates a valid pair, the agent sets the nominated flag of the pair to true. - if (pair->nomination_requested) { - JLOG_DEBUG("Got a nominated pair (%s)", - agent->mode == AGENT_MODE_CONTROLLING ? "controlling" : "controlled"); - pair->nominated = true; - } - } else if (entry->type == AGENT_STUN_ENTRY_TYPE_SERVER) { - agent_update_gathering_done(agent); - } - break; - } - case STUN_CLASS_RESP_ERROR: { - if (msg->error_code != STUN_ERROR_INTERNAL_VALIDATION_FAILED) { - if (msg->error_code == 487) - JLOG_DEBUG("Got STUN Binding error response, code=%u", - (unsigned int)msg->error_code); - else - JLOG_WARN("Got STUN Binding error response, code=%u", - (unsigned int)msg->error_code); - } - - if (entry->type == AGENT_STUN_ENTRY_TYPE_CHECK) { - if (msg->error_code == 487) { - if (entry->mode == agent->mode) { - // RFC 8445 7.2.5.1. Role Conflict: - // If the Binding request generates a 487 (Role Conflict) error response, and if - // the ICE agent included an ICE-CONTROLLED attribute in the request, the agent - // MUST switch to the controlling role. If the agent included an ICE-CONTROLLING - // attribute in the request, the agent MUST switch to the controlled role. Once - // the agent has switched its role, the agent MUST [...] set the candidate pair - // state to Waiting [and] change the tiebreaker value. - JLOG_WARN("ICE role conflict"); - JLOG_DEBUG("Switching roles to %s as requested", - entry->mode == AGENT_MODE_CONTROLLING ? "controlled" - : "controlling"); - agent->mode = entry->mode == AGENT_MODE_CONTROLLING ? AGENT_MODE_CONTROLLED - : AGENT_MODE_CONTROLLING; - agent_update_candidate_pairs(agent); - - juice_random(&agent->ice_tiebreaker, sizeof(agent->ice_tiebreaker)); - if (entry->state != AGENT_STUN_ENTRY_STATE_IDLE) { // Check might not be started - entry->state = AGENT_STUN_ENTRY_STATE_PENDING; - agent_arm_transmission(agent, entry, 0); - } - } else { - JLOG_DEBUG("Already switched roles to %s as requested", - agent->mode == AGENT_MODE_CONTROLLING ? "controlling" - : "controlled"); - } - } else { - // 7.2.5.2.4. Unrecoverable STUN Response: - // If the Binding request generates a STUN error response that is unrecoverable - // [RFC5389], the ICE agent SHOULD set the candidate pair state to Failed. - JLOG_DEBUG("Chandidate pair check failed (unrecoverable error)"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - entry->next_transmission = 0; - if (entry->pair) - entry->pair->state = ICE_CANDIDATE_PAIR_STATE_FAILED; - } - } else if (entry->type == AGENT_STUN_ENTRY_TYPE_SERVER) { - JLOG_INFO("STUN server binding failed (unrecoverable error)"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - } - break; - } - case STUN_CLASS_INDICATION: { - JLOG_VERBOSE("Received STUN Binding indication"); - break; - } - default: { - JLOG_WARN("Got STUN unexpected binding message, class=%u", (unsigned int)msg->msg_class); - return -1; - } - } - return 0; -} - -int agent_send_stun_binding(juice_agent_t *agent, agent_stun_entry_t *entry, stun_class_t msg_class, - unsigned int error_code, const uint8_t *transaction_id, - const addr_record_t *mapped) { - // Send STUN Binding - JLOG_DEBUG("Sending STUN Binding %s", - msg_class == STUN_CLASS_REQUEST - ? "request" - : (msg_class == STUN_CLASS_INDICATION ? "indication" : "response")); - - stun_message_t msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_class = msg_class; - msg.msg_method = STUN_METHOD_BINDING; - - if ((msg_class == STUN_CLASS_RESP_SUCCESS || msg_class == STUN_CLASS_RESP_ERROR) && - !transaction_id) { - JLOG_ERROR("No transaction ID specified for STUN response"); - return -1; - } - - if (transaction_id) - memcpy(msg.transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - else if (msg_class == STUN_CLASS_INDICATION) - juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE); - else - memcpy(msg.transaction_id, entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - - const char *password = NULL; - if (entry->type == AGENT_STUN_ENTRY_TYPE_CHECK) { - // RFC 8445 7.2.2. Forming Credentials: - // A connectivity-check Binding request MUST utilize the STUN short-term credential - // mechanism. The username for the credential is formed by concatenating the username - // fragment provided by the peer with the username fragment of the ICE agent sending the - // request, separated by a colon (":"). The password is equal to the password provided by - // the peer. - switch (msg_class) { - case STUN_CLASS_REQUEST: { - if (*agent->remote.ice_ufrag == '\0' || *agent->remote.ice_pwd == '\0') { - JLOG_DEBUG("Missing remote ICE credentials, dropping STUN binding request"); - return 0; - } - snprintf(msg.credentials.username, STUN_MAX_USERNAME_LEN, "%s:%s", - agent->remote.ice_ufrag, agent->local.ice_ufrag); - password = agent->remote.ice_pwd; - msg.ice_controlling = agent->mode == AGENT_MODE_CONTROLLING ? agent->ice_tiebreaker : 0; - msg.ice_controlled = agent->mode == AGENT_MODE_CONTROLLED ? agent->ice_tiebreaker : 0; - - // RFC 8445 7.1.1. PRIORITY - // The PRIORITY attribute MUST be included in a Binding request and be set to the value - // computed by the algorithm in Section 5.1.2 for the local candidate, but with the - // candidate type preference of peer-reflexive candidates. - int family = entry->record.addr.ss_family; - int index = entry->pair && entry->pair->local - ? (int)(entry->pair->local - agent->local.candidates) - : 0; - msg.priority = - ice_compute_priority(ICE_CANDIDATE_TYPE_PEER_REFLEXIVE, family, 1, index); - - // RFC 8445 8.1.1. Nominating Pairs: - // Once the controlling agent has picked a valid pair for nomination, it repeats the - // connectivity check that produced this valid pair [...], this time with the - // USE-CANDIDATE attribute. - msg.use_candidate = agent->mode == AGENT_MODE_CONTROLLING && entry->pair && - entry->pair->nomination_requested; - - entry->mode = agent->mode; // save current mode in case of conflict - break; - } - case STUN_CLASS_RESP_SUCCESS: - case STUN_CLASS_RESP_ERROR: { - password = agent->local.ice_pwd; - msg.error_code = error_code; - if (mapped) - msg.mapped = *mapped; - - break; - } - case STUN_CLASS_INDICATION: { - // RFC8445 11. Keepalives: - // When STUN is being used for keepalives, a STUN Binding Indication is used. The - // Indication MUST NOT utilize any authentication mechanism. It SHOULD contain the - // FINGERPRINT attribute to aid in demultiplexing, but it SHOULD NOT contain any other - // attributes. - } - } - } - - char buffer[BUFFER_SIZE]; - int size = stun_write(buffer, BUFFER_SIZE, &msg, password); - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - - if (entry->relay_entry) { - // The datagram must be sent through the relay - JLOG_DEBUG("Sending STUN message via relay"); - int ret; - if (entry->pair && entry->pair->nominated) - ret = agent_channel_send(agent, entry->relay_entry, &entry->record, buffer, size, 0); - else - ret = agent_relay_send(agent, entry->relay_entry, &entry->record, buffer, size, 0); - - if (ret < 0) { - JLOG_WARN("STUN message send via relay failed"); - return -1; - } - return 0; - } - - // Direct send - if (agent_direct_send(agent, &entry->record, buffer, size, 0) < 0) { - JLOG_WARN("STUN message send failed"); - return -1; - } - return 0; -} - -int agent_process_turn_allocate(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry) { - if (msg->msg_method != STUN_METHOD_ALLOCATE && msg->msg_method != STUN_METHOD_REFRESH) - return -1; - - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_WARN("Received TURN %s message for a non-relay entry, ignoring", - msg->msg_method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh"); - return -1; - } - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - - switch (msg->msg_class) { - case STUN_CLASS_RESP_SUCCESS: { - JLOG_DEBUG("Received TURN %s success response", - msg->msg_method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh"); - - if (msg->msg_method == STUN_METHOD_REFRESH) { - JLOG_DEBUG("TURN refresh successful"); - // There is nothing to do - break; - } - - JLOG_DEBUG("TURN allocate successful"); - - if (!msg->relayed.len) { - JLOG_ERROR("Expected relayed address in TURN Allocate response"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - return -1; - } - - if (entry->state != AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) { - entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED; - entry->next_transmission = 0; - } - - if (!agent->selected_pair || !agent->selected_pair->nominated) { - // We want to send refresh requests for keepalive now - entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE; - agent_arm_keepalive(agent, entry); - } - - if (msg->mapped.len) { - JLOG_VERBOSE("Response has mapped address"); - - if (JLOG_INFO_ENABLED) { - char mapped_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(&msg->mapped, mapped_str, ADDR_MAX_STRING_LEN); - JLOG_INFO("Got STUN mapped address %s from TURN server", mapped_str); - } - - if (agent_add_local_reflexive_candidate(agent, ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE, - &msg->mapped)) { - JLOG_WARN("Failed to add local peer reflexive candidate from TURN mapped address"); - } - } - - entry->relayed = msg->relayed; - if (agent_add_local_relayed_candidate(agent, &msg->relayed)) { - JLOG_WARN("Failed to add local relayed candidate from TURN relayed address"); - return -1; - } - - if (JLOG_INFO_ENABLED) { - char relayed_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(&entry->relayed, relayed_str, ADDR_MAX_STRING_LEN); - JLOG_INFO("Allocated TURN relayed address %s", relayed_str); - } - - agent_update_gathering_done(agent); - break; - } - case STUN_CLASS_RESP_ERROR: { - if (msg->error_code == 401) { // Unauthorized - JLOG_DEBUG("Got TURN %s Unauthorized response", - msg->msg_method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh"); - if (*entry->turn->credentials.realm != '\0') { - JLOG_ERROR("TURN authentication failed"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - return -1; - } - if (*msg->credentials.realm == '\0' || *msg->credentials.nonce == '\0') { - JLOG_ERROR("Expected realm and nonce in TURN error response"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - return -1; - } - - stun_process_credentials(&msg->credentials, &entry->turn->credentials); - - // Resend request when possible - agent_arm_transmission(agent, entry, 0); - - } else if (msg->error_code == 438) { // Stale Nonce - JLOG_DEBUG("Got TURN %s Stale Nonce response", - msg->msg_method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh"); - if (*msg->credentials.realm == '\0' || *msg->credentials.nonce == '\0') { - JLOG_ERROR("Expected realm and nonce in TURN error response"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - return -1; - } - - stun_process_credentials(&msg->credentials, &entry->turn->credentials); - - // Resend request when possible - agent_arm_transmission(agent, entry, 0); - - } else if (msg->msg_method == STUN_METHOD_ALLOCATE && - msg->error_code == 300) { // Try Alternate - // RFC 8489 10. ALTERNATE-SERVER Mechanism: - // A client using this extension handles a 300 (Try Alternate) error code as follows. - // The client looks for an ALTERNATE-SERVER attribute in the error response. If one is - // found, then the client considers the current transaction as failed and reattempts the - // request with the server specified in the attribute, using the same transport protocol - // used for the previous request. - if (!msg->alternate_server.len || - addr_record_is_equal(&msg->alternate_server, &entry->record, true)) { - JLOG_ERROR("Expected alternate server in TURN Allocate 300 Try Alternate response"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - return -1; - } - // Prevent infinite redirection loop - if (entry->turn_redirections >= MAX_TURN_REDIRECTIONS) { - JLOG_ERROR("Too many redirections for TURN Allocate"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - return -1; - } - - if (JLOG_INFO_ENABLED) { - char alternate_server_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(&msg->alternate_server, alternate_server_str, - ADDR_MAX_STRING_LEN); - JLOG_INFO("Trying alternate TURN server %s", alternate_server_str); - } - - // Change record and resend request when possible - ++entry->turn_redirections; - entry->record = msg->alternate_server; - agent_arm_transmission(agent, entry, 0); - - } else { - if (msg->error_code != STUN_ERROR_INTERNAL_VALIDATION_FAILED) - JLOG_WARN("Got TURN %s error response, code=%u", - msg->msg_method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh", - (unsigned int)msg->error_code); - - JLOG_INFO("TURN allocation failed"); - entry->state = AGENT_STUN_ENTRY_STATE_FAILED; - agent_update_gathering_done(agent); - } - break; - } - default: { - JLOG_WARN("Got unexpected TURN %s message, class=%u", - msg->msg_method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh", - (unsigned int)msg->msg_class); - return -1; - } - } - return 0; -} - -int agent_send_turn_allocate_request(juice_agent_t *agent, const agent_stun_entry_t *entry, - stun_method_t method) { - if (method != STUN_METHOD_ALLOCATE && method != STUN_METHOD_REFRESH) - return -1; - - JLOG_DEBUG("Sending TURN %s request", method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh"); - - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_ERROR("Attempted to send a TURN %s request for a non-relay entry", - method == STUN_METHOD_ALLOCATE ? "Allocate" : "Refresh"); - return -1; - } - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - - stun_message_t msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_class = STUN_CLASS_REQUEST; - msg.msg_method = method; - memcpy(msg.transaction_id, entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - - msg.credentials = entry->turn->credentials; - msg.lifetime = TURN_LIFETIME / 1000; // seconds - - // Include allocation attributes in Allocate request only - if (method == STUN_METHOD_ALLOCATE) { - msg.requested_transport = true; - } - - const char *password = *msg.credentials.nonce != '\0' ? entry->turn->password : NULL; - - char buffer[BUFFER_SIZE]; - int size = stun_write(buffer, BUFFER_SIZE, &msg, password); - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - if (agent_direct_send(agent, &entry->record, buffer, size, 0) < 0) { - JLOG_WARN("STUN message send failed"); - return -1; - } - return 0; -} - -int agent_process_turn_create_permission(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry) { - (void)(agent); - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_WARN("Received TURN CreatePermission message for a non-relay entry, ignoring"); - return -1; - } - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - - switch (msg->msg_class) { - case STUN_CLASS_RESP_SUCCESS: { - JLOG_DEBUG("Received TURN CreatePermission success response"); - if (!turn_set_permission(&entry->turn->map, msg->transaction_id, NULL, - PERMISSION_LIFETIME / 2)) - JLOG_WARN("Transaction ID from TURN CreatePermission response does not match"); - break; - } - case STUN_CLASS_RESP_ERROR: { - if (msg->error_code == 438) { // Stale Nonce - JLOG_DEBUG("Got TURN CreatePermission Stale Nonce response"); - if (*msg->credentials.realm == '\0' || *msg->credentials.nonce == '\0') { - JLOG_ERROR("Expected realm and nonce in TURN error response"); - return -1; - } - - stun_process_credentials(&msg->credentials, &entry->turn->credentials); - - // Resend - addr_record_t record; - if (turn_retrieve_transaction_id(&entry->turn->map, msg->transaction_id, &record)) - agent_send_turn_create_permission_request(agent, entry, &record, 0); - - } else if (msg->error_code != STUN_ERROR_INTERNAL_VALIDATION_FAILED) { - JLOG_WARN("Got TURN CreatePermission error response, code=%u", - (unsigned int)msg->error_code); - } - break; - } - default: { - JLOG_WARN("Got unexpected TURN CreatePermission message, class=%u", - (unsigned int)msg->msg_class); - return -1; - } - } - return 0; -} - -int agent_send_turn_create_permission_request(juice_agent_t *agent, agent_stun_entry_t *entry, - const addr_record_t *record, int ds) { - if (JLOG_DEBUG_ENABLED) { - char record_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(record, record_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Sending TURN CreatePermission request for %s", record_str); - } - - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_ERROR("Attempted to send a TURN CreatePermission request for a non-relay entry"); - return -1; - } - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - const stun_credentials_t *credentials = &entry->turn->credentials; - - if (*credentials->realm == '\0' || *credentials->nonce == '\0') { - JLOG_ERROR("Missing realm and nonce to send TURN CreatePermission request"); - return -1; - } - - stun_message_t msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_class = STUN_CLASS_REQUEST; - msg.msg_method = STUN_METHOD_CREATE_PERMISSION; - if (!turn_set_random_permission_transaction_id(&entry->turn->map, record, msg.transaction_id)) - return -1; - - msg.credentials = entry->turn->credentials; - msg.peer = *record; - - char buffer[BUFFER_SIZE]; - int size = stun_write(buffer, BUFFER_SIZE, &msg, entry->turn->password); - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - if (agent_direct_send(agent, &entry->record, buffer, size, ds) < 0) { - JLOG_WARN("STUN message send failed"); - return -1; - } - return 0; -} - -int agent_process_turn_channel_bind(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry) { - (void)agent; - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_WARN("Received TURN ChannelBind message for a non-relay entry, ignoring"); - return -1; - } - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - - switch (msg->msg_class) { - case STUN_CLASS_RESP_SUCCESS: { - JLOG_DEBUG("Received TURN ChannelBind success response"); - if (!turn_bind_current_channel(&entry->turn->map, msg->transaction_id, NULL, - BIND_LIFETIME / 2)) - JLOG_WARN("Transaction ID from TURN ChannelBind response does not match"); - break; - } - case STUN_CLASS_RESP_ERROR: { - if (msg->error_code == 438) { // Stale Nonce - JLOG_DEBUG("Got TURN ChannelBind Stale Nonce response"); - if (*msg->credentials.realm == '\0' || *msg->credentials.nonce == '\0') { - JLOG_ERROR("Expected realm and nonce in TURN error response"); - return -1; - } - - stun_process_credentials(&msg->credentials, &entry->turn->credentials); - - // Resend - addr_record_t record; - if (turn_retrieve_transaction_id(&entry->turn->map, msg->transaction_id, &record)) - agent_send_turn_channel_bind_request(agent, entry, &record, 0, NULL); - - } else if (msg->error_code != STUN_ERROR_INTERNAL_VALIDATION_FAILED) { - JLOG_WARN("Got TURN ChannelBind error response, code=%u", - (unsigned int)msg->error_code); - } - break; - } - default: { - JLOG_WARN("Got STUN unexpected ChannelBind message, class=%u", - (unsigned int)msg->msg_class); - return -1; - } - } - return 0; -} - -int agent_send_turn_channel_bind_request(juice_agent_t *agent, agent_stun_entry_t *entry, - const addr_record_t *record, int ds, - uint16_t *out_channel) { - if (JLOG_DEBUG_ENABLED) { - char record_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(record, record_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Sending TURN ChannelBind request for %s", record_str); - } - - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_ERROR("Attempted to send a TURN ChannelBind request for a non-relay entry"); - return -1; - } - if (!entry->turn) { - JLOG_ERROR("Missing TURN state on relay entry"); - return -1; - } - const stun_credentials_t *credentials = &entry->turn->credentials; - const char *password = entry->turn->password; - - if (*credentials->realm == '\0' || *credentials->nonce == '\0') { - JLOG_ERROR("Missing realm and nonce to send TURN ChannelBind request"); - return -1; - } - - uint16_t channel; - if (!turn_get_channel(&entry->turn->map, record, &channel)) - if (!turn_bind_random_channel(&entry->turn->map, record, &channel, 0)) - return -1; - - stun_message_t msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_class = STUN_CLASS_REQUEST; - msg.msg_method = STUN_METHOD_CHANNEL_BIND; - if (!turn_set_random_channel_transaction_id(&entry->turn->map, record, msg.transaction_id)) - return -1; - - msg.credentials = entry->turn->credentials; - msg.channel_number = channel; - msg.peer = *record; - - if (out_channel) - *out_channel = channel; - - char buffer[BUFFER_SIZE]; - int size = stun_write(buffer, BUFFER_SIZE, &msg, password); - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - if (agent_direct_send(agent, &entry->record, buffer, size, ds) < 0) { - JLOG_WARN("STUN message send failed"); - return -1; - } - return 0; -} - -int agent_process_turn_data(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry) { - if (entry->type != AGENT_STUN_ENTRY_TYPE_RELAY) { - JLOG_WARN("Received TURN Data message for a non-relay entry, ignoring"); - return -1; - } - if (msg->msg_class != STUN_CLASS_INDICATION) { - JLOG_WARN("Received non-indication TURN Data message, ignoring"); - return -1; - } - - JLOG_DEBUG("Received TURN Data indication"); - if (!msg->data) { - JLOG_WARN("Missing data in TURN Data indication"); - return -1; - } - if (!msg->peer.len) { - JLOG_WARN("Missing peer address in TURN Data indication"); - return -1; - } - return agent_input(agent, (char *)msg->data, msg->data_size, &msg->peer, &entry->relayed); -} - -int agent_process_channel_data(juice_agent_t *agent, agent_stun_entry_t *entry, char *buf, - size_t len) { - if (len < sizeof(struct channel_data_header)) { - JLOG_WARN("ChannelData is too short"); - return -1; - } - - const struct channel_data_header *header = (const struct channel_data_header *)buf; - buf += sizeof(struct channel_data_header); - len -= sizeof(struct channel_data_header); - uint16_t channel = ntohs(header->channel_number); - uint16_t length = ntohs(header->length); - JLOG_VERBOSE("Received ChannelData, channel=0x%hX, length=%hu", channel, length); - if (length > len) { - JLOG_WARN("ChannelData has invalid length"); - return -1; - } - - addr_record_t src; - if (!turn_find_channel(&entry->turn->map, channel, &src)) { - JLOG_WARN("Channel not found"); - return -1; - } - - return agent_input(agent, buf, length, &src, &entry->relayed); -} - -int agent_add_local_relayed_candidate(juice_agent_t *agent, const addr_record_t *record) { - if (ice_find_candidate_from_addr(&agent->local, record, ICE_CANDIDATE_TYPE_RELAYED)) { - JLOG_VERBOSE("The relayed local candidate already exists"); - return 0; - } - ice_candidate_t candidate; - if (ice_create_local_candidate(ICE_CANDIDATE_TYPE_RELAYED, 1, agent->local.candidates_count, - record, &candidate)) { - JLOG_ERROR("Failed to create relayed candidate"); - return -1; - } - if (ice_add_candidate(&candidate, &agent->local)) { - JLOG_ERROR("Failed to add candidate to local description"); - return -1; - } - - char buffer[BUFFER_SIZE]; - if (ice_generate_candidate_sdp(&candidate, buffer, BUFFER_SIZE) < 0) { - JLOG_ERROR("Failed to generate SDP for local candidate"); - return -1; - } - JLOG_DEBUG("Gathered relayed candidate: %s", buffer); - - // Relayed candidates must be differenciated, so match them with already known remote candidates - ice_candidate_t *local = agent->local.candidates + agent->local.candidates_count - 1; - for (int i = 0; i < agent->remote.candidates_count; ++i) { - ice_candidate_t *remote = agent->remote.candidates + i; - if (local->resolved.addr.ss_family == remote->resolved.addr.ss_family) - agent_add_candidate_pair(agent, local, remote); - } - - if (agent->config.cb_candidate) - agent->config.cb_candidate(agent, buffer, agent->config.user_ptr); - - return 0; -} - -int agent_add_local_reflexive_candidate(juice_agent_t *agent, ice_candidate_type_t type, - const addr_record_t *record) { - if (type != ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE && type != ICE_CANDIDATE_TYPE_PEER_REFLEXIVE) { - JLOG_ERROR("Invalid type for local reflexive candidate"); - return -1; - } - int family = record->addr.ss_family; - if (ice_find_candidate_from_addr(&agent->local, record, - family == AF_INET6 ? ICE_CANDIDATE_TYPE_UNKNOWN : type)) { - JLOG_VERBOSE("A local candidate exists for the mapped address"); - return 0; - } - ice_candidate_t candidate; - if (ice_create_local_candidate(type, 1, agent->local.candidates_count, record, &candidate)) { - JLOG_ERROR("Failed to create reflexive candidate"); - return -1; - } - if (candidate.type == ICE_CANDIDATE_TYPE_PEER_REFLEXIVE && - ice_candidates_count(&agent->local, ICE_CANDIDATE_TYPE_PEER_REFLEXIVE) >= - MAX_PEER_REFLEXIVE_CANDIDATES_COUNT) { - JLOG_INFO( - "Local description has the maximum number of peer reflexive candidates, ignoring"); - return 0; - } - if (ice_add_candidate(&candidate, &agent->local)) { - JLOG_ERROR("Failed to add candidate to local description"); - return -1; - } - - char buffer[BUFFER_SIZE]; - if (ice_generate_candidate_sdp(&candidate, buffer, BUFFER_SIZE) < 0) { - JLOG_ERROR("Failed to generate SDP for local candidate"); - return -1; - } - JLOG_DEBUG("Gathered reflexive candidate: %s", buffer); - - if (type != ICE_CANDIDATE_TYPE_PEER_REFLEXIVE && agent->config.cb_candidate) - agent->config.cb_candidate(agent, buffer, agent->config.user_ptr); - - return 0; -} - -int agent_add_remote_reflexive_candidate(juice_agent_t *agent, ice_candidate_type_t type, - uint32_t priority, const addr_record_t *record) { - if (type != ICE_CANDIDATE_TYPE_PEER_REFLEXIVE) { - JLOG_ERROR("Invalid type for remote reflexive candidate"); - return -1; - } - if (ice_find_candidate_from_addr(&agent->remote, record, ICE_CANDIDATE_TYPE_UNKNOWN)) { - JLOG_VERBOSE("A remote candidate exists for the remote address"); - return 0; - } - ice_candidate_t candidate; - if (ice_create_local_candidate(type, 1, agent->local.candidates_count, record, &candidate)) { - JLOG_ERROR("Failed to create reflexive candidate"); - return -1; - } - if (ice_candidates_count(&agent->remote, ICE_CANDIDATE_TYPE_PEER_REFLEXIVE) >= - MAX_PEER_REFLEXIVE_CANDIDATES_COUNT) { - JLOG_INFO( - "Remote description has the maximum number of peer reflexive candidates, ignoring"); - return 0; - } - if (ice_add_candidate(&candidate, &agent->remote)) { - JLOG_ERROR("Failed to add candidate to remote description"); - return -1; - } - - JLOG_DEBUG("Obtained a new remote reflexive candidate, priority=%lu", (unsigned long)priority); - - ice_candidate_t *remote = agent->remote.candidates + agent->remote.candidates_count - 1; - remote->priority = priority; - - return agent_add_candidate_pairs_for_remote(agent, remote); -} - -int agent_add_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, // local may be NULL - ice_candidate_t *remote) { - ice_candidate_pair_t pair; - bool is_controlling = agent->mode == AGENT_MODE_CONTROLLING; - if (ice_create_candidate_pair(local, remote, is_controlling, &pair)) { - JLOG_ERROR("Failed to create candidate pair"); - return -1; - } - - if (agent->candidate_pairs_count >= MAX_CANDIDATE_PAIRS_COUNT) { - JLOG_WARN("Session already has the maximum number of candidate pairs"); - return -1; - } - - JLOG_VERBOSE("Adding new candidate pair, priority=%" PRIu64, pair.priority); - - // Add pair - ice_candidate_pair_t *pos = agent->candidate_pairs + agent->candidate_pairs_count; - *pos = pair; - ++agent->candidate_pairs_count; - - agent_update_ordered_pairs(agent); - - if (agent->entries_count == MAX_STUN_ENTRIES_COUNT) { - JLOG_WARN("No free STUN entry left for candidate pair checking"); - return -1; - } - - agent_stun_entry_t *relay_entry = NULL; - if (local && local->type == ICE_CANDIDATE_TYPE_RELAYED) { - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *other_entry = agent->entries + i; - if (other_entry->type == AGENT_STUN_ENTRY_TYPE_RELAY && - addr_record_is_equal(&other_entry->relayed, &local->resolved, true)) { - relay_entry = other_entry; - break; - } - } - if (!relay_entry) { - JLOG_ERROR("Relay entry not found"); - return -1; - } - } - - JLOG_VERBOSE("Registering STUN entry %d for candidate pair checking", agent->entries_count); - agent_stun_entry_t *entry = agent->entries + agent->entries_count; - entry->type = AGENT_STUN_ENTRY_TYPE_CHECK; - entry->state = AGENT_STUN_ENTRY_STATE_IDLE; - entry->mode = AGENT_MODE_UNKNOWN; - entry->pair = pos; - entry->record = pos->remote->resolved; - entry->relay_entry = relay_entry; - juice_random(entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - ++agent->entries_count; - - if (remote->type == ICE_CANDIDATE_TYPE_HOST) - agent_translate_host_candidate_entry(agent, entry); - - if (agent->mode == AGENT_MODE_CONTROLLING) { - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - ice_candidate_pair_t *ordered_pair = agent->ordered_pairs[i]; - if (ordered_pair == pos) { - JLOG_VERBOSE("Candidate pair has priority"); - break; - } - if (ordered_pair->state == ICE_CANDIDATE_PAIR_STATE_SUCCEEDED) { - // We found a succeeded pair with higher priority, ignore this one - JLOG_VERBOSE("Candidate pair doesn't have priority, keeping it frozen"); - return 0; - } - } - } - - // There is only one component, therefore we can unfreeze if no pair is nominated - if (*agent->remote.ice_ufrag != '\0' && - (!agent->selected_pair || !agent->selected_pair->nominated)) { - JLOG_VERBOSE("Unfreezing the new candidate pair"); - agent_unfreeze_candidate_pair(agent, pos); - } - - return 0; -} - -int agent_add_candidate_pairs_for_remote(juice_agent_t *agent, ice_candidate_t *remote) { - // Here is the trick: local non-relayed candidates are undifferentiated for sending. - // Therefore, we don't need to match remote candidates with local ones. - if (agent_add_candidate_pair(agent, NULL, remote)) - return -1; - - // However, we need still to differenciate local relayed candidates - for (int i = 0; i < agent->local.candidates_count; ++i) { - ice_candidate_t *local = agent->local.candidates + i; - if (local->type == ICE_CANDIDATE_TYPE_RELAYED && - local->resolved.addr.ss_family == remote->resolved.addr.ss_family) - if (agent_add_candidate_pair(agent, local, remote)) - return -1; - } - - return 0; -} - -int agent_unfreeze_candidate_pair(juice_agent_t *agent, ice_candidate_pair_t *pair) { - if (pair->state != ICE_CANDIDATE_PAIR_STATE_FROZEN) - return 0; - - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->pair == pair) { - pair->state = ICE_CANDIDATE_PAIR_STATE_PENDING; - entry->state = AGENT_STUN_ENTRY_STATE_PENDING; - agent_arm_transmission(agent, entry, 0); // transmit now - return 0; - } - } - - JLOG_WARN("Unable to unfreeze the pair: no matching entry"); - return -1; -} - -void agent_arm_keepalive(juice_agent_t *agent, agent_stun_entry_t *entry) { - if (entry->state == AGENT_STUN_ENTRY_STATE_SUCCEEDED) - entry->state = AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE; - - if (entry->state != AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) - return; - - timediff_t period; - switch (entry->type) { - case AGENT_STUN_ENTRY_TYPE_RELAY: - period = agent->remote.candidates_count > 0 ? TURN_REFRESH_PERIOD : STUN_KEEPALIVE_PERIOD; - break; - case AGENT_STUN_ENTRY_TYPE_SERVER: - period = STUN_KEEPALIVE_PERIOD; - break; - default: -#if JUICE_DISABLE_CONSENT_FRESHNESS - period = STUN_KEEPALIVE_PERIOD; -#else - period = MIN_CONSENT_CHECK_PERIOD + - juice_rand32() % (MAX_CONSENT_CHECK_PERIOD - MIN_CONSENT_CHECK_PERIOD + 1); -#endif - break; - } - - agent_arm_transmission(agent, entry, period); -} - -void agent_arm_transmission(juice_agent_t *agent, agent_stun_entry_t *entry, timediff_t delay) { - if (entry->state != AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE) - entry->state = AGENT_STUN_ENTRY_STATE_PENDING; - - // Arm transmission - entry->next_transmission = current_timestamp() + delay; - - if (entry->state == AGENT_STUN_ENTRY_STATE_PENDING) { - entry->retransmission_timeout = MIN_STUN_RETRANSMISSION_TIMEOUT; - entry->retransmissions = entry->type == AGENT_STUN_ENTRY_TYPE_CHECK - ? MAX_STUN_CHECK_RETRANSMISSION_COUNT - : MAX_STUN_SERVER_RETRANSMISSION_COUNT; - } - - // Find a time slot - agent_stun_entry_t *other = agent->entries; - while (other != agent->entries + agent->entries_count) { - if (other != entry) { - timestamp_t other_transmission = other->next_transmission; - timediff_t timediff = entry->next_transmission - other_transmission; - if (other_transmission && abs((int)timediff) < STUN_PACING_TIME) { - entry->next_transmission = other_transmission + STUN_PACING_TIME; - other = agent->entries; - continue; - } - } - ++other; - } -} - -void agent_update_pac_timer(juice_agent_t *agent) { - if (agent->pac_timestamp) - return; - - // RFC 8863: The ICE agent will start its timer once it believes ICE connectivity checks are - // starting. This occurs when the agent has sent the values needed to perform connectivity - // checks (e.g., the Username Fragment and Password [...]) and has received some indication that - // the remote side is ready to start connectivity checks, typically via receipt of the values - // mentioned above. - if (*agent->remote.ice_ufrag != '\0' && agent->gathering_done) { - JLOG_INFO("Connectivity timer started"); - agent->pac_timestamp = current_timestamp() + ICE_PAC_TIMEOUT; - } -} - -void agent_update_gathering_done(juice_agent_t *agent) { - JLOG_VERBOSE("Updating gathering status"); - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->type != AGENT_STUN_ENTRY_TYPE_CHECK && - entry->state == AGENT_STUN_ENTRY_STATE_PENDING) { - JLOG_VERBOSE("STUN server or relay entry %d is still pending", i); - return; - } - } - if (!agent->gathering_done) { - JLOG_INFO("Candidate gathering done"); - agent->local.finished = true; - agent->gathering_done = true; - - agent_update_pac_timer(agent); - - if (agent->config.cb_gathering_done) - agent->config.cb_gathering_done(agent, agent->config.user_ptr); - } -} - -void agent_update_candidate_pairs(juice_agent_t *agent) { - bool is_controlling = agent->mode == AGENT_MODE_CONTROLLING; - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - ice_candidate_pair_t *pair = agent->candidate_pairs + i; - ice_update_candidate_pair(pair, is_controlling); - } - agent_update_ordered_pairs(agent); -} - -void agent_update_ordered_pairs(juice_agent_t *agent) { - JLOG_VERBOSE("Updating ordered candidate pairs"); - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - ice_candidate_pair_t **begin = agent->ordered_pairs; - ice_candidate_pair_t **end = begin + i; - ice_candidate_pair_t **prev = end; - uint64_t priority = agent->candidate_pairs[i].priority; - while (--prev >= begin && (*prev)->priority < priority) - *(prev + 1) = *prev; - - *(prev + 1) = agent->candidate_pairs + i; - } -} - -static inline bool pair_is_relayed(const ice_candidate_pair_t *pair) { - return pair->local && pair->local->type == ICE_CANDIDATE_TYPE_RELAYED; -} - -static inline bool entry_is_relayed(const agent_stun_entry_t *entry) { - return entry->pair && pair_is_relayed(entry->pair); -} - -agent_stun_entry_t *agent_find_entry_from_transaction_id(juice_agent_t *agent, - const uint8_t *transaction_id) { - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (memcmp(transaction_id, entry->transaction_id, STUN_TRANSACTION_ID_SIZE) == 0) { - JLOG_VERBOSE("STUN entry %d matching incoming transaction ID", i); - return entry; - } - if (entry->turn) { - if (turn_retrieve_transaction_id(&entry->turn->map, transaction_id, NULL)) { - JLOG_VERBOSE("STUN entry %d matching incoming transaction ID (TURN)", i); - return entry; - } - } - } - return NULL; -} - -agent_stun_entry_t *agent_find_entry_from_record(juice_agent_t *agent, const addr_record_t *record, - const addr_record_t *relayed) { - agent_stun_entry_t *selected_entry = atomic_load(&agent->selected_entry); - - if (selected_entry && selected_entry->pair && selected_entry->pair->nominated) { - // As an optimization, try to match the nominated entry first - if (relayed) { - if (entry_is_relayed(selected_entry) && - addr_record_is_equal(&selected_entry->pair->local->resolved, relayed, true) && - addr_record_is_equal(&selected_entry->record, record, true)) { - JLOG_DEBUG("STUN selected entry matching incoming relayed address"); - return selected_entry; - } - } else { - if (!entry_is_relayed(selected_entry) && - addr_record_is_equal(&selected_entry->record, record, true)) { - JLOG_DEBUG("STUN selected entry matching incoming address"); - return selected_entry; - } - } - } - - if (relayed) { - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry_is_relayed(entry) && - addr_record_is_equal(&entry->pair->local->resolved, relayed, true) && - addr_record_is_equal(&entry->record, record, true)) { - JLOG_DEBUG("STUN entry %d matching incoming relayed address", i); - return entry; - } - } - } else { - // Try to match pairs by priority first - ice_candidate_pair_t *matching_pair = NULL; - for (int i = 0; i < agent->candidate_pairs_count; ++i) { - ice_candidate_pair_t *pair = agent->ordered_pairs[i]; - if (!pair_is_relayed(pair) && - addr_record_is_equal(&pair->remote->resolved, record, true)) { - matching_pair = pair; - break; - } - } - - if (matching_pair) { - // Just find the corresponding entry - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (entry->pair == matching_pair) { - JLOG_DEBUG("STUN entry %d pair matching incoming address", i); - return entry; - } - } - } - - // Try to match entries directly - for (int i = 0; i < agent->entries_count; ++i) { - agent_stun_entry_t *entry = agent->entries + i; - if (!entry_is_relayed(entry) && addr_record_is_equal(&entry->record, record, true)) { - JLOG_DEBUG("STUN entry %d matching incoming address", i); - return entry; - } - } - } - return NULL; -} - -void agent_translate_host_candidate_entry(juice_agent_t *agent, agent_stun_entry_t *entry) { - if (!entry->pair || entry->pair->remote->type != ICE_CANDIDATE_TYPE_HOST) - return; - -#if JUICE_ENABLE_LOCAL_ADDRESS_TRANSLATION - for (int i = 0; i < agent->local.candidates_count; ++i) { - ice_candidate_t *candidate = agent->local.candidates + i; - if (candidate->type != ICE_CANDIDATE_TYPE_HOST) - continue; - - if (addr_record_is_equal(&candidate->resolved, &entry->record, false)) { - JLOG_DEBUG("Entry remote address matches local candidate, translating to localhost"); - struct sockaddr_storage *addr = &entry->record.addr; - switch (addr->ss_family) { - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; - memset(&sin6->sin6_addr, 0, 16); - *((uint8_t *)&sin6->sin6_addr + 15) = 0x01; - break; - } - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)addr; - const uint8_t localhost[4] = {127, 0, 0, 1}; - memcpy(&sin->sin_addr, localhost, 4); - break; - } - default: - // Ignore - break; - } - break; - } - } -#else - (void)agent; -#endif -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/agent.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/agent.h deleted file mode 100644 index 603814c5..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/agent.h +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_AGENT_H -#define JUICE_AGENT_H - -#include "addr.h" -#include "conn.h" -#include "ice.h" -#include "juice.h" -#include "stun.h" -#include "thread.h" -#include "timestamp.h" -#include "turn.h" - -#include -#include - -// RFC 8445: Agents MUST NOT use an RTO value smaller than 500 ms. -#define MIN_STUN_RETRANSMISSION_TIMEOUT 500 // msecs -#define LAST_STUN_RETRANSMISSION_TIMEOUT (MIN_STUN_RETRANSMISSION_TIMEOUT * 16) -#define MAX_STUN_CHECK_RETRANSMISSION_COUNT 6 // exponential backoff, total 39500ms -#define MAX_STUN_SERVER_RETRANSMISSION_COUNT 5 // total 23500ms - -// RFC 8445: ICE agents SHOULD use a default Ta value, 50 ms, but MAY use another value based on the -// characteristics of the associated data. -#define STUN_PACING_TIME 50 // msecs - -// RFC 8445: Agents SHOULD use a Tr value of 15 seconds. Agents MAY use a bigger value but MUST NOT -// use a value smaller than 15 seconds. -#define STUN_KEEPALIVE_PERIOD 15000 // msecs - -// ICE Patiently Awaiting Connectivity timer -// RFC 8863: The RECOMMENDED duration for the PAC timer is equal to the agent's connectivity check -// transaction timeout, including all retransmissions. -#define ICE_PAC_TIMEOUT 39500 // msecs - -// Consent freshness -// RFC 7675: Consent expires after 30 seconds. -#define CONSENT_TIMEOUT 30000 // msecs - -// RFC 7675: To prevent synchronization of consent checks, each interval MUST be randomized from -// between 0.8 and 1.2 times the basic period. Implementations SHOULD set a default interval of 5 -// seconds, resulting in a period between checks of 4 to 6 seconds. Implementations MUST NOT set the -// period between checks to less than 4 seconds. -#define MIN_CONSENT_CHECK_PERIOD 4000 // msecs -#define MAX_CONSENT_CHECK_PERIOD 6000 // msecs - -// Nomination timeout for the controlling agent to settle for the selected pair -#define NOMINATION_TIMEOUT 2000 - -// TURN refresh period -#define TURN_LIFETIME 600000 // msecs (10 min) -#define TURN_REFRESH_PERIOD (TURN_LIFETIME - 60000) // msecs (lifetime - 1 min) - -// Max STUN and TURN server entries -#define MAX_SERVER_ENTRIES_COUNT 2 // max STUN server entries -#define MAX_RELAY_ENTRIES_COUNT 2 // max TURN server entries - -// Max TURN redirections for ALTERNATE-SERVER mechanism -#define MAX_TURN_REDIRECTIONS 1 - -// Compute max candidates and entries count -#define MAX_STUN_SERVER_RECORDS_COUNT MAX_SERVER_ENTRIES_COUNT -#define MAX_HOST_CANDIDATES_COUNT ((ICE_MAX_CANDIDATES_COUNT - MAX_STUN_SERVER_RECORDS_COUNT) / 2) -#define MAX_PEER_REFLEXIVE_CANDIDATES_COUNT MAX_HOST_CANDIDATES_COUNT -#define MAX_CANDIDATE_PAIRS_COUNT (ICE_MAX_CANDIDATES_COUNT * (1 + MAX_RELAY_ENTRIES_COUNT)) -#define MAX_STUN_ENTRIES_COUNT (MAX_CANDIDATE_PAIRS_COUNT + MAX_STUN_SERVER_RECORDS_COUNT) - -#define AGENT_TURN_MAP_SIZE ICE_MAX_CANDIDATES_COUNT - -typedef enum agent_mode { - AGENT_MODE_UNKNOWN, - AGENT_MODE_CONTROLLED, - AGENT_MODE_CONTROLLING -} agent_mode_t; - -typedef enum agent_stun_entry_type { - AGENT_STUN_ENTRY_TYPE_EMPTY, - AGENT_STUN_ENTRY_TYPE_SERVER, - AGENT_STUN_ENTRY_TYPE_RELAY, - AGENT_STUN_ENTRY_TYPE_CHECK -} agent_stun_entry_type_t; - -typedef enum agent_stun_entry_state { - AGENT_STUN_ENTRY_STATE_PENDING, - AGENT_STUN_ENTRY_STATE_CANCELLED, - AGENT_STUN_ENTRY_STATE_FAILED, - AGENT_STUN_ENTRY_STATE_SUCCEEDED, - AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE, - AGENT_STUN_ENTRY_STATE_IDLE -} agent_stun_entry_state_t; - -typedef struct agent_turn_state { - turn_map_t map; - stun_credentials_t credentials; - const char *password; -} agent_turn_state_t; - -typedef struct agent_stun_entry { - agent_stun_entry_type_t type; - agent_stun_entry_state_t state; - agent_mode_t mode; - ice_candidate_pair_t *pair; - addr_record_t record; - addr_record_t relayed; - uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE]; - timestamp_t next_transmission; - timediff_t retransmission_timeout; - int retransmissions; - - // TURN - agent_turn_state_t *turn; - unsigned int turn_redirections; - struct agent_stun_entry *relay_entry; - -} agent_stun_entry_t; - -struct juice_agent { - juice_config_t config; - juice_state_t state; - agent_mode_t mode; - - ice_description_t local; - ice_description_t remote; - - ice_candidate_pair_t candidate_pairs[MAX_CANDIDATE_PAIRS_COUNT]; - ice_candidate_pair_t *ordered_pairs[MAX_CANDIDATE_PAIRS_COUNT]; - ice_candidate_pair_t *selected_pair; - int candidate_pairs_count; - - agent_stun_entry_t entries[MAX_STUN_ENTRIES_COUNT]; - int entries_count; - atomic_ptr(agent_stun_entry_t) selected_entry; - - uint64_t ice_tiebreaker; - timestamp_t pac_timestamp; // Patiently Awaiting Connectivity timer - timestamp_t nomination_timestamp; - bool gathering_done; - - int conn_index; - void *conn_impl; - - thread_t resolver_thread; - bool resolver_thread_started; -}; - -juice_agent_t *agent_create(const juice_config_t *config); -void agent_destroy(juice_agent_t *agent); - -int agent_gather_candidates(juice_agent_t *agent); -int agent_resolve_servers(juice_agent_t *agent); -int agent_get_local_description(juice_agent_t *agent, char *buffer, size_t size); -int agent_set_remote_description(juice_agent_t *agent, const char *sdp); -int agent_add_remote_candidate(juice_agent_t *agent, const char *sdp); -int agent_set_remote_gathering_done(juice_agent_t *agent); -int agent_send(juice_agent_t *agent, const char *data, size_t size, int ds); -int agent_direct_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds); -int agent_relay_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr_record_t *dst, - const char *data, size_t size, int ds); -int agent_channel_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr_record_t *dst, - const char *data, size_t size, int ds); -juice_state_t agent_get_state(juice_agent_t *agent); -int agent_get_selected_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, - ice_candidate_t *remote); - -int agent_conn_recv(juice_agent_t *agent, char *buf, size_t len, const addr_record_t *src); -int agent_conn_update(juice_agent_t *agent, timestamp_t *next_timestamp); -int agent_conn_fail(juice_agent_t *agent); - -int agent_input(juice_agent_t *agent, char *buf, size_t len, const addr_record_t *src, - const addr_record_t *relayed); // relayed may be NULL -int agent_bookkeeping(juice_agent_t *agent, timestamp_t *next_timestamp); -void agent_change_state(juice_agent_t *agent, juice_state_t state); -int agent_verify_stun_binding(juice_agent_t *agent, void *buf, size_t size, - const stun_message_t *msg); -int agent_verify_credentials(juice_agent_t *agent, const agent_stun_entry_t *entry, void *buf, - size_t size, stun_message_t *msg); -int agent_dispatch_stun(juice_agent_t *agent, void *buf, size_t size, stun_message_t *msg, - const addr_record_t *src, - const addr_record_t *relayed); // relayed may be NULL -int agent_process_stun_binding(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry, const addr_record_t *src, - const addr_record_t *relayed); // relayed may be NULL -int agent_send_stun_binding(juice_agent_t *agent, agent_stun_entry_t *entry, stun_class_t msg_class, - unsigned int error_code, const uint8_t *transaction_id, - const addr_record_t *mapped); -int agent_process_turn_allocate(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry); -int agent_send_turn_allocate_request(juice_agent_t *agent, const agent_stun_entry_t *entry, - stun_method_t method); -int agent_process_turn_create_permission(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry); -int agent_send_turn_create_permission_request(juice_agent_t *agent, agent_stun_entry_t *entry, - const addr_record_t *record, int ds); -int agent_process_turn_channel_bind(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry); -int agent_send_turn_channel_bind_request(juice_agent_t *agent, agent_stun_entry_t *entry, - const addr_record_t *record, int ds, - uint16_t *out_channel); // out_channel may be NULL -int agent_process_turn_data(juice_agent_t *agent, const stun_message_t *msg, - agent_stun_entry_t *entry); -int agent_process_channel_data(juice_agent_t *agent, agent_stun_entry_t *entry, char *buf, - size_t len); - -int agent_add_local_relayed_candidate(juice_agent_t *agent, const addr_record_t *record); -int agent_add_local_reflexive_candidate(juice_agent_t *agent, ice_candidate_type_t type, - const addr_record_t *record); -int agent_add_remote_reflexive_candidate(juice_agent_t *agent, ice_candidate_type_t type, - uint32_t priority, const addr_record_t *record); -int agent_add_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, - ice_candidate_t *remote); // local may be NULL -int agent_add_candidate_pairs_for_remote(juice_agent_t *agent, ice_candidate_t *remote); -int agent_unfreeze_candidate_pair(juice_agent_t *agent, ice_candidate_pair_t *pair); - -void agent_arm_keepalive(juice_agent_t *agent, agent_stun_entry_t *entry); -void agent_arm_transmission(juice_agent_t *agent, agent_stun_entry_t *entry, timediff_t delay); -void agent_update_pac_timer(juice_agent_t *agent); -void agent_update_gathering_done(juice_agent_t *agent); -void agent_update_candidate_pairs(juice_agent_t *agent); -void agent_update_ordered_pairs(juice_agent_t *agent); - -agent_stun_entry_t *agent_find_entry_from_transaction_id(juice_agent_t *agent, - const uint8_t *transaction_id); -agent_stun_entry_t * -agent_find_entry_from_record(juice_agent_t *agent, const addr_record_t *record, - const addr_record_t *relayed); // relayed may be NULL -void agent_translate_host_candidate_entry(juice_agent_t *agent, agent_stun_entry_t *entry); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/base64.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/base64.c deleted file mode 100644 index 206cc6a0..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/base64.c +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Copyright (c) 2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "base64.h" - -#include -#include - -int juice_base64_encode(const void *data, size_t size, char *out, size_t out_size) { - static const char tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - if (out_size < 4 * ((size + 2) / 3) + 1) - return -1; - - const uint8_t *in = (const uint8_t *)data; - char *w = out; - while (size >= 3) { - *w++ = tab[*in >> 2]; - *w++ = tab[((*in & 0x03) << 4) | (*(in + 1) >> 4)]; - *w++ = tab[((*(in + 1) & 0x0F) << 2) | (*(in + 2) >> 6)]; - *w++ = tab[*(in + 2) & 0x3F]; - in += 3; - size -= 3; - } - - if (size) { - *w++ = tab[*in >> 2]; - if (size == 1) { - *w++ = tab[(*in & 0x03) << 4]; - *w++ = '='; - } else { // size == 2 - *w++ = tab[((*in & 0x03) << 4) | (*(in + 1) >> 4)]; - *w++ = tab[(*(in + 1) & 0x0F) << 2]; - } - *w++ = '='; - } - - *w = '\0'; - return (int)(w - out); -} - -int juice_base64_decode(const char *str, void *out, size_t out_size) { - const uint8_t *in = (const uint8_t *)str; - uint8_t *w = (uint8_t *)out; - while (*in && *in != '=') { - uint8_t tab[4] = {0, 0, 0, 0}; - size_t size = 0; - while (*in && size < 4) { - uint8_t c = *in++; - if (isspace(c)) - continue; - if (c == '=') - break; - - if ('A' <= c && c <= 'Z') - tab[size++] = c - 'A'; - else if ('a' <= c && c <= 'z') - tab[size++] = c + 26 - 'a'; - else if ('0' <= c && c <= '9') - tab[size++] = c + 52 - '0'; - else if (c == '+' || c == '-') - tab[size++] = 62; - else if (c == '/' || c == '_') - tab[size++] = 63; - else - return -1; // Invalid character - } - - if (size > 0) { - if (out_size < size - 1) - return -1; - - out_size -= size - 1; - - *w++ = (tab[0] << 2) | (tab[1] >> 4); - if (size > 1) { - *w++ = (tab[1] << 4) | (tab[2] >> 2); - if (size > 2) - *w++ = (tab[2] << 6) | tab[3]; - } - } - } - - return (int)(w - (uint8_t *)out); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/base64.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/base64.h deleted file mode 100644 index 21ebf208..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/base64.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_BASE64_H -#define JUICE_BASE64_H - -#include "juice.h" - -#include -#include - -// RFC4648-compliant base64 encoder and decoder -JUICE_EXPORT int juice_base64_encode(const void *data, size_t size, char *out, size_t out_size); -JUICE_EXPORT int juice_base64_decode(const char *str, void *out, size_t out_size); - -#define BASE64_ENCODE(data, size, out, out_size) juice_base64_encode(data, size, out, out_size) -#define BASE64_DECODE(str, out, out_size) juice_base64_decode(str, out, out_size) - -#endif // JUICE_BASE64_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn.c deleted file mode 100644 index 4d7893a0..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn.c +++ /dev/null @@ -1,249 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "conn.h" -#include "agent.h" -#include "conn_mux.h" -#include "conn_poll.h" -#include "conn_thread.h" -#include "log.h" - -#include -#include - -#define INITIAL_REGISTRY_SIZE 16 - -typedef struct conn_mode_entry { - int (*registry_init_func)(conn_registry_t *registry, udp_socket_config_t *config); - void (*registry_cleanup_func)(conn_registry_t *registry); - - int (*init_func)(juice_agent_t *agent, struct conn_registry *registry, - udp_socket_config_t *config); - void (*cleanup_func)(juice_agent_t *agent); - void (*lock_func)(juice_agent_t *agent); - void (*unlock_func)(juice_agent_t *agent); - int (*interrupt_func)(juice_agent_t *agent); - int (*send_func)(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds); - int (*get_addrs_func)(juice_agent_t *agent, addr_record_t *records, size_t size); - - mutex_t mutex; - conn_registry_t *registry; -} conn_mode_entry_t; - -#define MODE_ENTRIES_SIZE 3 - -static conn_mode_entry_t mode_entries[MODE_ENTRIES_SIZE] = { - {conn_poll_registry_init, conn_poll_registry_cleanup, conn_poll_init, conn_poll_cleanup, - conn_poll_lock, conn_poll_unlock, conn_poll_interrupt, conn_poll_send, conn_poll_get_addrs, - MUTEX_INITIALIZER, NULL}, - {conn_mux_registry_init, conn_mux_registry_cleanup, conn_mux_init, conn_mux_cleanup, - conn_mux_lock, conn_mux_unlock, conn_mux_interrupt, conn_mux_send, conn_mux_get_addrs, - MUTEX_INITIALIZER, NULL}, - {NULL, NULL, conn_thread_init, conn_thread_cleanup, conn_thread_lock, conn_thread_unlock, - conn_thread_interrupt, conn_thread_send, conn_thread_get_addrs, MUTEX_INITIALIZER, NULL}}; - -static conn_mode_entry_t *get_mode_entry(juice_agent_t *agent) { - juice_concurrency_mode_t mode = agent->config.concurrency_mode; - assert(mode >= 0 && mode < MODE_ENTRIES_SIZE); - return mode_entries + (int)mode; -} - -static conn_registry_t *acquire_registry(conn_mode_entry_t *entry, udp_socket_config_t *config) { - // entry must be locked - conn_registry_t *registry = entry->registry; - if (!registry) { - if (!entry->registry_init_func) - return NULL; - - JLOG_DEBUG("Creating connections registry"); - - registry = calloc(1, sizeof(conn_registry_t)); - if (!registry) { - JLOG_FATAL("Memory allocation failed for connections registry"); - return NULL; - } - - registry->agents = malloc(INITIAL_REGISTRY_SIZE * sizeof(juice_agent_t *)); - if (!registry->agents) { - JLOG_FATAL("Memory allocation failed for connections array"); - free(registry); - return NULL; - } - - registry->agents_size = INITIAL_REGISTRY_SIZE; - registry->agents_count = 0; - memset(registry->agents, 0, INITIAL_REGISTRY_SIZE * sizeof(juice_agent_t *)); - - mutex_init(®istry->mutex, MUTEX_RECURSIVE); - mutex_lock(®istry->mutex); - - if (entry->registry_init_func(registry, config)) { - mutex_unlock(®istry->mutex); - free(registry->agents); - free(registry); - return NULL; - } - - entry->registry = registry; - - } else { - mutex_lock(®istry->mutex); - } - - // registry is locked - return registry; -} - -static void release_registry(conn_mode_entry_t *entry) { - // entry must be locked - conn_registry_t *registry = entry->registry; - if (!registry) - return; - - // registry must be locked - - if (registry->agents_count == 0) { - JLOG_DEBUG("No connection left, destroying connections registry"); - mutex_unlock(®istry->mutex); - - if (entry->registry_cleanup_func) - entry->registry_cleanup_func(registry); - - free(registry->agents); - free(registry); - entry->registry = NULL; - return; - } - - JLOG_VERBOSE("%d connection%s left", registry->agents_count, - registry->agents_count >= 2 ? "s" : ""); - - mutex_unlock(®istry->mutex); -} - -int conn_create(juice_agent_t *agent, udp_socket_config_t *config) { - conn_mode_entry_t *entry = get_mode_entry(agent); - mutex_lock(&entry->mutex); - conn_registry_t *registry = acquire_registry(entry, config); // locks the registry if created - mutex_unlock(&entry->mutex); - - JLOG_DEBUG("Creating connection"); - if (registry) { - int i = 0; - while (i < registry->agents_size && registry->agents[i]) - ++i; - - if (i == registry->agents_size) { - int new_size = registry->agents_size * 2; - JLOG_DEBUG("Reallocating connections array, new_size=%d", new_size); - assert(new_size > 0); - - juice_agent_t **new_agents = - realloc(registry->agents, new_size * sizeof(juice_agent_t *)); - if (!new_agents) { - JLOG_FATAL("Memory reallocation failed for connections array"); - mutex_unlock(®istry->mutex); - return -1; - } - - registry->agents = new_agents; - registry->agents_size = new_size; - memset(registry->agents + i, 0, (new_size - i) * sizeof(juice_agent_t *)); - } - - if (get_mode_entry(agent)->init_func(agent, registry, config)) { - mutex_unlock(®istry->mutex); - return -1; - } - - registry->agents[i] = agent; - agent->conn_index = i; - ++registry->agents_count; - - mutex_unlock(®istry->mutex); - - } else { - if (get_mode_entry(agent)->init_func(agent, NULL, config)) { - mutex_unlock(®istry->mutex); - return -1; - } - - agent->conn_index = -1; - } - - conn_interrupt(agent); - return 0; -} - -void conn_destroy(juice_agent_t *agent) { - conn_mode_entry_t *entry = get_mode_entry(agent); - mutex_lock(&entry->mutex); - - JLOG_DEBUG("Destroying connection"); - conn_registry_t *registry = entry->registry; - if (registry) { - mutex_lock(®istry->mutex); - - entry->cleanup_func(agent); - - if (agent->conn_index >= 0) { - int i = agent->conn_index; - assert(registry->agents[i] == agent); - registry->agents[i] = NULL; - agent->conn_index = -1; - } - - assert(registry->agents_count > 0); - --registry->agents_count; - - release_registry(entry); // unlocks the registry - - } else { - entry->cleanup_func(agent); - assert(agent->conn_index < 0); - } - - mutex_unlock(&entry->mutex); -} - -void conn_lock(juice_agent_t *agent) { - if (!agent->conn_impl) - return; - - get_mode_entry(agent)->lock_func(agent); -} - -void conn_unlock(juice_agent_t *agent) { - if (!agent->conn_impl) - return; - - get_mode_entry(agent)->unlock_func(agent); -} - -int conn_interrupt(juice_agent_t *agent) { - if (!agent->conn_impl) - return -1; - - return get_mode_entry(agent)->interrupt_func(agent); -} - -int conn_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds) { - if (!agent->conn_impl) - return -1; - - return get_mode_entry(agent)->send_func(agent, dst, data, size, ds); -} - -int conn_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size) { - if (!agent->conn_impl) - return -1; - - return get_mode_entry(agent)->get_addrs_func(agent, records, size); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn.h deleted file mode 100644 index 4aec7d0c..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_CONN_H -#define JUICE_CONN_H - -#include "addr.h" -#include "juice.h" -#include "thread.h" -#include "timestamp.h" -#include "udp.h" - -#include -#include - -typedef struct juice_agent juice_agent_t; - -// Generic connection interface for agents -// This interface abstracts sockets and polling to allow for different concurrency modes. -// See include/juice/juice.h for implemented concurrency modes - -typedef struct conn_registry { - void *impl; - mutex_t mutex; - juice_agent_t **agents; - int agents_size; - int agents_count; -} conn_registry_t; - -int conn_create(juice_agent_t *agent, udp_socket_config_t *config); -void conn_destroy(juice_agent_t *agent); -void conn_lock(juice_agent_t *agent); -void conn_unlock(juice_agent_t *agent); -int conn_interrupt(juice_agent_t *agent); -int conn_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds); -int conn_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.c deleted file mode 100644 index a783b3f8..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.c +++ /dev/null @@ -1,541 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "conn_mux.h" -#include "agent.h" -#include "log.h" -#include "socket.h" -#include "stun.h" -#include "thread.h" -#include "udp.h" - -#include -#include - -#define BUFFER_SIZE 4096 -#define INITIAL_MAP_SIZE 16 - -typedef enum map_entry_type { - MAP_ENTRY_TYPE_EMPTY = 0, - MAP_ENTRY_TYPE_DELETED, - MAP_ENTRY_TYPE_FULL -} map_entry_type_t; - -typedef struct map_entry { - map_entry_type_t type; - juice_agent_t *agent; - addr_record_t record; -} map_entry_t; - -typedef struct registry_impl { - thread_t thread; - socket_t sock; - mutex_t send_mutex; - int send_ds; - map_entry_t *map; - int map_size; - int map_count; -} registry_impl_t; - -typedef struct conn_impl { - conn_registry_t *registry; - timestamp_t next_timestamp; - bool finished; -} conn_impl_t; - -static bool is_ready(const juice_agent_t *agent) { - if (!agent) - return false; - - conn_impl_t *conn_impl = agent->conn_impl; - if (!conn_impl || conn_impl->finished) - return false; - - return true; -} - -static map_entry_t *find_map_entry(registry_impl_t *impl, const addr_record_t *record, - bool allow_deleted); -static int insert_map_entry(registry_impl_t *impl, const addr_record_t *record, - juice_agent_t *agent); -static int remove_map_entries(registry_impl_t *impl, juice_agent_t *agent); -static int grow_map(registry_impl_t *impl, int new_size); - -static map_entry_t *find_map_entry(registry_impl_t *impl, const addr_record_t *record, - bool allow_deleted) { - unsigned long key = addr_record_hash(record, false) % impl->map_size; - unsigned long pos = key; - while (true) { - map_entry_t *entry = impl->map + pos; - if (entry->type == MAP_ENTRY_TYPE_EMPTY || - addr_record_is_equal(&entry->record, record, true)) // compare ports - break; - - if (entry->type == MAP_ENTRY_TYPE_DELETED && allow_deleted) - break; - - pos = (pos + 1) % impl->map_size; - if (pos == key) - return NULL; - } - return impl->map + pos; -} - -static int insert_map_entry(registry_impl_t *impl, const addr_record_t *record, - juice_agent_t *agent) { - - map_entry_t *entry = find_map_entry(impl, record, true); // allow deleted - if (!entry || (entry->type != MAP_ENTRY_TYPE_FULL && impl->map_count * 2 >= impl->map_size)) { - grow_map(impl, impl->map_size * 2); - return insert_map_entry(impl, record, agent); - } - - if (entry->type != MAP_ENTRY_TYPE_FULL) - ++impl->map_count; - - entry->type = MAP_ENTRY_TYPE_FULL; - entry->agent = agent; - entry->record = *record; - - JLOG_VERBOSE("Added map entry, count=%d", impl->map_count); - return 0; -} - -static int remove_map_entries(registry_impl_t *impl, juice_agent_t *agent) { - int count = 0; - for (int i = 0; i < impl->map_size; ++i) { - map_entry_t *entry = impl->map + i; - if (entry->type == MAP_ENTRY_TYPE_FULL && entry->agent == agent) { - entry->type = MAP_ENTRY_TYPE_DELETED; - entry->agent = NULL; - ++count; - } - } - - assert(impl->map_count >= count); - impl->map_count -= count; - - JLOG_VERBOSE("Removed %d map entries, count=%d", count, impl->map_count); - return 0; -} - -static int grow_map(registry_impl_t *impl, int new_size) { - if (new_size <= impl->map_size) - return 0; - - JLOG_DEBUG("Growing map, new_size=%d", new_size); - - map_entry_t *new_map = calloc(1, new_size * sizeof(map_entry_t)); - if (!new_map) { - JLOG_FATAL("Memory allocation failed for map"); - return -1; - } - - map_entry_t *old_map = impl->map; - int old_size = impl->map_size; - impl->map = new_map; - impl->map_size = new_size; - impl->map_count = 0; - - for (int i = 0; i < old_size; ++i) { - map_entry_t *old_entry = old_map + i; - if (old_entry->type == MAP_ENTRY_TYPE_FULL) - insert_map_entry(impl, &old_entry->record, old_entry->agent); - } - - free(old_map); - return 0; -} - -int conn_mux_prepare(conn_registry_t *registry, struct pollfd *pfd, timestamp_t *next_timestamp); -int conn_mux_process(conn_registry_t *registry, struct pollfd *pfd); -int conn_mux_recv(conn_registry_t *registry, char *buffer, size_t size, addr_record_t *src); -void conn_mux_fail(conn_registry_t *registry); -int conn_mux_run(conn_registry_t *registry); - -static thread_return_t THREAD_CALL conn_mux_thread_entry(void *arg) { - thread_set_name_self("juice mux"); - conn_registry_t *registry = (conn_registry_t *)arg; - conn_mux_run(registry); - return (thread_return_t)0; -} - -int conn_mux_registry_init(conn_registry_t *registry, udp_socket_config_t *config) { - (void)config; - registry_impl_t *registry_impl = calloc(1, sizeof(registry_impl_t)); - if (!registry_impl) { - JLOG_FATAL("Memory allocation failed for connections registry impl"); - return -1; - } - - registry_impl->map = calloc(INITIAL_MAP_SIZE, sizeof(map_entry_t)); - if (!registry_impl->map) { - JLOG_FATAL("Memory allocation failed for map"); - free(registry_impl); - return -1; - } - registry_impl->map_size = INITIAL_MAP_SIZE; - registry_impl->map_count = 0; - - registry_impl->sock = udp_create_socket(config); - if (registry_impl->sock == INVALID_SOCKET) { - JLOG_FATAL("UDP socket creation failed"); - free(registry_impl->map); - free(registry_impl); - return -1; - } - - mutex_init(®istry_impl->send_mutex, 0); - registry->impl = registry_impl; - - JLOG_DEBUG("Starting connections thread"); - int ret = thread_init(®istry_impl->thread, conn_mux_thread_entry, registry); - if (ret) { - JLOG_FATAL("Thread creation failed, error=%d", ret); - goto error; - } - - return 0; - -error: - mutex_destroy(®istry_impl->send_mutex); - closesocket(registry_impl->sock); - free(registry_impl->map); - free(registry_impl); - registry->impl = NULL; - return -1; -} - -void conn_mux_registry_cleanup(conn_registry_t *registry) { - registry_impl_t *registry_impl = registry->impl; - - JLOG_VERBOSE("Waiting for connections thread"); - thread_join(registry_impl->thread, NULL); - - mutex_destroy(®istry_impl->send_mutex); - closesocket(registry_impl->sock); - free(registry_impl->map); - free(registry->impl); - registry->impl = NULL; -} - -int conn_mux_prepare(conn_registry_t *registry, struct pollfd *pfd, timestamp_t *next_timestamp) { - timestamp_t now = current_timestamp(); - *next_timestamp = now + 60000; - - mutex_lock(®istry->mutex); - registry_impl_t *registry_impl = registry->impl; - pfd->fd = registry_impl->sock; - pfd->events = POLLIN; - - for (int i = 0; i < registry->agents_size; ++i) { - juice_agent_t *agent = registry->agents[i]; - if (is_ready(agent)) { - conn_impl_t *conn_impl = agent->conn_impl; - if (*next_timestamp > conn_impl->next_timestamp) - *next_timestamp = conn_impl->next_timestamp; - } - } - - int count = registry->agents_count; - mutex_unlock(®istry->mutex); - return count; -} - -static juice_agent_t *lookup_agent(conn_registry_t *registry, char *buf, size_t len, - const addr_record_t *src) { - JLOG_VERBOSE("Looking up agent from address"); - - registry_impl_t *registry_impl = registry->impl; - map_entry_t *entry = find_map_entry(registry_impl, src, false); - juice_agent_t *agent = entry && entry->type == MAP_ENTRY_TYPE_FULL ? entry->agent : NULL; - if (agent) { - JLOG_DEBUG("Found agent from address"); - return agent; - } - - if (!is_stun_datagram(buf, len)) { - JLOG_INFO("Got non-STUN message from unknown source address"); - return NULL; - } - - JLOG_VERBOSE("Looking up agent from STUN message content"); - - stun_message_t msg; - if (stun_read(buf, len, &msg) < 0) { - JLOG_ERROR("STUN message reading failed"); - return NULL; - } - - if (msg.msg_class == STUN_CLASS_REQUEST && msg.msg_method == STUN_METHOD_BINDING && - msg.has_integrity) { - // Binding request from peer - char username[STUN_MAX_USERNAME_LEN]; - strcpy(username, msg.credentials.username); - char *separator = strchr(username, ':'); - if (!separator) { - JLOG_WARN("STUN username invalid, username=\"%s\"", username); - return NULL; - } - *separator = '\0'; - const char *local_ufrag = username; - for (int i = 0; i < registry->agents_size; ++i) { - agent = registry->agents[i]; - if (is_ready(agent)) { - if (strcmp(local_ufrag, agent->local.ice_ufrag) == 0) { - JLOG_DEBUG("Found agent from ICE ufrag"); - insert_map_entry(registry_impl, src, agent); - return agent; - } - } - } - - } else { - if (!STUN_IS_RESPONSE(msg.msg_class)) { - JLOG_INFO("Got unexpected STUN message from unknown source address"); - return NULL; - } - - for (int i = 0; i < registry->agents_size; ++i) { - agent = registry->agents[i]; - if (is_ready(agent)) { - if (agent_find_entry_from_transaction_id(agent, msg.transaction_id)) { - JLOG_DEBUG("Found agent from transaction ID"); - return agent; - } - } - } - } - - return NULL; -} - -int conn_mux_process(conn_registry_t *registry, struct pollfd *pfd) { - mutex_lock(®istry->mutex); - - if (pfd->revents & POLLNVAL || pfd->revents & POLLERR) { - JLOG_ERROR("Error when polling socket"); - conn_mux_fail(registry); - mutex_unlock(®istry->mutex); - return -1; - } - - if (pfd->revents & POLLIN) { - char buffer[BUFFER_SIZE]; - addr_record_t src; - int ret; - while ((ret = conn_mux_recv(registry, buffer, BUFFER_SIZE, &src)) > 0) { - if (JLOG_DEBUG_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(&src, src_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Demultiplexing incoming datagram from %s", src_str); - } - - juice_agent_t *agent = lookup_agent(registry, buffer, (size_t)ret, &src); - if (!agent || !is_ready(agent)) { - JLOG_DEBUG("Agent not found for incoming datagram, dropping"); - continue; - } - - conn_impl_t *conn_impl = agent->conn_impl; - if (agent_conn_recv(agent, buffer, (size_t)ret, &src) != 0) { - JLOG_WARN("Agent receive failed"); - conn_impl->finished = true; - continue; - } - - conn_impl->next_timestamp = current_timestamp(); - } - - if (ret < 0) { - conn_mux_fail(registry); - mutex_unlock(®istry->mutex); - return -1; - } - } - - for (int i = 0; i < registry->agents_size; ++i) { - juice_agent_t *agent = registry->agents[i]; - if (is_ready(agent)) { - conn_impl_t *conn_impl = agent->conn_impl; - if (conn_impl->next_timestamp <= current_timestamp()) { - if (agent_conn_update(agent, &conn_impl->next_timestamp) != 0) { - JLOG_WARN("Agent update failed"); - conn_impl->finished = true; - continue; - } - } - } - } - - mutex_unlock(®istry->mutex); - return 0; -} - -int conn_mux_recv(conn_registry_t *registry, char *buffer, size_t size, addr_record_t *src) { - JLOG_VERBOSE("Receiving datagram"); - registry_impl_t *registry_impl = registry->impl; - int len; - while ((len = udp_recvfrom(registry_impl->sock, buffer, size, src)) == 0) { - // Empty datagram (used to interrupt) - } - - if (len < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) { - JLOG_VERBOSE("No more datagrams to receive"); - return 0; - } - JLOG_ERROR("recvfrom failed, errno=%d", sockerrno); - return -1; - } - - addr_unmap_inet6_v4mapped((struct sockaddr *)&src->addr, &src->len); - return len; // len > 0 -} - -void conn_mux_fail(conn_registry_t *registry) { - for (int i = 0; i < registry->agents_size; ++i) { - juice_agent_t *agent = registry->agents[i]; - if (is_ready(agent)) { - conn_impl_t *conn_impl = agent->conn_impl; - agent_conn_fail(agent); - conn_impl->finished = true; - } - } -} - -int conn_mux_run(conn_registry_t *registry) { - struct pollfd pfd[1]; - timestamp_t next_timestamp; - while (conn_mux_prepare(registry, pfd, &next_timestamp) > 0) { - timediff_t timediff = next_timestamp - current_timestamp(); - if (timediff < 0) - timediff = 0; - - JLOG_VERBOSE("Entering poll for %d ms", (int)timediff); - int ret = poll(pfd, 1, (int)timediff); - JLOG_VERBOSE("Leaving poll"); - if (ret < 0) { - if (sockerrno == SEINTR || sockerrno == SEAGAIN) { - JLOG_VERBOSE("poll interrupted"); - continue; - } else { - JLOG_FATAL("poll failed, errno=%d", sockerrno); - break; - } - } - - if (conn_mux_process(registry, pfd) < 0) - break; - } - - JLOG_DEBUG("Leaving connections thread"); - return 0; -} - -int conn_mux_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_config_t *config) { - (void)config; // ignored, only the config from the first connection is used - - conn_impl_t *conn_impl = calloc(1, sizeof(conn_impl_t)); - if (!conn_impl) { - JLOG_FATAL("Memory allocation failed for connection impl"); - return -1; - } - - conn_impl->registry = registry; - agent->conn_impl = conn_impl; - return 0; -} - -void conn_mux_cleanup(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - - mutex_lock(®istry->mutex); - registry_impl_t *registry_impl = registry->impl; - remove_map_entries(registry_impl, agent); - mutex_unlock(®istry->mutex); - - conn_mux_interrupt(agent); - - free(agent->conn_impl); - agent->conn_impl = NULL; -} - -void conn_mux_lock(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - mutex_lock(®istry->mutex); -} - -void conn_mux_unlock(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - mutex_unlock(®istry->mutex); -} - -int conn_mux_interrupt(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - - mutex_lock(®istry->mutex); - conn_impl->next_timestamp = current_timestamp(); - mutex_unlock(®istry->mutex); - - JLOG_VERBOSE("Interrupting connections thread"); - - registry_impl_t *registry_impl = registry->impl; - mutex_lock(®istry_impl->send_mutex); - if (udp_sendto_self(registry_impl->sock, NULL, 0) < 0) { - if (sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) { - JLOG_WARN("Failed to interrupt poll by triggering socket, errno=%d", sockerrno); - } - mutex_unlock(®istry_impl->send_mutex); - return -1; - } - mutex_unlock(®istry_impl->send_mutex); - return 0; -} - -int conn_mux_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds) { - conn_impl_t *conn_impl = agent->conn_impl; - registry_impl_t *registry_impl = conn_impl->registry->impl; - - mutex_lock(®istry_impl->send_mutex); - - if (registry_impl->send_ds >= 0 && registry_impl->send_ds != ds) { - JLOG_VERBOSE("Setting Differentiated Services field to 0x%X", ds); - if (udp_set_diffserv(registry_impl->sock, ds) == 0) - registry_impl->send_ds = ds; - else - registry_impl->send_ds = -1; // disable for next time - } - - JLOG_VERBOSE("Sending datagram, size=%d", size); - - int ret = udp_sendto(registry_impl->sock, data, size, dst); - if (ret < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) - JLOG_INFO("Send failed, buffer is full"); - else if (sockerrno == SEMSGSIZE) - JLOG_WARN("Send failed, datagram is too large"); - else - JLOG_WARN("Send failed, errno=%d", sockerrno); - } - - mutex_unlock(®istry_impl->send_mutex); - return ret; -} - -int conn_mux_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size) { - conn_impl_t *conn_impl = agent->conn_impl; - registry_impl_t *registry_impl = conn_impl->registry->impl; - - return udp_get_addrs(registry_impl->sock, records, size); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.h deleted file mode 100644 index 9519f066..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_mux.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_CONN_MUX_H -#define JUICE_CONN_MUX_H - -#include "addr.h" -#include "conn.h" -#include "thread.h" -#include "timestamp.h" - -#include -#include - -int conn_mux_registry_init(conn_registry_t *registry, udp_socket_config_t *config); -void conn_mux_registry_cleanup(conn_registry_t *registry); - -int conn_mux_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_config_t *config); -void conn_mux_cleanup(juice_agent_t *agent); -void conn_mux_lock(juice_agent_t *agent); -void conn_mux_unlock(juice_agent_t *agent); -int conn_mux_interrupt(juice_agent_t *agent); -int conn_mux_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds); -int conn_mux_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.c deleted file mode 100644 index be3377c2..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.c +++ /dev/null @@ -1,431 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "conn_poll.h" -#include "agent.h" -#include "log.h" -#include "socket.h" -#include "thread.h" -#include "udp.h" - -#include -#include - -#define BUFFER_SIZE 4096 - -typedef struct registry_impl { - thread_t thread; -#ifdef _WIN32 - socket_t interrupt_sock; -#else - int interrupt_pipe_out; - int interrupt_pipe_in; -#endif -} registry_impl_t; - -typedef enum conn_state { CONN_STATE_NEW = 0, CONN_STATE_READY, CONN_STATE_FINISHED } conn_state_t; - -typedef struct conn_impl { - conn_registry_t *registry; - conn_state_t state; - socket_t sock; - mutex_t send_mutex; - int send_ds; - timestamp_t next_timestamp; -} conn_impl_t; - -typedef struct pfds_record { - struct pollfd *pfds; - nfds_t size; -} pfds_record_t; - -int conn_poll_prepare(conn_registry_t *registry, pfds_record_t *pfds, timestamp_t *next_timestamp); -int conn_poll_process(conn_registry_t *registry, pfds_record_t *pfds); -int conn_poll_recv(socket_t sock, char *buffer, size_t size, addr_record_t *src); -int conn_poll_run(conn_registry_t *registry); - -static thread_return_t THREAD_CALL conn_thread_entry(void *arg) { - thread_set_name_self("juice poll"); - conn_registry_t *registry = (conn_registry_t *)arg; - conn_poll_run(registry); - return (thread_return_t)0; -} - -int conn_poll_registry_init(conn_registry_t *registry, udp_socket_config_t *config) { - (void)config; - registry_impl_t *registry_impl = calloc(1, sizeof(registry_impl_t)); - if (!registry_impl) { - JLOG_FATAL("Memory allocation failed for connections registry impl"); - return -1; - } - -#ifdef _WIN32 - udp_socket_config_t interrupt_config; - memset(&interrupt_config, 0, sizeof(interrupt_config)); - interrupt_config.bind_address = "localhost"; - registry_impl->interrupt_sock = udp_create_socket(&interrupt_config); - if (registry_impl->interrupt_sock == INVALID_SOCKET) { - JLOG_FATAL("Dummy socket creation failed"); - free(registry_impl); - return -1; - } -#else - int pipefds[2]; - if (pipe(pipefds)) { - JLOG_FATAL("Pipe creation failed"); - free(registry_impl); - return -1; - } - - fcntl(pipefds[0], F_SETFL, O_NONBLOCK); - fcntl(pipefds[1], F_SETFL, O_NONBLOCK); - registry_impl->interrupt_pipe_out = pipefds[1]; // read - registry_impl->interrupt_pipe_in = pipefds[0]; // write -#endif - - registry->impl = registry_impl; - - JLOG_DEBUG("Starting connections thread"); - int ret = thread_init(®istry_impl->thread, conn_thread_entry, registry); - if (ret) { - JLOG_FATAL("Thread creation failed, error=%d", ret); - goto error; - } - - return 0; - -error: -#ifndef _WIN32 - close(registry_impl->interrupt_pipe_out); - close(registry_impl->interrupt_pipe_in); -#endif - free(registry_impl); - registry->impl = NULL; - return -1; -} - -void conn_poll_registry_cleanup(conn_registry_t *registry) { - registry_impl_t *registry_impl = registry->impl; - - JLOG_VERBOSE("Waiting for connections thread"); - thread_join(registry_impl->thread, NULL); - -#ifdef _WIN32 - closesocket(registry_impl->interrupt_sock); -#else - close(registry_impl->interrupt_pipe_out); - close(registry_impl->interrupt_pipe_in); -#endif - free(registry->impl); - registry->impl = NULL; -} - -int conn_poll_prepare(conn_registry_t *registry, pfds_record_t *pfds, timestamp_t *next_timestamp) { - timestamp_t now = current_timestamp(); - *next_timestamp = now + 60000; - - mutex_lock(®istry->mutex); - nfds_t size = (nfds_t)(1 + registry->agents_size); - if (pfds->size != size) { - struct pollfd *new_pfds = realloc(pfds->pfds, sizeof(struct pollfd) * size); - if (!new_pfds) { - JLOG_FATAL("Memory allocation for poll file descriptors failed"); - goto error; - } - pfds->pfds = new_pfds; - pfds->size = size; - } - - registry_impl_t *registry_impl = registry->impl; - struct pollfd *interrupt_pfd = pfds->pfds; - assert(interrupt_pfd); -#ifdef _WIN32 - interrupt_pfd->fd = registry_impl->interrupt_sock; -#else - interrupt_pfd->fd = registry_impl->interrupt_pipe_in; -#endif - interrupt_pfd->events = POLLIN; - - for (nfds_t i = 1; i < pfds->size; ++i) { - struct pollfd *pfd = pfds->pfds + i; - juice_agent_t *agent = registry->agents[i - 1]; - if (!agent) { - pfd->fd = INVALID_SOCKET; - pfd->events = 0; - continue; - } - - conn_impl_t *conn_impl = agent->conn_impl; - if (!conn_impl || - (conn_impl->state != CONN_STATE_NEW && conn_impl->state != CONN_STATE_READY)) { - pfd->fd = INVALID_SOCKET; - pfd->events = 0; - continue; - } - - if (conn_impl->state == CONN_STATE_NEW) - conn_impl->state = CONN_STATE_READY; - - if (*next_timestamp > conn_impl->next_timestamp) - *next_timestamp = conn_impl->next_timestamp; - - pfd->fd = conn_impl->sock; - pfd->events = POLLIN; - } - - int count = registry->agents_count; - mutex_unlock(®istry->mutex); - return count; - -error: - mutex_unlock(®istry->mutex); - return -1; -} - -int conn_poll_recv(socket_t sock, char *buffer, size_t size, addr_record_t *src) { - JLOG_VERBOSE("Receiving datagram"); - int len; - while ((len = udp_recvfrom(sock, buffer, size, src)) == 0) { - // Empty datagram, ignore - } - - if (len < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) { - JLOG_VERBOSE("No more datagrams to receive"); - return 0; - } - JLOG_ERROR("recvfrom failed, errno=%d", sockerrno); - return -1; - } - - addr_unmap_inet6_v4mapped((struct sockaddr *)&src->addr, &src->len); - return len; // len > 0 -} - -int conn_poll_process(conn_registry_t *registry, pfds_record_t *pfds) { - struct pollfd *interrupt_pfd = pfds->pfds; - if (interrupt_pfd->revents & POLLIN) { -#ifdef _WIN32 - char dummy; - addr_record_t src; - while (udp_recvfrom(interrupt_pfd->fd, &dummy, 1, &src) >= 0) { - // Ignore - } -#else - char dummy; - while (read(interrupt_pfd->fd, &dummy, 1) > 0) { - // Ignore - } -#endif - } - - mutex_lock(®istry->mutex); - for (nfds_t i = 1; i < pfds->size; ++i) { - struct pollfd *pfd = pfds->pfds + i; - if (pfd->fd == INVALID_SOCKET) - continue; - - juice_agent_t *agent = registry->agents[i - 1]; - if (!agent) - continue; - - conn_impl_t *conn_impl = agent->conn_impl; - if (!conn_impl || conn_impl->sock != pfd->fd || conn_impl->state != CONN_STATE_READY) - continue; - - if (pfd->revents & POLLNVAL || pfd->revents & POLLERR) { - JLOG_WARN("Error when polling socket"); - agent_conn_fail(agent); - conn_impl->state = CONN_STATE_FINISHED; - continue; - } - - if (pfd->revents & POLLIN) { - char buffer[BUFFER_SIZE]; - addr_record_t src; - int ret = 0; - int left = 1000; // limit for fairness between sockets - while (left-- && - (ret = conn_poll_recv(conn_impl->sock, buffer, BUFFER_SIZE, &src)) > 0) { - if (agent_conn_recv(agent, buffer, (size_t)ret, &src) != 0) { - JLOG_WARN("Agent receive failed"); - conn_impl->state = CONN_STATE_FINISHED; - break; - } - } - if (conn_impl->state == CONN_STATE_FINISHED) - continue; - - if (ret < 0) { - agent_conn_fail(agent); - conn_impl->state = CONN_STATE_FINISHED; - continue; - } - - if (agent_conn_update(agent, &conn_impl->next_timestamp) != 0) { - JLOG_WARN("Agent update failed"); - conn_impl->state = CONN_STATE_FINISHED; - continue; - } - - } else if (conn_impl->next_timestamp <= current_timestamp()) { - if (agent_conn_update(agent, &conn_impl->next_timestamp) != 0) { - JLOG_WARN("Agent update failed"); - conn_impl->state = CONN_STATE_FINISHED; - continue; - } - } - } - mutex_unlock(®istry->mutex); - return 0; -} - -int conn_poll_run(conn_registry_t *registry) { - pfds_record_t pfds; - pfds.pfds = NULL; - pfds.size = 0; - timestamp_t next_timestamp = 0; - int count; - while ((count = conn_poll_prepare(registry, &pfds, &next_timestamp)) > 0) { - timediff_t timediff = next_timestamp - current_timestamp(); - if (timediff < 0) - timediff = 0; - - JLOG_VERBOSE("Entering poll on %d sockets for %d ms", count, (int)timediff); - int ret = poll(pfds.pfds, pfds.size, (int)timediff); - JLOG_VERBOSE("Leaving poll"); - if (ret < 0) { -#ifdef _WIN32 - if (ret == WSAENOTSOCK) - continue; // prepare again as the fd has been removed -#endif - if (sockerrno == SEINTR || sockerrno == SEAGAIN) { - JLOG_VERBOSE("poll interrupted"); - continue; - } else { - JLOG_FATAL("poll failed, errno=%d", sockerrno); - break; - } - } - - if (conn_poll_process(registry, &pfds) < 0) - break; - } - - JLOG_DEBUG("Leaving connections thread"); - free(pfds.pfds); - return 0; -} - -int conn_poll_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_config_t *config) { - conn_impl_t *conn_impl = calloc(1, sizeof(conn_impl_t)); - if (!conn_impl) { - JLOG_FATAL("Memory allocation failed for connection impl"); - return -1; - } - - conn_impl->sock = udp_create_socket(config); - if (conn_impl->sock == INVALID_SOCKET) { - JLOG_ERROR("UDP socket creation failed"); - free(conn_impl); - return -1; - } - - mutex_init(&conn_impl->send_mutex, 0); - conn_impl->registry = registry; - - agent->conn_impl = conn_impl; - return 0; -} - -void conn_poll_cleanup(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - - conn_poll_interrupt(agent); - - mutex_destroy(&conn_impl->send_mutex); - closesocket(conn_impl->sock); - free(agent->conn_impl); - agent->conn_impl = NULL; -} - -void conn_poll_lock(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - mutex_lock(®istry->mutex); -} - -void conn_poll_unlock(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - mutex_unlock(®istry->mutex); -} - -int conn_poll_interrupt(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - registry_impl_t *registry_impl = registry->impl; - - mutex_lock(®istry->mutex); - conn_impl->next_timestamp = current_timestamp(); - mutex_unlock(®istry->mutex); - - JLOG_VERBOSE("Interrupting connections thread"); - -#ifdef _WIN32 - if (udp_sendto_self(registry_impl->interrupt_sock, NULL, 0) < 0) { - if (sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) { - JLOG_WARN("Failed to interrupt poll by triggering socket, errno=%d", sockerrno); - } - return -1; - } -#else - char dummy = 0; - if (write(registry_impl->interrupt_pipe_out, &dummy, 1) < 0 && errno != EAGAIN && - errno != EWOULDBLOCK) { - JLOG_WARN("Failed to interrupt poll by writing to pipe, errno=%d", errno); - } -#endif - return 0; -} - -int conn_poll_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds) { - conn_impl_t *conn_impl = agent->conn_impl; - - mutex_lock(&conn_impl->send_mutex); - - if (conn_impl->send_ds >= 0 && conn_impl->send_ds != ds) { - JLOG_VERBOSE("Setting Differentiated Services field to 0x%X", ds); - if (udp_set_diffserv(conn_impl->sock, ds) == 0) - conn_impl->send_ds = ds; - else - conn_impl->send_ds = -1; // disable for next time - } - - JLOG_VERBOSE("Sending datagram, size=%d", size); - - int ret = udp_sendto(conn_impl->sock, data, size, dst); - if (ret < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) - JLOG_INFO("Send failed, buffer is full"); - else if (sockerrno == SEMSGSIZE) - JLOG_WARN("Send failed, datagram is too large"); - else - JLOG_WARN("Send failed, errno=%d", sockerrno); - } - - mutex_unlock(&conn_impl->send_mutex); - return ret; -} - -int conn_poll_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size) { - conn_impl_t *conn_impl = agent->conn_impl; - - return udp_get_addrs(conn_impl->sock, records, size); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.h deleted file mode 100644 index b3a162a8..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_poll.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_CONN_POLL_H -#define JUICE_CONN_POLL_H - -#include "addr.h" -#include "conn.h" -#include "thread.h" -#include "timestamp.h" - -#include -#include - -int conn_poll_registry_init(conn_registry_t *registry, udp_socket_config_t *config); -void conn_poll_registry_cleanup(conn_registry_t *registry); - -int conn_poll_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_config_t *config); -void conn_poll_cleanup(juice_agent_t *agent); -void conn_poll_lock(juice_agent_t *agent); -void conn_poll_unlock(juice_agent_t *agent); -int conn_poll_interrupt(juice_agent_t *agent); -int conn_poll_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds); -int conn_poll_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.c deleted file mode 100644 index 00c49b0c..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.c +++ /dev/null @@ -1,279 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "conn_thread.h" -#include "agent.h" -#include "log.h" -#include "socket.h" -#include "thread.h" -#include "udp.h" - -#include -#include - -#define BUFFER_SIZE 4096 - -typedef struct conn_impl { - thread_t thread; - socket_t sock; - mutex_t mutex; - mutex_t send_mutex; - int send_ds; - timestamp_t next_timestamp; - bool stopped; -} conn_impl_t; - -int conn_thread_run(juice_agent_t *agent); -int conn_thread_prepare(juice_agent_t *agent, struct pollfd *pfd, timestamp_t *next_timestamp); -int conn_thread_process(juice_agent_t *agent, struct pollfd *pfd); -int conn_thread_recv(socket_t sock, char *buffer, size_t size, addr_record_t *src); - -static thread_return_t THREAD_CALL conn_thread_entry(void *arg) { - thread_set_name_self("juice agent"); - juice_agent_t *agent = (juice_agent_t *)arg; - conn_thread_run(agent); - return (thread_return_t)0; -} - -int conn_thread_prepare(juice_agent_t *agent, struct pollfd *pfd, timestamp_t *next_timestamp) { - conn_impl_t *conn_impl = agent->conn_impl; - mutex_lock(&conn_impl->mutex); - if (conn_impl->stopped) { - mutex_unlock(&conn_impl->mutex); - return 0; - } - - pfd->fd = conn_impl->sock; - pfd->events = POLLIN; - - *next_timestamp = conn_impl->next_timestamp; - - mutex_unlock(&conn_impl->mutex); - return 1; -} - -int conn_thread_process(juice_agent_t *agent, struct pollfd *pfd) { - conn_impl_t *conn_impl = agent->conn_impl; - mutex_lock(&conn_impl->mutex); - if (conn_impl->stopped) { - mutex_unlock(&conn_impl->mutex); - return -1; - } - - if (pfd->revents & POLLNVAL || pfd->revents & POLLERR) { - JLOG_ERROR("Error when polling socket"); - agent_conn_fail(agent); - mutex_unlock(&conn_impl->mutex); - return -1; - } - - if (pfd->revents & POLLIN) { - char buffer[BUFFER_SIZE]; - addr_record_t src; - int ret; - while ((ret = conn_thread_recv(conn_impl->sock, buffer, BUFFER_SIZE, &src)) > 0) { - if (agent_conn_recv(agent, buffer, (size_t)ret, &src) != 0) { - JLOG_WARN("Agent receive failed"); - mutex_unlock(&conn_impl->mutex); - return -1; - } - } - - if (ret < 0) { - agent_conn_fail(agent); - mutex_unlock(&conn_impl->mutex); - return -1; - } - - if (agent_conn_update(agent, &conn_impl->next_timestamp) != 0) { - JLOG_WARN("Agent update failed"); - mutex_unlock(&conn_impl->mutex); - return -1; - } - - } else if (conn_impl->next_timestamp <= current_timestamp()) { - if (agent_conn_update(agent, &conn_impl->next_timestamp) != 0) { - JLOG_WARN("Agent update failed"); - mutex_unlock(&conn_impl->mutex); - return -1; - } - } - - mutex_unlock(&conn_impl->mutex); - return 0; -} - -int conn_thread_recv(socket_t sock, char *buffer, size_t size, addr_record_t *src) { - JLOG_VERBOSE("Receiving datagram"); - int len; - while ((len = udp_recvfrom(sock, buffer, size, src)) == 0) { - // Empty datagram (used to interrupt) - } - - if (len < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) { - JLOG_VERBOSE("No more datagrams to receive"); - return 0; - } - JLOG_ERROR("recvfrom failed, errno=%d", sockerrno); - return -1; - } - - addr_unmap_inet6_v4mapped((struct sockaddr *)&src->addr, &src->len); - return len; // len > 0 -} - -int conn_thread_run(juice_agent_t *agent) { - struct pollfd pfd[1]; - timestamp_t next_timestamp; - while (conn_thread_prepare(agent, pfd, &next_timestamp) > 0) { - timediff_t timediff = next_timestamp - current_timestamp(); - if (timediff < 0) - timediff = 0; - - JLOG_VERBOSE("Entering poll for %d ms", (int)timediff); - int ret = poll(pfd, 1, (int)timediff); - JLOG_VERBOSE("Leaving poll"); - if (ret < 0) { - if (sockerrno == SEINTR || sockerrno == SEAGAIN) { - JLOG_VERBOSE("poll interrupted"); - continue; - } else { - JLOG_FATAL("poll failed, errno=%d", sockerrno); - break; - } - } - - if (conn_thread_process(agent, pfd) < 0) - break; - } - - JLOG_DEBUG("Leaving connection thread"); - return 0; -} - -int conn_thread_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_config_t *config) { - (void)registry; - - conn_impl_t *conn_impl = calloc(1, sizeof(conn_impl_t)); - if (!conn_impl) { - JLOG_FATAL("Memory allocation failed for connection impl"); - return -1; - } - - conn_impl->sock = udp_create_socket(config); - if (conn_impl->sock == INVALID_SOCKET) { - JLOG_ERROR("UDP socket creation failed"); - free(conn_impl); - return -1; - } - - mutex_init(&conn_impl->mutex, 0); - mutex_init(&conn_impl->send_mutex, 0); - - agent->conn_impl = conn_impl; - - JLOG_DEBUG("Starting connection thread"); - int ret = thread_init(&conn_impl->thread, conn_thread_entry, agent); - if (ret) { - JLOG_FATAL("Thread creation failed, error=%d", ret); - free(conn_impl); - agent->conn_impl = NULL; - return -1; - } - - return 0; -} - -void conn_thread_cleanup(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - - mutex_lock(&conn_impl->mutex); - conn_impl->stopped = true; - mutex_unlock(&conn_impl->mutex); - - conn_thread_interrupt(agent); - - JLOG_VERBOSE("Waiting for connection thread"); - thread_join(conn_impl->thread, NULL); - - closesocket(conn_impl->sock); - mutex_destroy(&conn_impl->mutex); - mutex_destroy(&conn_impl->send_mutex); - free(agent->conn_impl); - agent->conn_impl = NULL; -} - -void conn_thread_lock(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - mutex_lock(&conn_impl->mutex); -} - -void conn_thread_unlock(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - mutex_unlock(&conn_impl->mutex); -} - -int conn_thread_interrupt(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - - mutex_lock(&conn_impl->mutex); - conn_impl->next_timestamp = current_timestamp(); - mutex_unlock(&conn_impl->mutex); - - JLOG_VERBOSE("Interrupting connection thread"); - - mutex_lock(&conn_impl->send_mutex); - if (udp_sendto_self(conn_impl->sock, NULL, 0) < 0) { - if (sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) { - JLOG_WARN("Failed to interrupt poll by triggering socket, errno=%d", sockerrno); - } - mutex_unlock(&conn_impl->send_mutex); - return -1; - } - - mutex_unlock(&conn_impl->send_mutex); - return 0; -} - -int conn_thread_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds) { - conn_impl_t *conn_impl = agent->conn_impl; - - mutex_lock(&conn_impl->send_mutex); - - if (conn_impl->send_ds >= 0 && conn_impl->send_ds != ds) { - JLOG_VERBOSE("Setting Differentiated Services field to 0x%X", ds); - if (udp_set_diffserv(conn_impl->sock, ds) == 0) - conn_impl->send_ds = ds; - else - conn_impl->send_ds = -1; // disable for next time - } - - JLOG_VERBOSE("Sending datagram, size=%d", size); - - int ret = udp_sendto(conn_impl->sock, data, size, dst); - if (ret < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) - JLOG_INFO("Send failed, buffer is full"); - else if (sockerrno == SEMSGSIZE) - JLOG_WARN("Send failed, datagram is too large"); - else - JLOG_WARN("Send failed, errno=%d", sockerrno); - } - - mutex_unlock(&conn_impl->send_mutex); - return ret; -} - -int conn_thread_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size) { - conn_impl_t *conn_impl = agent->conn_impl; - - return udp_get_addrs(conn_impl->sock, records, size); -} - diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.h deleted file mode 100644 index ceb23a4c..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/conn_thread.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_CONN_THREAD_H -#define JUICE_CONN_THREAD_H - -#include "addr.h" -#include "conn.h" -#include "thread.h" -#include "timestamp.h" - -#include -#include - -int conn_thread_registry_init(conn_registry_t *registry, udp_socket_config_t *config); -void conn_thread_registry_cleanup(conn_registry_t *registry); - -int conn_thread_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_config_t *config); -void conn_thread_cleanup(juice_agent_t *agent); -void conn_thread_lock(juice_agent_t *agent); -void conn_thread_unlock(juice_agent_t *agent); -int conn_thread_interrupt(juice_agent_t *agent); -int conn_thread_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, - int ds); -int conn_thread_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.c deleted file mode 100644 index 5529ca2d..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.c +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "const_time.h" - -int const_time_memcmp(const void *a, const void *b, size_t len) { - const unsigned char *ca = a; - const unsigned char *cb = b; - unsigned char x = 0; - for (size_t i = 0; i < len; i++) - x |= ca[i] ^ cb[i]; - - return x; -} - -int const_time_strcmp(const void *a, const void *b) { - const unsigned char *ca = a; - const unsigned char *cb = b; - unsigned char x = 0; - size_t i = 0; - for(;;) { - x |= ca[i] ^ cb[i]; - if (!ca[i] || !cb[i]) - break; - ++i; - } - - return x; -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.h deleted file mode 100644 index d654a730..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/const_time.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_CONST_TIME_H -#define JUICE_CONST_TIME_H - -#include -#include - -int const_time_memcmp(const void *a, const void *b, size_t len); -int const_time_strcmp(const void *a, const void *b); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.c deleted file mode 100644 index 61cff0aa..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.c +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "crc32.h" - -#define CRC32_REVERSED_POLY 0xEDB88320 -#define CRC32_INIT 0xFFFFFFFF -#define CRC32_XOR 0xFFFFFFFF - -static uint32_t crc32_byte(uint32_t crc) { - for (int i = 0; i < 8; ++i) - if (crc & 1) - crc = (crc >> 1) ^ CRC32_REVERSED_POLY; - else - crc = (crc >> 1); - return crc; -} - -static uint32_t crc32_table(const uint8_t *p, size_t size, uint32_t *table) { - uint32_t crc = CRC32_INIT; - while (size--) - crc = table[(uint8_t)(crc & 0xFF) ^ *p++] ^ (crc >> 8); - return crc ^ CRC32_XOR; -} - -JUICE_EXPORT uint32_t juice_crc32(const void *data, size_t size) { - static uint32_t table[256] = {0}; - if (table[0] == 0) - for (uint32_t i = 0; i < 256; ++i) - table[i] = crc32_byte(i); - - return crc32_table(data, size, table); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.h deleted file mode 100644 index 9567209a..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/crc32.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_CRC32_H -#define JUICE_CRC32_H - -#include "juice.h" - -#include -#include - -JUICE_EXPORT uint32_t juice_crc32(const void *data, size_t size); - -#define CRC32(data, size) juice_crc32(data, size) - -#endif // JUICE_CRC32_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/hash.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/hash.c deleted file mode 100644 index 3f969e6a..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/hash.c +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "hash.h" - -#if USE_NETTLE -#include -#include -#include -#else -#include "picohash.h" -#endif - -void hash_md5(const void *message, size_t size, void *digest) { -#if USE_NETTLE - struct md5_ctx ctx; - md5_init(&ctx); - md5_update(&ctx, size, message); - md5_digest(&ctx, HASH_MD5_SIZE, digest); -#else - picohash_ctx_t ctx; - picohash_init_md5(&ctx); - picohash_update(&ctx, message, size); - picohash_final(&ctx, digest); -#endif -} - -void hash_sha1(const void *message, size_t size, void *digest) { -#if USE_NETTLE - struct sha1_ctx ctx; - sha1_init(&ctx); - sha1_update(&ctx, size, message); - sha1_digest(&ctx, HASH_SHA1_SIZE, digest); -#else - picohash_ctx_t ctx; - picohash_init_sha1(&ctx); - picohash_update(&ctx, message, size); - picohash_final(&ctx, digest); -#endif -} - -void hash_sha256(const void *message, size_t size, void *digest) { -#if USE_NETTLE - struct sha256_ctx ctx; - sha256_init(&ctx); - sha256_update(&ctx, size, message); - sha256_digest(&ctx, HASH_SHA256_SIZE, digest); -#else - picohash_ctx_t ctx; - picohash_init_sha256(&ctx); - picohash_update(&ctx, message, size); - picohash_final(&ctx, digest); -#endif -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/hash.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/hash.h deleted file mode 100644 index 31d392b8..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/hash.h +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_HASH_H -#define JUICE_HASH_H - -#include -#include - -#define HASH_MD5_SIZE 16 -#define HASH_SHA1_SIZE 24 -#define HASH_SHA256_SIZE 32 - -void hash_md5(const void *message, size_t size, void *digest); -void hash_sha1(const void *message, size_t size, void *digest); -void hash_sha256(const void *message, size_t size, void *digest); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.c deleted file mode 100644 index 179b02f9..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.c +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "hmac.h" - -#if USE_NETTLE -#include -#else -#include "picohash.h" -#endif - -void hmac_sha1(const void *message, size_t size, const void *key, size_t key_size, void *digest) { -#if USE_NETTLE - struct hmac_sha1_ctx ctx; - hmac_sha1_set_key(&ctx, key_size, key); - hmac_sha1_update(&ctx, size, message); - hmac_sha1_digest(&ctx, HMAC_SHA1_SIZE, digest); -#else - picohash_ctx_t ctx; - picohash_init_hmac(&ctx, picohash_init_sha1, key, key_size); - picohash_update(&ctx, message, size); - picohash_final(&ctx, digest); -#endif -} - -void hmac_sha256(const void *message, size_t size, const void *key, size_t key_size, void *digest) { -#if USE_NETTLE - struct hmac_sha256_ctx ctx; - hmac_sha256_set_key(&ctx, key_size, key); - hmac_sha256_update(&ctx, size, message); - hmac_sha256_digest(&ctx, HMAC_SHA256_SIZE, digest); -#else - picohash_ctx_t ctx; - picohash_init_hmac(&ctx, picohash_init_sha256, key, key_size); - picohash_update(&ctx, message, size); - picohash_final(&ctx, digest); -#endif -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.h deleted file mode 100644 index 2eedfc05..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/hmac.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_HMAC_H -#define JUICE_HMAC_H - -#include -#include - -#define HMAC_SHA1_SIZE 20 -#define HMAC_SHA256_SIZE 32 - -void hmac_sha1(const void *message, size_t size, const void *key, size_t key_size, void *digest); -void hmac_sha256(const void *message, size_t size, const void *key, size_t key_size, void *digest); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/ice.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/ice.c deleted file mode 100644 index 393caeff..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/ice.c +++ /dev/null @@ -1,417 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "ice.h" -#include "log.h" -#include "random.h" - -#include -#include -#include -#include -#include - -#define BUFFER_SIZE 1024 - -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - -// See RFC4566 for SDP format: https://www.rfc-editor.org/rfc/rfc4566.html - -static const char *skip_prefix(const char *str, const char *prefix) { - size_t len = strlen(prefix); - return strncmp(str, prefix, len) == 0 ? str + len : str; -} - -static bool match_prefix(const char *str, const char *prefix, const char **end) { - *end = skip_prefix(str, prefix); - return *end != str || !*prefix; -} - -static int parse_sdp_line(const char *line, ice_description_t *description) { - const char *arg; - if (match_prefix(line, "a=ice-ufrag:", &arg)) { - sscanf(arg, "%256s", description->ice_ufrag); - return 0; - } - if (match_prefix(line, "a=ice-pwd:", &arg)) { - sscanf(arg, "%256s", description->ice_pwd); - return 0; - } - if (match_prefix(line, "a=ice-lite", &arg)) { - description->ice_lite = true; - return 0; - } - if (match_prefix(line, "a=end-of-candidates", &arg)) { - description->finished = true; - return 0; - } - ice_candidate_t candidate; - if (ice_parse_candidate_sdp(line, &candidate) == 0) { - ice_add_candidate(&candidate, description); - return 0; - } - return ICE_PARSE_IGNORED; -} - -static int parse_sdp_candidate(const char *line, ice_candidate_t *candidate) { - memset(candidate, 0, sizeof(*candidate)); - - line = skip_prefix(line, "a="); - line = skip_prefix(line, "candidate:"); - - char transport[32 + 1]; - char type[32 + 1]; - if (sscanf(line, "%32s %d %32s %u %256s %32s typ %32s", candidate->foundation, - &candidate->component, transport, &candidate->priority, candidate->hostname, - candidate->service, type) != 7) { - JLOG_WARN("Failed to parse candidate: %s", line); - return ICE_PARSE_ERROR; - } - - for (int i = 0; transport[i]; ++i) - transport[i] = toupper((unsigned char)transport[i]); - - for (int i = 0; type[i]; ++i) - type[i] = tolower((unsigned char)type[i]); - - if (strcmp(type, "host") == 0) - candidate->type = ICE_CANDIDATE_TYPE_HOST; - else if (strcmp(type, "srflx") == 0) - candidate->type = ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE; - else if (strcmp(type, "relay") == 0) - candidate->type = ICE_CANDIDATE_TYPE_RELAYED; - else { - JLOG_WARN("Ignoring candidate with unknown type \"%s\"", type); - return ICE_PARSE_IGNORED; - } - - if (strcmp(transport, "UDP") != 0) { - JLOG_WARN("Ignoring candidate with transport %s", transport); - return ICE_PARSE_IGNORED; - } - - return 0; -} - -int ice_parse_sdp(const char *sdp, ice_description_t *description) { - memset(description, 0, sizeof(*description)); - description->ice_lite = false; - description->candidates_count = 0; - description->finished = false; - - char buffer[BUFFER_SIZE]; - size_t size = 0; - while (*sdp) { - if (*sdp == '\n') { - if (size) { - buffer[size++] = '\0'; - if(parse_sdp_line(buffer, description) == ICE_PARSE_ERROR) - return ICE_PARSE_ERROR; - - size = 0; - } - } else if (*sdp != '\r' && size + 1 < BUFFER_SIZE) { - buffer[size++] = *sdp; - } - ++sdp; - } - ice_sort_candidates(description); - - JLOG_DEBUG("Parsed remote description: ufrag=\"%s\", pwd=\"%s\", candidates=%d", - description->ice_ufrag, description->ice_pwd, description->candidates_count); - - if (*description->ice_ufrag == '\0') - return ICE_PARSE_MISSING_UFRAG; - - if (*description->ice_pwd == '\0') - return ICE_PARSE_MISSING_PWD; - - return 0; -} - -int ice_parse_candidate_sdp(const char *line, ice_candidate_t *candidate) { - const char *arg; - if (match_prefix(line, "a=candidate:", &arg)) { - int ret = parse_sdp_candidate(line, candidate); - if (ret < 0) - return ret; - ice_resolve_candidate(candidate, ICE_RESOLVE_MODE_SIMPLE); - return 0; - } - return ICE_PARSE_ERROR; -} - -int ice_create_local_description(ice_description_t *description) { - memset(description, 0, sizeof(*description)); - juice_random_str64(description->ice_ufrag, 4 + 1); - juice_random_str64(description->ice_pwd, 22 + 1); - description->ice_lite = false; - description->candidates_count = 0; - description->finished = false; - JLOG_DEBUG("Created local description: ufrag=\"%s\", pwd=\"%s\"", description->ice_ufrag, - description->ice_pwd); - return 0; -} - -int ice_create_local_candidate(ice_candidate_type_t type, int component, int index, - const addr_record_t *record, ice_candidate_t *candidate) { - memset(candidate, 0, sizeof(*candidate)); - candidate->type = type; - candidate->component = component; - candidate->resolved = *record; - strcpy(candidate->foundation, "-"); - - candidate->priority = ice_compute_priority(candidate->type, candidate->resolved.addr.ss_family, - candidate->component, index); - - if (getnameinfo((struct sockaddr *)&record->addr, record->len, candidate->hostname, 256, - candidate->service, 32, NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM)) { - JLOG_ERROR("getnameinfo failed, errno=%d", sockerrno); - return -1; - } - return 0; -} - -int ice_resolve_candidate(ice_candidate_t *candidate, ice_resolve_mode_t mode) { - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_ADDRCONFIG; - if (mode != ICE_RESOLVE_MODE_LOOKUP) - hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; - struct addrinfo *ai_list = NULL; - if (getaddrinfo(candidate->hostname, candidate->service, &hints, &ai_list)) { - JLOG_INFO("Failed to resolve address: %s:%s", candidate->hostname, candidate->service); - candidate->resolved.len = 0; - return -1; - } - for (struct addrinfo *ai = ai_list; ai; ai = ai->ai_next) { - if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { - candidate->resolved.len = (socklen_t)ai->ai_addrlen; - memcpy(&candidate->resolved.addr, ai->ai_addr, ai->ai_addrlen); - break; - } - } - freeaddrinfo(ai_list); - return 0; -} - -int ice_add_candidate(ice_candidate_t *candidate, ice_description_t *description) { - if (candidate->type == ICE_CANDIDATE_TYPE_UNKNOWN) - return -1; - - if (description->candidates_count >= ICE_MAX_CANDIDATES_COUNT) { - JLOG_WARN("Description already has the maximum number of candidates"); - return -1; - } - - if (strcmp(candidate->foundation, "-") == 0) - snprintf(candidate->foundation, 32, "%u", - (unsigned int)(description->candidates_count + 1)); - - ice_candidate_t *pos = description->candidates + description->candidates_count; - *pos = *candidate; - ++description->candidates_count; - return 0; -} - -void ice_sort_candidates(ice_description_t *description) { - // In-place insertion sort - ice_candidate_t *begin = description->candidates; - ice_candidate_t *end = begin + description->candidates_count; - ice_candidate_t *cur = begin; - while (++cur < end) { - uint32_t priority = cur->priority; - ice_candidate_t *prev = cur; - ice_candidate_t tmp = *prev; - while (--prev >= begin && prev->priority < priority) { - *(prev + 1) = *prev; - } - if (prev + 1 != cur) - *(prev + 1) = tmp; - } -} - -ice_candidate_t *ice_find_candidate_from_addr(ice_description_t *description, - const addr_record_t *record, - ice_candidate_type_t type) { - ice_candidate_t *cur = description->candidates; - ice_candidate_t *end = cur + description->candidates_count; - while (cur != end) { - if ((type == ICE_CANDIDATE_TYPE_UNKNOWN || cur->type == type) && - addr_is_equal((struct sockaddr *)&record->addr, (struct sockaddr *)&cur->resolved.addr, - true)) - return cur; - ++cur; - } - return NULL; -} - -int ice_generate_sdp(const ice_description_t *description, char *buffer, size_t size) { - if (!*description->ice_ufrag || !*description->ice_pwd) - return -1; - - int len = 0; - char *begin = buffer; - char *end = begin + size; - - // Round 0: description - // Round i with i>0 and icandidates_count + 2; ++i) { - int ret; - if (i == 0) { - ret = snprintf(begin, end - begin, "a=ice-ufrag:%s\r\na=ice-pwd:%s\r\n", - description->ice_ufrag, description->ice_pwd); - if (description->ice_lite) - ret = snprintf(begin, end - begin, "a=ice-lite\r\n"); - - } else if (i < description->candidates_count + 1) { - const ice_candidate_t *candidate = description->candidates + i - 1; - if (candidate->type == ICE_CANDIDATE_TYPE_UNKNOWN || - candidate->type == ICE_CANDIDATE_TYPE_PEER_REFLEXIVE) - continue; - char tmp[BUFFER_SIZE]; - if (ice_generate_candidate_sdp(candidate, tmp, BUFFER_SIZE) < 0) - continue; - ret = snprintf(begin, end - begin, "%s\r\n", tmp); - } else { // i == description->candidates_count + 1 - // RFC 8445 10. ICE Option: An agent compliant to this specification MUST inform the - // peer about the compliance using the 'ice2' option. - if (description->finished) - ret = snprintf(begin, end - begin, "a=end-of-candidates\r\na=ice-options:ice2\r\n"); - else - ret = snprintf(begin, end - begin, "a=ice-options:ice2,trickle\r\n"); - } - if (ret < 0) - return -1; - - len += ret; - - if (begin < end) - begin += ret >= end - begin ? end - begin - 1 : ret; - } - return len; -} - -int ice_generate_candidate_sdp(const ice_candidate_t *candidate, char *buffer, size_t size) { - const char *type = NULL; - const char *suffix = NULL; - switch (candidate->type) { - case ICE_CANDIDATE_TYPE_HOST: - type = "host"; - break; - case ICE_CANDIDATE_TYPE_PEER_REFLEXIVE: - type = "prflx"; - break; - case ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: - type = "srflx"; - suffix = "raddr 0.0.0.0 rport 0"; // This is needed for compatibility with Firefox - break; - case ICE_CANDIDATE_TYPE_RELAYED: - type = "relay"; - suffix = "raddr 0.0.0.0 rport 0"; // This is needed for compatibility with Firefox - break; - default: - JLOG_ERROR("Unknown candidate type"); - return -1; - } - return snprintf(buffer, size, "a=candidate:%s %u UDP %u %s %s typ %s%s%s", - candidate->foundation, candidate->component, candidate->priority, - candidate->hostname, candidate->service, type, suffix ? " " : "", - suffix ? suffix : ""); -} - -int ice_create_candidate_pair(ice_candidate_t *local, ice_candidate_t *remote, bool is_controlling, - ice_candidate_pair_t *pair) { // local or remote might be NULL - if (local && remote && local->resolved.addr.ss_family != remote->resolved.addr.ss_family) { - JLOG_ERROR("Mismatching candidates address families"); - return -1; - } - - memset(pair, 0, sizeof(*pair)); - pair->local = local; - pair->remote = remote; - pair->state = ICE_CANDIDATE_PAIR_STATE_FROZEN; - return ice_update_candidate_pair(pair, is_controlling); -} - -int ice_update_candidate_pair(ice_candidate_pair_t *pair, bool is_controlling) { - // Compute pair priority according to RFC 8445, extended to support generic pairs missing local - // or remote See https://www.rfc-editor.org/rfc/rfc8445.html#section-6.1.2.3 - if (!pair->local && !pair->remote) - return 0; - uint64_t local_priority = - pair->local - ? pair->local->priority - : ice_compute_priority(ICE_CANDIDATE_TYPE_HOST, pair->remote->resolved.addr.ss_family, - pair->remote->component, 0); - uint64_t remote_priority = - pair->remote - ? pair->remote->priority - : ice_compute_priority(ICE_CANDIDATE_TYPE_HOST, pair->local->resolved.addr.ss_family, - pair->local->component, 0); - uint64_t g = is_controlling ? local_priority : remote_priority; - uint64_t d = is_controlling ? remote_priority : local_priority; - uint64_t min = g < d ? g : d; - uint64_t max = g > d ? g : d; - pair->priority = (min << 32) + (max << 1) + (g > d ? 1 : 0); - return 0; -} - -int ice_candidates_count(const ice_description_t *description, ice_candidate_type_t type) { - int count = 0; - for (int i = 0; i < description->candidates_count; ++i) { - const ice_candidate_t *candidate = description->candidates + i; - if (candidate->type == type) - ++count; - } - return count; -} - -uint32_t ice_compute_priority(ice_candidate_type_t type, int family, int component, int index) { - // Compute candidate priority according to RFC 8445 - // See https://www.rfc-editor.org/rfc/rfc8445.html#section-5.1.2.1 - uint32_t p = 0; - - switch (type) { - case ICE_CANDIDATE_TYPE_HOST: - p += ICE_CANDIDATE_PREF_HOST; - break; - case ICE_CANDIDATE_TYPE_PEER_REFLEXIVE: - p += ICE_CANDIDATE_PREF_PEER_REFLEXIVE; - break; - case ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: - p += ICE_CANDIDATE_PREF_SERVER_REFLEXIVE; - break; - case ICE_CANDIDATE_TYPE_RELAYED: - p += ICE_CANDIDATE_PREF_RELAYED; - break; - default: - break; - } - p <<= 16; - - switch (family) { - case AF_INET: - p += 32767; - break; - case AF_INET6: - p += 65535; - break; - default: - break; - } - p -= CLAMP(index, 0, 32767); - p <<= 8; - - p += 256 - CLAMP(component, 1, 256); - return p; -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/ice.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/ice.h deleted file mode 100644 index 51078bd4..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/ice.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_ICE_H -#define JUICE_ICE_H - -#include "addr.h" -#include "juice.h" -#include "timestamp.h" - -#include -#include - -#define ICE_MAX_CANDIDATES_COUNT 20 // ~ 500B * 20 = 10KB - -typedef enum ice_candidate_type { - ICE_CANDIDATE_TYPE_UNKNOWN, - ICE_CANDIDATE_TYPE_HOST, - ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE, - ICE_CANDIDATE_TYPE_PEER_REFLEXIVE, - ICE_CANDIDATE_TYPE_RELAYED, -} ice_candidate_type_t; - -// RFC 8445: The RECOMMENDED values for type preferences are 126 for host candidates, 110 for -// peer-reflexive candidates, 100 for server-reflexive candidates, and 0 for relayed candidates. -#define ICE_CANDIDATE_PREF_HOST 126 -#define ICE_CANDIDATE_PREF_PEER_REFLEXIVE 110 -#define ICE_CANDIDATE_PREF_SERVER_REFLEXIVE 100 -#define ICE_CANDIDATE_PREF_RELAYED 0 - -typedef struct ice_candidate { - ice_candidate_type_t type; - uint32_t priority; - int component; - char foundation[32 + 1]; // 1 to 32 characters - char transport[32 + 1]; - char hostname[256 + 1]; - char service[32 + 1]; - addr_record_t resolved; -} ice_candidate_t; - -typedef struct ice_description { - char ice_ufrag[256 + 1]; // 4 to 256 characters - char ice_pwd[256 + 1]; // 22 to 256 characters - bool ice_lite; - ice_candidate_t candidates[ICE_MAX_CANDIDATES_COUNT]; - int candidates_count; - bool finished; -} ice_description_t; - -typedef enum ice_candidate_pair_state { - ICE_CANDIDATE_PAIR_STATE_PENDING, - ICE_CANDIDATE_PAIR_STATE_SUCCEEDED, - ICE_CANDIDATE_PAIR_STATE_FAILED, - ICE_CANDIDATE_PAIR_STATE_FROZEN, -} ice_candidate_pair_state_t; - -typedef struct ice_candidate_pair { - ice_candidate_t *local; - ice_candidate_t *remote; - uint64_t priority; - ice_candidate_pair_state_t state; - bool nominated; - bool nomination_requested; - timestamp_t consent_expiry; -} ice_candidate_pair_t; - -typedef enum ice_resolve_mode { - ICE_RESOLVE_MODE_SIMPLE, - ICE_RESOLVE_MODE_LOOKUP, -} ice_resolve_mode_t; - -#define ICE_PARSE_ERROR -1 -#define ICE_PARSE_IGNORED -2 -#define ICE_PARSE_MISSING_UFRAG -3 -#define ICE_PARSE_MISSING_PWD -4 - -int ice_parse_sdp(const char *sdp, ice_description_t *description); -int ice_parse_candidate_sdp(const char *line, ice_candidate_t *candidate); -int ice_create_local_description(ice_description_t *description); -int ice_create_local_candidate(ice_candidate_type_t type, int component, int index, - const addr_record_t *record, ice_candidate_t *candidate); -int ice_resolve_candidate(ice_candidate_t *candidate, ice_resolve_mode_t mode); -int ice_add_candidate(ice_candidate_t *candidate, ice_description_t *description); -void ice_sort_candidates(ice_description_t *description); -ice_candidate_t *ice_find_candidate_from_addr(ice_description_t *description, - const addr_record_t *record, - ice_candidate_type_t type); -int ice_generate_sdp(const ice_description_t *description, char *buffer, size_t size); -int ice_generate_candidate_sdp(const ice_candidate_t *candidate, char *buffer, size_t size); -int ice_create_candidate_pair(ice_candidate_t *local, ice_candidate_t *remote, bool is_controlling, - ice_candidate_pair_t *pair); // local or remote might be NULL -int ice_update_candidate_pair(ice_candidate_pair_t *pair, bool is_controlling); - -int ice_candidates_count(const ice_description_t *description, ice_candidate_type_t type); - -uint32_t ice_compute_priority(ice_candidate_type_t type, int family, int component, int index); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/juice.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/juice.c deleted file mode 100644 index 6af80c94..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/juice.c +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "juice.h" -#include "addr.h" -#include "agent.h" -#include "ice.h" - -#ifndef NO_SERVER -#include "server.h" -#endif - -#include - -JUICE_EXPORT juice_agent_t *juice_create(const juice_config_t *config) { - if (!config) - return NULL; - - return agent_create(config); -} - -JUICE_EXPORT void juice_destroy(juice_agent_t *agent) { - if (agent) - agent_destroy(agent); -} - -JUICE_EXPORT int juice_gather_candidates(juice_agent_t *agent) { - if (!agent) - return JUICE_ERR_INVALID; - - if (agent_gather_candidates(agent) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_get_local_description(juice_agent_t *agent, char *buffer, size_t size) { - if (!agent || (!buffer && size)) - return JUICE_ERR_INVALID; - - if (agent_get_local_description(agent, buffer, size) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_set_remote_description(juice_agent_t *agent, const char *sdp) { - if (!agent || !sdp) - return JUICE_ERR_INVALID; - - if (agent_set_remote_description(agent, sdp) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_add_remote_candidate(juice_agent_t *agent, const char *sdp) { - if (!agent || !sdp) - return JUICE_ERR_INVALID; - - if (agent_add_remote_candidate(agent, sdp) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_set_remote_gathering_done(juice_agent_t *agent) { - if (!agent) - return JUICE_ERR_INVALID; - - if (agent_set_remote_gathering_done(agent) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_send(juice_agent_t *agent, const char *data, size_t size) { - if (!agent || (!data && size)) - return JUICE_ERR_INVALID; - - if (agent_send(agent, data, size, 0) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_send_diffserv(juice_agent_t *agent, const char *data, size_t size, int ds) { - if (!agent || (!data && size)) - return JUICE_ERR_INVALID; - - if (agent_send(agent, data, size, ds) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT juice_state_t juice_get_state(juice_agent_t *agent) { return agent_get_state(agent); } - -JUICE_EXPORT int juice_get_selected_candidates(juice_agent_t *agent, char *local, size_t local_size, - char *remote, size_t remote_size) { - if (!agent || (!local && local_size) || (!remote && remote_size)) - return JUICE_ERR_INVALID; - - ice_candidate_t local_cand, remote_cand; - if (agent_get_selected_candidate_pair(agent, &local_cand, &remote_cand)) - return JUICE_ERR_NOT_AVAIL; - - if (local_size && ice_generate_candidate_sdp(&local_cand, local, local_size) < 0) - return JUICE_ERR_FAILED; - - if (remote_size && ice_generate_candidate_sdp(&remote_cand, remote, remote_size) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT int juice_get_selected_addresses(juice_agent_t *agent, char *local, size_t local_size, - char *remote, size_t remote_size) { - if (!agent || (!local && local_size) || (!remote && remote_size)) - return JUICE_ERR_INVALID; - - ice_candidate_t local_cand, remote_cand; - if (agent_get_selected_candidate_pair(agent, &local_cand, &remote_cand)) - return JUICE_ERR_NOT_AVAIL; - - if (local_size && addr_record_to_string(&local_cand.resolved, local, local_size) < 0) - return JUICE_ERR_FAILED; - - if (remote_size && addr_record_to_string(&remote_cand.resolved, remote, remote_size) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -} - -JUICE_EXPORT const char *juice_state_to_string(juice_state_t state) { - switch (state) { - case JUICE_STATE_DISCONNECTED: - return "disconnected"; - case JUICE_STATE_GATHERING: - return "gathering"; - case JUICE_STATE_CONNECTING: - return "connecting"; - case JUICE_STATE_CONNECTED: - return "connected"; - case JUICE_STATE_COMPLETED: - return "completed"; - case JUICE_STATE_FAILED: - return "failed"; - default: - return "unknown"; - } -} - -JUICE_EXPORT juice_server_t *juice_server_create(const juice_server_config_t *config) { -#ifndef NO_SERVER - if (!config) - return NULL; - - return server_create(config); -#else - (void)config; - JLOG_FATAL("The library was compiled without server support"); - return NULL; -#endif -} - -JUICE_EXPORT void juice_server_destroy(juice_server_t *server) { -#ifndef NO_SERVER - if (server) - server_destroy(server); -#else - (void)server; -#endif -} - -JUICE_EXPORT uint16_t juice_server_get_port(juice_server_t *server) { -#ifndef NO_SERVER - return server ? server_get_port(server) : 0; -#else - (void)server; - return 0; -#endif -} - -JUICE_EXPORT int juice_server_add_credentials(juice_server_t *server, - const juice_server_credentials_t *credentials, - unsigned long lifetime_ms) { -#ifndef NO_SERVER - if (!server || !credentials) - return JUICE_ERR_INVALID; - - if (server_add_credentials(server, credentials, (timediff_t)lifetime_ms) < 0) - return JUICE_ERR_FAILED; - - return JUICE_ERR_SUCCESS; -#else - (void)server; - (void)credentials; - (void)lifetime_ms; - return JUICE_ERR_INVALID; -#endif -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/log.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/log.c deleted file mode 100644 index 2de7a2f0..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/log.c +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if !defined(GODOT_JUICE_DISABLE_LOG) - -#include "log.h" -#include "thread.h" // for mutexes and atomics - -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#define BUFFER_SIZE 4096 - -static const char *log_level_names[] = {"VERBOSE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"}; - -static const char *log_level_colors[] = { - "\x1B[90m", // grey - "\x1B[96m", // cyan - "\x1B[39m", // default foreground - "\x1B[93m", // yellow - "\x1B[91m", // red - "\x1B[97m\x1B[41m" // white on red -}; - -static mutex_t log_mutex = MUTEX_INITIALIZER; -static volatile juice_log_cb_t log_cb = NULL; -static atomic(juice_log_level_t) log_level = ATOMIC_VAR_INIT(JUICE_LOG_LEVEL_WARN); - -static bool use_color(void) { -#ifdef _WIN32 - return false; -#else - return isatty(fileno(stdout)) != 0; -#endif -} - -static int get_localtime(const time_t *t, struct tm *buf) { -#ifdef _WIN32 - // Windows does not have POSIX localtime_r... - return localtime_s(buf, t) == 0 ? 0 : -1; -#else // POSIX - return localtime_r(t, buf) != NULL ? 0 : -1; -#endif -} - -JUICE_EXPORT void juice_set_log_level(juice_log_level_t level) { atomic_store(&log_level, level); } - -JUICE_EXPORT void juice_set_log_handler(juice_log_cb_t cb) { - mutex_lock(&log_mutex); - log_cb = cb; - mutex_unlock(&log_mutex); -} - -bool juice_log_is_enabled(juice_log_level_t level) { - return level != JUICE_LOG_LEVEL_NONE && level >= atomic_load(&log_level); -} - -void juice_log_write(juice_log_level_t level, const char *file, int line, const char *fmt, ...) { - if (!juice_log_is_enabled(level)) - return; - - mutex_lock(&log_mutex); - -#if !RELEASE - const char *filename = file + strlen(file); - while (filename != file && *filename != '/' && *filename != '\\') - --filename; - if (filename != file) - ++filename; -#else - (void)file; - (void)line; -#endif - - if (log_cb) { - char message[BUFFER_SIZE]; - int len = 0; -#if !RELEASE - len = snprintf(message, BUFFER_SIZE, "%s:%d: ", filename, line); - if (len < 0) - goto __exit; -#endif - if (len < BUFFER_SIZE) { - va_list args; - va_start(args, fmt); - vsnprintf(message + len, BUFFER_SIZE - len, fmt, args); - va_end(args); - } - - log_cb(level, message); - - } else { - time_t t = time(NULL); - struct tm lt; - char buffer[16]; - if (get_localtime(&t, <) != 0 || strftime(buffer, 16, "%H:%M:%S", <) == 0) - buffer[0] = '\0'; - - if (use_color()) - fprintf(stdout, "%s", log_level_colors[level]); - - fprintf(stdout, "%s %-7s ", buffer, log_level_names[level]); - -#if !RELEASE - fprintf(stdout, "%s:%d: ", filename, line); -#endif - - va_list args; - va_start(args, fmt); - vfprintf(stdout, fmt, args); - va_end(args); - - if (use_color()) - fprintf(stdout, "%s", "\x1B[0m\x1B[0K"); - - fprintf(stdout, "\n"); - fflush(stdout); - } - -__exit: - mutex_unlock(&log_mutex); -} - -#else // !defined(GODOT_JUICE_DISABLE_LOG) - -#include "juice.h" - -JUICE_EXPORT void juice_set_log_level(juice_log_level_t level) { } - -JUICE_EXPORT void juice_set_log_handler(juice_log_cb_t cb) { } - -#endif // defined(GODOT_JUICE_DISABLE_LOG) diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/log.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/log.h deleted file mode 100644 index 3f5485fa..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/log.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_LOG_H -#define JUICE_LOG_H - -#include "juice.h" - -#include - -#if !defined(GODOT_JUICE_DISABLE_LOG) - -bool juice_log_is_enabled(juice_log_level_t level); -void juice_log_write(juice_log_level_t level, const char *file, int line, const char *fmt, ...); - -#else // !defined(GODOT_JUICE_DISABLE_LOG) - -inline bool juice_log_is_enabled(juice_log_level_t level) { return false; } -inline void juice_log_write(juice_log_level_t level, const char *file, int line, const char *fmt, ...) { } - -#endif // defined(GODOT_JUICE_DEBUG_LOG) - -#define JLOG_VERBOSE(...) juice_log_write(JUICE_LOG_LEVEL_VERBOSE, __FILE__, __LINE__, __VA_ARGS__) -#define JLOG_DEBUG(...) juice_log_write(JUICE_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) -#define JLOG_INFO(...) juice_log_write(JUICE_LOG_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__) -#define JLOG_WARN(...) juice_log_write(JUICE_LOG_LEVEL_WARN, __FILE__, __LINE__, __VA_ARGS__) -#define JLOG_ERROR(...) juice_log_write(JUICE_LOG_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__) -#define JLOG_FATAL(...) juice_log_write(JUICE_LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__) - -#define JLOG_VERBOSE_ENABLED juice_log_is_enabled(JUICE_LOG_LEVEL_VERBOSE) -#define JLOG_DEBUG_ENABLED juice_log_is_enabled(JUICE_LOG_LEVEL_DEBUG) -#define JLOG_INFO_ENABLED juice_log_is_enabled(JUICE_LOG_LEVEL_INFO) -#define JLOG_WARN_ENABLED juice_log_is_enabled(JUICE_LOG_LEVEL_WARN) -#define JLOG_ERROR_ENABLED juice_log_is_enabled(JUICE_LOG_LEVEL_ERROR) -#define JLOG_FATAL_ENABLED juice_log_is_enabled(JUICE_LOG_LEVEL_FATAL) - -#endif // JUICE_LOG_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/picohash.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/picohash.h deleted file mode 100644 index 4a58374e..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/picohash.h +++ /dev/null @@ -1,741 +0,0 @@ -/** - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ -#ifndef _picohash_h_ -#define _picohash_h_ - -#include -#include -#include - -#ifdef _WIN32 -/* assume Windows is little endian */ -#elif defined __BIG_ENDIAN__ -#define _PICOHASH_BIG_ENDIAN -#elif defined __LITTLE_ENDIAN__ -/* override */ -#elif defined __BYTE_ORDER -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define _PICOHASH_BIG_ENDIAN -#endif -#else // ! defined __LITTLE_ENDIAN__ -#include // machine/endian.h -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define _PICOHASH_BIG_ENDIAN -#endif -#endif - -#define PICOHASH_MD5_BLOCK_LENGTH 64 -#define PICOHASH_MD5_DIGEST_LENGTH 16 - -typedef struct { - uint_fast32_t lo, hi; - uint_fast32_t a, b, c, d; - unsigned char buffer[64]; - uint_fast32_t block[PICOHASH_MD5_DIGEST_LENGTH]; -} _picohash_md5_ctx_t; - -static void _picohash_md5_init(_picohash_md5_ctx_t *ctx); -static void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size); -static void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *digest); - -#define PICOHASH_SHA1_BLOCK_LENGTH 64 -#define PICOHASH_SHA1_DIGEST_LENGTH 20 - -typedef struct { - uint32_t buffer[PICOHASH_SHA1_BLOCK_LENGTH / 4]; - uint32_t state[PICOHASH_SHA1_DIGEST_LENGTH / 4]; - uint64_t byteCount; - uint8_t bufferOffset; -} _picohash_sha1_ctx_t; - -static void _picohash_sha1_init(_picohash_sha1_ctx_t *ctx); -static void _picohash_sha1_update(_picohash_sha1_ctx_t *ctx, const void *input, size_t len); -static void _picohash_sha1_final(_picohash_sha1_ctx_t *ctx, void *digest); - -#define PICOHASH_SHA256_BLOCK_LENGTH 64 -#define PICOHASH_SHA256_DIGEST_LENGTH 32 -#define PICOHASH_SHA224_BLOCK_LENGTH PICOHASH_SHA256_BLOCK_LENGTH -#define PICOHASH_SHA224_DIGEST_LENGTH 28 - -typedef struct { - uint64_t length; - uint32_t state[PICOHASH_SHA256_DIGEST_LENGTH / 4]; - uint32_t curlen; - unsigned char buf[PICOHASH_SHA256_BLOCK_LENGTH]; -} _picohash_sha256_ctx_t; - -static void _picohash_sha256_init(_picohash_sha256_ctx_t *ctx); -static void _picohash_sha256_update(_picohash_sha256_ctx_t *ctx, const void *data, size_t len); -static void _picohash_sha256_final(_picohash_sha256_ctx_t *ctx, void *digest); -static void _picohash_sha224_init(_picohash_sha256_ctx_t *ctx); -static void _picohash_sha224_final(_picohash_sha256_ctx_t *ctx, void *digest); - -#define PICOHASH_MAX_BLOCK_LENGTH 64 -#define PICOHASH_MAX_DIGEST_LENGTH 32 - -typedef struct { - union { - _picohash_md5_ctx_t _md5; - _picohash_sha1_ctx_t _sha1; - _picohash_sha256_ctx_t _sha256; - }; - size_t block_length; - size_t digest_length; - void (*_reset)(void *ctx); - void (*_update)(void *ctx, const void *input, size_t len); - void (*_final)(void *ctx, void *digest); - struct { - unsigned char key[PICOHASH_MAX_BLOCK_LENGTH]; - void (*hash_reset)(void *ctx); - void (*hash_final)(void *ctx, void *digest); - } _hmac; -} picohash_ctx_t; - -static void picohash_init_md5(picohash_ctx_t *ctx); -static void picohash_init_sha1(picohash_ctx_t *ctx); -static void picohash_init_sha224(picohash_ctx_t *ctx); -static void picohash_init_sha256(picohash_ctx_t *ctx); -static void picohash_update(picohash_ctx_t *ctx, const void *input, size_t len); -static void picohash_final(picohash_ctx_t *ctx, void *digest); -static void picohash_reset(picohash_ctx_t *ctx); - -static void picohash_init_hmac(picohash_ctx_t *ctx, void (*initf)(picohash_ctx_t *), const void *key, size_t key_len); - -/* following are private definitions */ - -/* - * The basic MD5 functions. - * - * F is optimized compared to its RFC 1321 definition just like in Colin - * Plumb's implementation. - */ -#define _PICOHASH_MD5_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define _PICOHASH_MD5_G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) -#define _PICOHASH_MD5_H(x, y, z) ((x) ^ (y) ^ (z)) -#define _PICOHASH_MD5_I(x, y, z) ((y) ^ ((x) | ~(z))) - -/* - * The MD5 transformation for all four rounds. - */ -#define _PICOHASH_MD5_STEP(f, a, b, c, d, x, t, s) \ - (a) += f((b), (c), (d)) + (x) + (t); \ - (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \ - (a) += (b); - -/* - * SET reads 4 input bytes in little-endian byte order and stores them - * in a properly aligned word in host byte order. - * - * Paul-Louis Ageneau: Removed optimization for little-endian architectures - * as it resulted in incorrect behavior when compiling with gcc optimizations. - */ -#define _PICOHASH_MD5_SET(n) \ - (ctx->block[(n)] = (uint_fast32_t)ptr[(n)*4] | ((uint_fast32_t)ptr[(n)*4 + 1] << 8) | ((uint_fast32_t)ptr[(n)*4 + 2] << 16) | \ - ((uint_fast32_t)ptr[(n)*4 + 3] << 24)) -#define _PICOHASH_MD5_GET(n) (ctx->block[(n)]) - -/* - * This processes one or more 64-byte data blocks, but does NOT update - * the bit counters. There're no alignment requirements. - */ -static const void *_picohash_md5_body(_picohash_md5_ctx_t *ctx, const void *data, size_t size) -{ - const unsigned char *ptr; - uint_fast32_t a, b, c, d; - uint_fast32_t saved_a, saved_b, saved_c, saved_d; - - ptr = data; - - a = ctx->a; - b = ctx->b; - c = ctx->c; - d = ctx->d; - - do { - saved_a = a; - saved_b = b; - saved_c = c; - saved_d = d; - - /* Round 1 */ - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(0), 0xd76aa478, 7) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(1), 0xe8c7b756, 12) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(2), 0x242070db, 17) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(3), 0xc1bdceee, 22) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(4), 0xf57c0faf, 7) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(5), 0x4787c62a, 12) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(6), 0xa8304613, 17) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(7), 0xfd469501, 22) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(8), 0x698098d8, 7) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(9), 0x8b44f7af, 12) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(10), 0xffff5bb1, 17) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(11), 0x895cd7be, 22) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(12), 0x6b901122, 7) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(13), 0xfd987193, 12) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(14), 0xa679438e, 17) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(15), 0x49b40821, 22) - - /* Round 2 */ - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(1), 0xf61e2562, 5) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(6), 0xc040b340, 9) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(11), 0x265e5a51, 14) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(0), 0xe9b6c7aa, 20) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(5), 0xd62f105d, 5) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(10), 0x02441453, 9) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(15), 0xd8a1e681, 14) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(4), 0xe7d3fbc8, 20) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(9), 0x21e1cde6, 5) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(14), 0xc33707d6, 9) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(3), 0xf4d50d87, 14) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(8), 0x455a14ed, 20) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(13), 0xa9e3e905, 5) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(2), 0xfcefa3f8, 9) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(7), 0x676f02d9, 14) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(12), 0x8d2a4c8a, 20) - - /* Round 3 */ - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(5), 0xfffa3942, 4) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(8), 0x8771f681, 11) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(11), 0x6d9d6122, 16) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(14), 0xfde5380c, 23) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(1), 0xa4beea44, 4) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(4), 0x4bdecfa9, 11) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(7), 0xf6bb4b60, 16) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(10), 0xbebfbc70, 23) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(13), 0x289b7ec6, 4) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(0), 0xeaa127fa, 11) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(3), 0xd4ef3085, 16) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(6), 0x04881d05, 23) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(9), 0xd9d4d039, 4) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(12), 0xe6db99e5, 11) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(15), 0x1fa27cf8, 16) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(2), 0xc4ac5665, 23) - - /* Round 4 */ - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(0), 0xf4292244, 6) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(7), 0x432aff97, 10) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(14), 0xab9423a7, 15) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(5), 0xfc93a039, 21) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(12), 0x655b59c3, 6) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(3), 0x8f0ccc92, 10) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(10), 0xffeff47d, 15) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(1), 0x85845dd1, 21) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(8), 0x6fa87e4f, 6) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(15), 0xfe2ce6e0, 10) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(6), 0xa3014314, 15) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(13), 0x4e0811a1, 21) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(4), 0xf7537e82, 6) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(11), 0xbd3af235, 10) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(2), 0x2ad7d2bb, 15) - _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(9), 0xeb86d391, 21) - - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; - - ptr += 64; - } while (size -= 64); - - ctx->a = a; - ctx->b = b; - ctx->c = c; - ctx->d = d; - - return ptr; -} - -inline void _picohash_md5_init(_picohash_md5_ctx_t *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - - ctx->lo = 0; - ctx->hi = 0; -} - -inline void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size) -{ - uint_fast32_t saved_lo; - unsigned long used, free; - - saved_lo = ctx->lo; - if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) - ctx->hi++; - ctx->hi += (uint_fast32_t)(size >> 29); - - used = saved_lo & 0x3f; - - if (used) { - free = 64 - used; - - if (size < free) { - memcpy(&ctx->buffer[used], data, size); - return; - } - - memcpy(&ctx->buffer[used], data, free); - data = (const unsigned char *)data + free; - size -= free; - _picohash_md5_body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = _picohash_md5_body(ctx, data, size & ~(unsigned long)0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - -inline void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *_digest) -{ - unsigned char *digest = _digest; - unsigned long used, free; - - used = ctx->lo & 0x3f; - - ctx->buffer[used++] = 0x80; - - free = 64 - used; - - if (free < 8) { - memset(&ctx->buffer[used], 0, free); - _picohash_md5_body(ctx, ctx->buffer, 64); - used = 0; - free = 64; - } - - memset(&ctx->buffer[used], 0, free - 8); - - ctx->lo <<= 3; - ctx->buffer[56] = ctx->lo; - ctx->buffer[57] = ctx->lo >> 8; - ctx->buffer[58] = ctx->lo >> 16; - ctx->buffer[59] = ctx->lo >> 24; - ctx->buffer[60] = ctx->hi; - ctx->buffer[61] = ctx->hi >> 8; - ctx->buffer[62] = ctx->hi >> 16; - ctx->buffer[63] = ctx->hi >> 24; - - _picohash_md5_body(ctx, ctx->buffer, 64); - - digest[0] = ctx->a; - digest[1] = ctx->a >> 8; - digest[2] = ctx->a >> 16; - digest[3] = ctx->a >> 24; - digest[4] = ctx->b; - digest[5] = ctx->b >> 8; - digest[6] = ctx->b >> 16; - digest[7] = ctx->b >> 24; - digest[8] = ctx->c; - digest[9] = ctx->c >> 8; - digest[10] = ctx->c >> 16; - digest[11] = ctx->c >> 24; - digest[12] = ctx->d; - digest[13] = ctx->d >> 8; - digest[14] = ctx->d >> 16; - digest[15] = ctx->d >> 24; - - memset(ctx, 0, sizeof(*ctx)); -} - -#define _PICOHASH_SHA1_K0 0x5a827999 -#define _PICOHASH_SHA1_K20 0x6ed9eba1 -#define _PICOHASH_SHA1_K40 0x8f1bbcdc -#define _PICOHASH_SHA1_K60 0xca62c1d6 - -static inline uint32_t _picohash_sha1_rol32(uint32_t number, uint8_t bits) -{ - return ((number << bits) | (number >> (32 - bits))); -} - -static inline void _picohash_sha1_hash_block(_picohash_sha1_ctx_t *s) -{ - uint8_t i; - uint32_t a, b, c, d, e, t; - - a = s->state[0]; - b = s->state[1]; - c = s->state[2]; - d = s->state[3]; - e = s->state[4]; - for (i = 0; i < 80; i++) { - if (i >= 16) { - t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^ s->buffer[(i + 2) & 15] ^ s->buffer[i & 15]; - s->buffer[i & 15] = _picohash_sha1_rol32(t, 1); - } - if (i < 20) { - t = (d ^ (b & (c ^ d))) + _PICOHASH_SHA1_K0; - } else if (i < 40) { - t = (b ^ c ^ d) + _PICOHASH_SHA1_K20; - } else if (i < 60) { - t = ((b & c) | (d & (b | c))) + _PICOHASH_SHA1_K40; - } else { - t = (b ^ c ^ d) + _PICOHASH_SHA1_K60; - } - t += _picohash_sha1_rol32(a, 5) + e + s->buffer[i & 15]; - e = d; - d = c; - c = _picohash_sha1_rol32(b, 30); - b = a; - a = t; - } - s->state[0] += a; - s->state[1] += b; - s->state[2] += c; - s->state[3] += d; - s->state[4] += e; -} - -static inline void _picohash_sha1_add_uncounted(_picohash_sha1_ctx_t *s, uint8_t data) -{ - uint8_t *const b = (uint8_t *)s->buffer; -#ifdef _PICOHASH_BIG_ENDIAN - b[s->bufferOffset] = data; -#else - b[s->bufferOffset ^ 3] = data; -#endif - s->bufferOffset++; - if (s->bufferOffset == PICOHASH_SHA1_BLOCK_LENGTH) { - _picohash_sha1_hash_block(s); - s->bufferOffset = 0; - } -} - -inline void _picohash_sha1_init(_picohash_sha1_ctx_t *s) -{ - s->state[0] = 0x67452301; - s->state[1] = 0xefcdab89; - s->state[2] = 0x98badcfe; - s->state[3] = 0x10325476; - s->state[4] = 0xc3d2e1f0; - s->byteCount = 0; - s->bufferOffset = 0; -} - -inline void _picohash_sha1_update(_picohash_sha1_ctx_t *s, const void *_data, size_t len) -{ - const uint8_t *data = _data; - for (; len != 0; --len) { - ++s->byteCount; - _picohash_sha1_add_uncounted(s, *data++); - } -} - -inline void _picohash_sha1_final(_picohash_sha1_ctx_t *s, void *digest) -{ - // Pad with 0x80 followed by 0x00 until the end of the block - _picohash_sha1_add_uncounted(s, 0x80); - while (s->bufferOffset != 56) - _picohash_sha1_add_uncounted(s, 0x00); - - // Append length in the last 8 bytes - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 53)); // Shifting to multiply by 8 - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 45)); // as SHA-1 supports bitstreams - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 37)); // as well as byte. - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 29)); - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 21)); - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 13)); - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount >> 5)); - _picohash_sha1_add_uncounted(s, (uint8_t)(s->byteCount << 3)); - -#ifndef SHA_BIG_ENDIAN - { // Swap byte order back - int i; - for (i = 0; i < 5; i++) { - s->state[i] = (((s->state[i]) << 24) & 0xff000000) | (((s->state[i]) << 8) & 0x00ff0000) | - (((s->state[i]) >> 8) & 0x0000ff00) | (((s->state[i]) >> 24) & 0x000000ff); - } - } -#endif - - memcpy(digest, s->state, sizeof(s->state)); -} - -#define _picohash_sha256_ch(x, y, z) (z ^ (x & (y ^ z))) -#define _picohash_sha256_maj(x, y, z) (((x | y) & z) | (x & y)) -#define _picohash_sha256_s(x, y) \ - (((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | ((uint32_t)(x) << (uint32_t)(32 - ((y)&31)))) & 0xFFFFFFFFUL) -#define _picohash_sha256_r(x, n) (((x)&0xFFFFFFFFUL) >> (n)) -#define _picohash_sha256_sigma0(x) (_picohash_sha256_s(x, 2) ^ _picohash_sha256_s(x, 13) ^ _picohash_sha256_s(x, 22)) -#define _picohash_sha256_sigma1(x) (_picohash_sha256_s(x, 6) ^ _picohash_sha256_s(x, 11) ^ _picohash_sha256_s(x, 25)) -#define _picohash_sha256_gamma0(x) (_picohash_sha256_s(x, 7) ^ _picohash_sha256_s(x, 18) ^ _picohash_sha256_r(x, 3)) -#define _picohash_sha256_gamma1(x) (_picohash_sha256_s(x, 17) ^ _picohash_sha256_s(x, 19) ^ _picohash_sha256_r(x, 10)) -#define _picohash_sha256_rnd(a, b, c, d, e, f, g, h, i) \ - t0 = h + _picohash_sha256_sigma1(e) + _picohash_sha256_ch(e, f, g) + K[i] + W[i]; \ - t1 = _picohash_sha256_sigma0(a) + _picohash_sha256_maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - -static inline void _picohash_sha256_compress(_picohash_sha256_ctx_t *ctx, unsigned char *buf) -{ - static const uint32_t K[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; - uint32_t S[8], W[64], t, t0, t1; - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) - S[i] = ctx->state[i]; - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) - W[i] = - (uint32_t)buf[4 * i] << 24 | (uint32_t)buf[4 * i + 1] << 16 | (uint32_t)buf[4 * i + 2] << 8 | (uint32_t)buf[4 * i + 3]; - - /* fill W[16..63] */ - for (i = 16; i < 64; i++) - W[i] = _picohash_sha256_gamma1(W[i - 2]) + W[i - 7] + _picohash_sha256_gamma0(W[i - 15]) + W[i - 16]; - - /* Compress */ - for (i = 0; i < 64; ++i) { - _picohash_sha256_rnd(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); - t = S[7]; - S[7] = S[6]; - S[6] = S[5]; - S[5] = S[4]; - S[4] = S[3]; - S[3] = S[2]; - S[2] = S[1]; - S[1] = S[0]; - S[0] = t; - } - - /* feedback */ - for (i = 0; i < 8; i++) - ctx->state[i] = ctx->state[i] + S[i]; -} - -static inline void _picohash_sha256_do_final(_picohash_sha256_ctx_t *ctx, void *digest, size_t len) -{ - unsigned char *out = digest; - size_t i; - - /* increase the length of the message */ - ctx->length += ctx->curlen * 8; - - /* append the '1' bit */ - ctx->buf[ctx->curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (ctx->curlen > 56) { - while (ctx->curlen < 64) { - ctx->buf[ctx->curlen++] = (unsigned char)0; - } - _picohash_sha256_compress(ctx, ctx->buf); - ctx->curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (ctx->curlen < 56) { - ctx->buf[ctx->curlen++] = (unsigned char)0; - } - - /* store length */ - for (i = 0; i != 8; ++i) - ctx->buf[56 + i] = (unsigned char)(ctx->length >> (56 - 8 * i)); - _picohash_sha256_compress(ctx, ctx->buf); - - /* copy output */ - for (i = 0; i != len / 4; ++i) { - out[i * 4] = ctx->state[i] >> 24; - out[i * 4 + 1] = ctx->state[i] >> 16; - out[i * 4 + 2] = ctx->state[i] >> 8; - out[i * 4 + 3] = ctx->state[i]; - } -} - -inline void _picohash_sha256_init(_picohash_sha256_ctx_t *ctx) -{ - ctx->curlen = 0; - ctx->length = 0; - ctx->state[0] = 0x6A09E667UL; - ctx->state[1] = 0xBB67AE85UL; - ctx->state[2] = 0x3C6EF372UL; - ctx->state[3] = 0xA54FF53AUL; - ctx->state[4] = 0x510E527FUL; - ctx->state[5] = 0x9B05688CUL; - ctx->state[6] = 0x1F83D9ABUL; - ctx->state[7] = 0x5BE0CD19UL; -} - -inline void _picohash_sha256_update(_picohash_sha256_ctx_t *ctx, const void *data, size_t len) -{ - const unsigned char *in = data; - size_t n; - - while (len > 0) { - if (ctx->curlen == 0 && len >= PICOHASH_SHA256_BLOCK_LENGTH) { - _picohash_sha256_compress(ctx, (unsigned char *)in); - ctx->length += PICOHASH_SHA256_BLOCK_LENGTH * 8; - in += PICOHASH_SHA256_BLOCK_LENGTH; - len -= PICOHASH_SHA256_BLOCK_LENGTH; - } else { - n = PICOHASH_SHA256_BLOCK_LENGTH - ctx->curlen; - if (n > len) - n = len; - memcpy(ctx->buf + ctx->curlen, in, n); - ctx->curlen += (uint32_t)n; - in += n; - len -= n; - if (ctx->curlen == 64) { - _picohash_sha256_compress(ctx, ctx->buf); - ctx->length += 8 * PICOHASH_SHA256_BLOCK_LENGTH; - ctx->curlen = 0; - } - } - } -} - -inline void _picohash_sha256_final(_picohash_sha256_ctx_t *ctx, void *digest) -{ - _picohash_sha256_do_final(ctx, digest, PICOHASH_SHA256_DIGEST_LENGTH); -} - -inline void _picohash_sha224_init(_picohash_sha256_ctx_t *ctx) -{ - ctx->curlen = 0; - ctx->length = 0; - ctx->state[0] = 0xc1059ed8UL; - ctx->state[1] = 0x367cd507UL; - ctx->state[2] = 0x3070dd17UL; - ctx->state[3] = 0xf70e5939UL; - ctx->state[4] = 0xffc00b31UL; - ctx->state[5] = 0x68581511UL; - ctx->state[6] = 0x64f98fa7UL; - ctx->state[7] = 0xbefa4fa4UL; -} - -inline void _picohash_sha224_final(_picohash_sha256_ctx_t *ctx, void *digest) -{ - _picohash_sha256_do_final(ctx, digest, PICOHASH_SHA224_DIGEST_LENGTH); -} - -inline void picohash_init_md5(picohash_ctx_t *ctx) -{ - ctx->block_length = PICOHASH_MD5_BLOCK_LENGTH; - ctx->digest_length = PICOHASH_MD5_DIGEST_LENGTH; - ctx->_reset = (void *)_picohash_md5_init; - ctx->_update = (void *)_picohash_md5_update; - ctx->_final = (void *)_picohash_md5_final; - - _picohash_md5_init(&ctx->_md5); -} - -inline void picohash_init_sha1(picohash_ctx_t *ctx) -{ - ctx->block_length = PICOHASH_SHA1_BLOCK_LENGTH; - ctx->digest_length = PICOHASH_SHA1_DIGEST_LENGTH; - ctx->_reset = (void *)_picohash_sha1_init; - ctx->_update = (void *)_picohash_sha1_update; - ctx->_final = (void *)_picohash_sha1_final; - _picohash_sha1_init(&ctx->_sha1); -} - -inline void picohash_init_sha224(picohash_ctx_t *ctx) -{ - ctx->block_length = PICOHASH_SHA224_BLOCK_LENGTH; - ctx->digest_length = PICOHASH_SHA224_DIGEST_LENGTH; - ctx->_reset = (void *)_picohash_sha224_init; - ctx->_update = (void *)_picohash_sha256_update; - ctx->_final = (void *)_picohash_sha224_final; - _picohash_sha224_init(&ctx->_sha256); -} - -inline void picohash_init_sha256(picohash_ctx_t *ctx) -{ - ctx->block_length = PICOHASH_SHA256_BLOCK_LENGTH; - ctx->digest_length = PICOHASH_SHA256_DIGEST_LENGTH; - ctx->_reset = (void *)_picohash_sha256_init; - ctx->_update = (void *)_picohash_sha256_update; - ctx->_final = (void *)_picohash_sha256_final; - _picohash_sha256_init(&ctx->_sha256); -} - -inline void picohash_update(picohash_ctx_t *ctx, const void *input, size_t len) -{ - ctx->_update(ctx, input, len); -} - -inline void picohash_final(picohash_ctx_t *ctx, void *digest) -{ - ctx->_final(ctx, digest); -} - -inline void picohash_reset(picohash_ctx_t *ctx) -{ - ctx->_reset(ctx); -} - -static inline void _picohash_hmac_apply_key(picohash_ctx_t *ctx, unsigned char delta) -{ - size_t i; - for (i = 0; i != ctx->block_length; ++i) - ctx->_hmac.key[i] ^= delta; - picohash_update(ctx, ctx->_hmac.key, ctx->block_length); - for (i = 0; i != ctx->block_length; ++i) - ctx->_hmac.key[i] ^= delta; -} - -static void _picohash_hmac_final(picohash_ctx_t *ctx, void *digest) -{ - unsigned char inner_digest[PICOHASH_MAX_DIGEST_LENGTH]; - - ctx->_hmac.hash_final(ctx, inner_digest); - - ctx->_hmac.hash_reset(ctx); - _picohash_hmac_apply_key(ctx, 0x5c); - picohash_update(ctx, inner_digest, ctx->digest_length); - memset(inner_digest, 0, ctx->digest_length); - - ctx->_hmac.hash_final(ctx, digest); -} - -static inline void _picohash_hmac_reset(picohash_ctx_t *ctx) -{ - ctx->_hmac.hash_reset(ctx); - _picohash_hmac_apply_key(ctx, 0x36); -} - -inline void picohash_init_hmac(picohash_ctx_t *ctx, void (*initf)(picohash_ctx_t *), const void *key, size_t key_len) -{ - initf(ctx); - - memset(ctx->_hmac.key, 0, ctx->block_length); - if (key_len > ctx->block_length) { - /* hash the key if it is too long */ - picohash_update(ctx, key, key_len); - picohash_final(ctx, ctx->_hmac.key); - ctx->_hmac.hash_reset(ctx); - } else { - memcpy(ctx->_hmac.key, key, key_len); - } - - /* replace reset and final function */ - ctx->_hmac.hash_reset = ctx->_reset; - ctx->_hmac.hash_final = ctx->_final; - ctx->_reset = (void *)_picohash_hmac_reset; - ctx->_final = (void *)_picohash_hmac_final; - - /* start calculating the inner hash */ - _picohash_hmac_apply_key(ctx, 0x36); -} - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/random.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/random.c deleted file mode 100644 index 46bd8f85..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/random.c +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "random.h" -#include "log.h" -#include "thread.h" // for mutexes - -#include -#include -#include - -// getrandom() is not available in Android NDK API < 28 and needs glibc >= 2.25 -#if defined(__linux__) && !defined(__ANDROID__) && (!defined(__GLIBC__) || __GLIBC__ > 2 || __GLIBC_MINOR__ >= 25) - -#include -#include - -static int random_bytes(void *buf, size_t size) { - ssize_t ret = getrandom(buf, size, 0); - if (ret < 0) { - JLOG_WARN("getrandom failed, errno=%d", errno); - return -1; - } - if ((size_t)ret < size) { - JLOG_WARN("getrandom returned too few bytes, size=%zu, returned=%zu", size, (size_t)ret); - return -1; - } - return 0; -} - -#elif defined(_WIN32) - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 // Windows 7 -#endif - -#include -// -#include - -static int random_bytes(void *buf, size_t size) { - // Requires Windows 7 or later - NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); - return !status ? 0 : -1; -} - -#else -static int random_bytes(void *buf, size_t size) { - (void)buf; - (void)size; - return -1; -} -#endif - -static unsigned int generate_seed() { -#ifdef _WIN32 - return (unsigned int)GetTickCount(); -#else - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) == 0) - return (unsigned int)(ts.tv_sec ^ ts.tv_nsec); - else - return (unsigned int)time(NULL); -#endif -} - -void juice_random(void *buf, size_t size) { - if (random_bytes(buf, size) == 0) - return; - - // rand() is not thread-safe - static mutex_t rand_mutex = MUTEX_INITIALIZER; - mutex_lock(&rand_mutex); - - static bool srandom_called = false; -#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) -#define random_func random -#define srandom_func srandom - if (!srandom_called) - JLOG_DEBUG("Using random() for random bytes"); -#else -#define random_func rand -#define srandom_func srand - if (!srandom_called) - JLOG_WARN("Falling back on rand() for random bytes"); -#endif - if (!srandom_called) { - srandom_func(generate_seed()); - srandom_called = true; - } - // RAND_MAX is guaranteed to be at least 2^15 - 1 - uint8_t *bytes = buf; - for (size_t i = 0; i < size; ++i) - bytes[i] = (uint8_t)((random_func() & 0x7f80) >> 7); - - mutex_unlock(&rand_mutex); -} - -void juice_random_str64(char *buf, size_t size) { - static const char chars64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - size_t i = 0; - for (i = 0; i + 1 < size; ++i) { - uint8_t byte = 0; - juice_random(&byte, 1); - buf[i] = chars64[byte & 0x3F]; - } - buf[i] = '\0'; -} - -uint32_t juice_rand32(void) { - uint32_t r = 0; - juice_random(&r, sizeof(r)); - return r; -} - -uint64_t juice_rand64(void) { - uint64_t r = 0; - juice_random(&r, sizeof(r)); - return r; -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/random.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/random.h deleted file mode 100644 index 2985d871..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/random.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_RANDOM_H -#define JUICE_RANDOM_H - -#include -#include - -void juice_random(void *buf, size_t size); -void juice_random_str64(char *buf, size_t size); - -uint32_t juice_rand32(void); -uint64_t juice_rand64(void); - -#endif // JUICE_RANDOM_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/server.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/server.c deleted file mode 100644 index f4f28fa5..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/server.c +++ /dev/null @@ -1,1144 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef NO_SERVER - -#include "server.h" -#include "const_time.h" -#include "hmac.h" -#include "ice.h" -#include "juice.h" -#include "log.h" -#include "random.h" -#include "stun.h" -#include "turn.h" -#include "udp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -#define ALLOCATION_LIFETIME 600000 // ms - -// RFC 8656: The Permission Lifetime MUST be 300 seconds (= 5 minutes) -#define PERMISSION_LIFETIME 300000 // ms - -// RFC 8656: Channel bindings last for 10 minutes unless refreshed -#define BIND_LIFETIME 600000 // ms - -#define MAX_RELAYED_RECORDS_COUNT 8 -#define BUFFER_SIZE 4096 - -static char *alloc_string_copy(const char *orig, bool *alloc_failed) { - if (!orig) - return NULL; - - char *copy = malloc(strlen(orig) + 1); - if (!copy) { - if (alloc_failed) - *alloc_failed = true; - - return NULL; - } - strcpy(copy, orig); - return copy; -} - -static server_turn_alloc_t *find_allocation(server_turn_alloc_t allocs[], int size, - const addr_record_t *record, bool allow_deleted) { - unsigned long key = addr_record_hash(record, true) % size; - unsigned long pos = key; - while (!(allocs[pos].state == SERVER_TURN_ALLOC_EMPTY || - (allow_deleted && allocs[pos].state == SERVER_TURN_ALLOC_DELETED) || - addr_record_is_equal(&allocs[pos].record, record, true))) { - pos = (pos + 1) % size; - if (pos == key) { - JLOG_VERBOSE("TURN allocation map is full"); - return NULL; - } - } - return allocs + pos; -} - -static void delete_allocation(server_turn_alloc_t *alloc) { - if (alloc->state != SERVER_TURN_ALLOC_FULL) - return; - - ++alloc->credentials->allocations_quota; - - alloc->state = SERVER_TURN_ALLOC_DELETED; - turn_destroy_map(&alloc->map); - closesocket(alloc->sock); - alloc->sock = INVALID_SOCKET; - alloc->credentials = NULL; -} - -static thread_return_t THREAD_CALL server_thread_entry(void *arg) { - thread_set_name_self("juice server"); - server_run((juice_server_t *)arg); - return (thread_return_t)0; -} - -juice_server_t *server_create(const juice_server_config_t *config) { - JLOG_VERBOSE("Creating server"); - -#ifdef _WIN32 - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { - JLOG_FATAL("WSAStartup failed"); - return NULL; - } -#endif - - juice_server_t *server = calloc(1, sizeof(juice_server_t)); - if (!server) { - JLOG_FATAL("Memory allocation for server data failed"); - return NULL; - } - - udp_socket_config_t socket_config; - memset(&socket_config, 0, sizeof(socket_config)); - socket_config.bind_address = config->bind_address; - socket_config.port_begin = config->port; - socket_config.port_end = config->port; - - server->sock = udp_create_socket(&socket_config); - if (server->sock == INVALID_SOCKET) { - JLOG_FATAL("Server socket opening failed"); - free(server); - return NULL; - } - - mutex_init(&server->mutex, MUTEX_RECURSIVE); - - bool alloc_failed = false; - server->config.max_allocations = - config->max_allocations > 0 ? config->max_allocations : SERVER_DEFAULT_MAX_ALLOCATIONS; - server->config.max_peers = config->max_peers; - server->config.bind_address = alloc_string_copy(config->bind_address, &alloc_failed); - server->config.external_address = alloc_string_copy(config->external_address, &alloc_failed); - server->config.port = config->port; - server->config.relay_port_range_begin = config->relay_port_range_begin; - server->config.relay_port_range_end = config->relay_port_range_end; - server->config.realm = alloc_string_copy( - config->realm && *config->realm != '\0' ? config->realm : SERVER_DEFAULT_REALM, - &alloc_failed); - if (alloc_failed) { - JLOG_FATAL("Memory allocation for server configuration failed"); - goto error; - } - - // Don't copy credentials but process them - server->config.credentials = NULL; - server->config.credentials_count = 0; - if (config->credentials_count <= 0) { - // TURN disabled - JLOG_INFO("TURN relaying disabled, STUN-only mode"); - server->allocs = NULL; - server->allocs_count = 0; - - } else { - // TURN enabled - server->allocs = calloc(server->config.max_allocations, sizeof(server_turn_alloc_t)); - if (!server->allocs) { - JLOG_FATAL("Memory allocation for TURN allocation table failed"); - goto error; - } - server->allocs_count = (int)server->config.max_allocations; - - for (int i = 0; i < config->credentials_count; ++i) { - juice_server_credentials_t *credentials = config->credentials + i; - if (server->config.max_allocations < credentials->allocations_quota) - server->config.max_allocations = credentials->allocations_quota; - - if (!server_do_add_credentials(server, credentials, 0)) { // never expires - JLOG_FATAL("Failed to add TURN credentials"); - goto error; - } - } - - juice_credentials_list_t *node = server->credentials; - while (node) { - juice_server_credentials_t *credentials = &node->credentials; - if (credentials->allocations_quota == 0) // unlimited - credentials->allocations_quota = server->config.max_allocations; - - node = node->next; - } - } - - server->config.port = udp_get_port(server->sock); - server->nonce_key_timestamp = 0; - if (server->config.max_peers == 0) - server->config.max_peers = SERVER_DEFAULT_MAX_PEERS; - - if (server->config.bind_address) - JLOG_INFO("Created server on %s:%hu", server->config.bind_address, server->config.port); - else - JLOG_INFO("Created server on port %hu", server->config.port); - - int ret = thread_init(&server->thread, server_thread_entry, server); - if (ret) { - JLOG_FATAL("Thread creation failed, error=%d", ret); - goto error; - } - - return server; - -error: - server_do_destroy(server); - return NULL; -} - -void server_do_destroy(juice_server_t *server) { - JLOG_DEBUG("Destroying server"); - - closesocket(server->sock); - mutex_destroy(&server->mutex); - - server_turn_alloc_t *end = server->allocs + server->allocs_count; - for (server_turn_alloc_t *alloc = server->allocs; alloc < end; ++alloc) { - delete_allocation(alloc); - } - free((void *)server->allocs); - - juice_credentials_list_t *node = server->credentials; - while (node) { - juice_credentials_list_t *prev = node; - node = node->next; - free((void *)prev->credentials.username); - free((void *)prev->credentials.password); - free(prev); - } - - free((void *)server->config.bind_address); - free((void *)server->config.external_address); - free((void *)server->config.realm); - free(server); - -#ifdef _WIN32 - WSACleanup(); -#endif - JLOG_VERBOSE("Destroyed server"); -} - -void server_destroy(juice_server_t *server) { - mutex_lock(&server->mutex); - - JLOG_VERBOSE("Waiting for server thread"); - server->thread_stopped = true; - mutex_unlock(&server->mutex); - server_interrupt(server); - thread_join(server->thread, NULL); - - server_do_destroy(server); -} - -uint16_t server_get_port(juice_server_t *server) { - mutex_lock(&server->mutex); - uint16_t port = server->config.port; // updated at creation - mutex_unlock(&server->mutex); - return port; -} - -int server_add_credentials(juice_server_t *server, const juice_server_credentials_t *credentials, - timediff_t lifetime) { - mutex_lock(&server->mutex); - - if (server->config.max_allocations < credentials->allocations_quota) - server->config.max_allocations = credentials->allocations_quota; - - if (server->allocs_count < (int)server->config.max_allocations) { - if (server->allocs_count == 0) - JLOG_INFO("Enabling TURN relaying"); - - server_turn_alloc_t *reallocated = - realloc(server->allocs, server->config.max_allocations * sizeof(server_turn_alloc_t)); - if (!reallocated) { - JLOG_ERROR("Memory allocation for TURN allocation table failed"); - mutex_unlock(&server->mutex); - return -1; - } - memset(reallocated + server->allocs_count, 0, - ((int)server->config.max_allocations - server->allocs_count) * - sizeof(server_turn_alloc_t)); - server->allocs_count = (int)server->config.max_allocations; - server->allocs = reallocated; - } - - juice_credentials_list_t *node = server_do_add_credentials(server, credentials, lifetime); - if (!node) { - mutex_unlock(&server->mutex); - return -1; - } - - if (node->credentials.allocations_quota == 0) // unlimited - node->credentials.allocations_quota = server->config.max_allocations; - - mutex_unlock(&server->mutex); - return 0; -} - -juice_credentials_list_t *server_do_add_credentials(juice_server_t *server, - const juice_server_credentials_t *credentials, - timediff_t lifetime) { - juice_credentials_list_t *node = calloc(1, sizeof(juice_credentials_list_t)); - if (!node) { - JLOG_ERROR("Memory allocation for TURN credentials failed"); - goto error; - } - - bool alloc_failed = false; - node->credentials.username = - alloc_string_copy(credentials->username ? credentials->username : "", &alloc_failed); - node->credentials.password = - alloc_string_copy(credentials->password ? credentials->password : "", &alloc_failed); - node->credentials.allocations_quota = credentials->allocations_quota; - if (alloc_failed) { - JLOG_ERROR("Memory allocation for TURN credentials failed"); - goto error; - } - - stun_compute_userhash(node->credentials.username, server->config.realm, node->userhash); - - if (lifetime > 0) - node->timestamp = current_timestamp() + lifetime; - else - node->timestamp = 0; // never expires - - node->next = server->credentials; - server->credentials = node; - return server->credentials; - -error: - if (node) { - free((void *)node->credentials.username); - free((void *)node->credentials.password); - free(node); - } - return NULL; -} - -void server_run(juice_server_t *server) { - mutex_lock(&server->mutex); - nfds_t nfd = 0; - struct pollfd *pfd = NULL; - - // Main loop - timestamp_t next_timestamp; - while (server_bookkeeping(server, &next_timestamp) == 0) { - timediff_t timediff = next_timestamp - current_timestamp(); - if (timediff < 0) - timediff = 0; - - if (!pfd || nfd != (nfds_t)(1 + server->allocs_count)) { - free(pfd); - nfd = (nfds_t)(1 + server->allocs_count); - pfd = calloc(nfd, sizeof(struct pollfd)); - if (!pfd) { - JLOG_FATAL("Memory allocation for poll descriptors failed"); - break; - } - } - - pfd[0].fd = server->sock; - pfd[0].events = POLLIN; - - for (int i = 0; i < server->allocs_count; ++i) { - server_turn_alloc_t *alloc = server->allocs + i; - if (alloc->state == SERVER_TURN_ALLOC_FULL) { - pfd[1 + i].fd = alloc->sock; - pfd[1 + i].events = POLLIN; - } else { - pfd[1 + i].fd = -1; // ignore - } - } - - JLOG_VERBOSE("Entering poll for %d ms", (int)timediff); - mutex_unlock(&server->mutex); - int ret = poll(pfd, nfd, (int)timediff); - mutex_lock(&server->mutex); - JLOG_VERBOSE("Leaving poll"); - if (ret < 0) { - if (sockerrno == SEINTR || sockerrno == SEAGAIN) { - JLOG_VERBOSE("poll interrupted"); - continue; - } else { - JLOG_FATAL("poll failed, errno=%d", sockerrno); - break; - } - } - - if (server->thread_stopped) { - JLOG_VERBOSE("Server destruction requested"); - break; - } - - if (pfd[0].revents & POLLNVAL || pfd[0].revents & POLLERR) { - JLOG_FATAL("Error when polling server socket"); - break; - } - - if (pfd[0].revents & POLLIN) { - if (server_recv(server) < 0) - break; - } - - for (int i = 0; i < server->allocs_count; ++i) { - server_turn_alloc_t *alloc = server->allocs + i; - if (alloc->state == SERVER_TURN_ALLOC_FULL && pfd[1 + i].revents & POLLIN) - server_forward(server, alloc); - } - } - - JLOG_DEBUG("Leaving server thread"); - free(pfd); - mutex_unlock(&server->mutex); -} - -int server_send(juice_server_t *server, const addr_record_t *dst, const char *data, size_t size) { - JLOG_VERBOSE("Sending datagram, size=%d", size); - - int ret = udp_sendto(server->sock, data, size, dst); - if (ret < 0 && sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) - JLOG_WARN("Send failed, errno=%d", sockerrno); - - return ret; -} - -int server_stun_send(juice_server_t *server, const addr_record_t *dst, const stun_message_t *msg, - const char *password) { - char buffer[BUFFER_SIZE]; - int size = stun_write(buffer, BUFFER_SIZE, msg, password); - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - - if (server_send(server, dst, buffer, size) < 0) { - JLOG_WARN("STUN message send failed, errno=%d", sockerrno); - return -1; - } - return 0; -} - -int server_recv(juice_server_t *server) { - JLOG_VERBOSE("Receiving datagrams"); - while (true) { - char buffer[BUFFER_SIZE]; - addr_record_t record; - int len = udp_recvfrom(server->sock, buffer, BUFFER_SIZE, &record); - if (len < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) { - JLOG_VERBOSE("No more datagrams to receive"); - break; - } - JLOG_ERROR("recvfrom failed, errno=%d", sockerrno); - return -1; - } - if (len == 0) { - // Empty datagram (used to interrupt) - continue; - } - - addr_unmap_inet6_v4mapped((struct sockaddr *)&record.addr, &record.len); - server_input(server, buffer, len, &record); - } - - return 0; -} - -int server_forward(juice_server_t *server, server_turn_alloc_t *alloc) { - JLOG_VERBOSE("Forwarding datagrams"); - while (true) { - char buffer[BUFFER_SIZE]; - addr_record_t record; - int len = udp_recvfrom(alloc->sock, buffer, BUFFER_SIZE, &record); - if (len < 0) { - if (sockerrno == SEAGAIN || sockerrno == SEWOULDBLOCK) { - break; - } - JLOG_WARN("recvfrom failed, errno=%d", sockerrno); - return -1; - } - addr_unmap_inet6_v4mapped((struct sockaddr *)&record.addr, &record.len); - - uint16_t channel; - if (turn_get_bound_channel(&alloc->map, &record, &channel)) { - // Use ChannelData - len = turn_wrap_channel_data(buffer, BUFFER_SIZE, buffer, len, channel); - if (len <= 0) { - JLOG_ERROR("TURN ChannelData wrapping failed"); - return -1; - } - - JLOG_VERBOSE("Forwarding as ChannelData, size=%d", len); - - int ret = udp_sendto(server->sock, buffer, len, &alloc->record); - if (ret < 0 && sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) - JLOG_WARN("Send failed, errno=%d", sockerrno); - - return ret; - - } else { - // Use TURN Data indication - JLOG_VERBOSE("Forwarding as TURN Data indication"); - - stun_message_t msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_class = STUN_CLASS_INDICATION; - msg.msg_method = STUN_METHOD_DATA; - msg.peer = record; - msg.data = buffer; - msg.data_size = len; - juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE); - - return server_stun_send(server, &alloc->record, &msg, NULL); - } - } - - return 0; -} - -int server_input(juice_server_t *server, char *buf, size_t len, const addr_record_t *src) { - JLOG_VERBOSE("Received datagram, size=%d", len); - - if (is_stun_datagram(buf, len)) { - if (JLOG_DEBUG_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Received STUN datagram from %s", src_str); - } - stun_message_t msg; - if (stun_read(buf, len, &msg) < 0) { - JLOG_ERROR("STUN message reading failed"); - return -1; - } - return server_dispatch_stun(server, buf, len, &msg, src); - } - - if (is_channel_data(buf, len)) { - if (JLOG_DEBUG_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - JLOG_DEBUG("Received ChannelData datagram from %s", src_str); - } - return server_process_channel_data(server, buf, len, src); - } - - if (JLOG_WARN_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - JLOG_WARN("Received unexpected non-STUN datagram from %s, ignoring", src_str); - } - return -1; -} - -int server_interrupt(juice_server_t *server) { - JLOG_VERBOSE("Interrupting server thread"); - mutex_lock(&server->mutex); - if (server->sock == INVALID_SOCKET) { - mutex_unlock(&server->mutex); - return -1; - } - - if (udp_sendto_self(server->sock, NULL, 0) < 0) { - if (sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) { - JLOG_WARN("Failed to interrupt thread by triggering socket, errno=%d", sockerrno); - mutex_unlock(&server->mutex); - return -1; - } - } - - mutex_unlock(&server->mutex); - return 0; -} - -int server_bookkeeping(juice_server_t *server, timestamp_t *next_timestamp) { - timestamp_t now = current_timestamp(); - *next_timestamp = now + 60000; - - // Handle allocations - for (int i = 0; i < server->allocs_count; ++i) { - server_turn_alloc_t *alloc = server->allocs + i; - if (alloc->state != SERVER_TURN_ALLOC_FULL) - continue; - - if (alloc->timestamp <= now) { - JLOG_DEBUG("Allocation timed out"); - delete_allocation(alloc); - continue; - } - - if (alloc->timestamp < *next_timestamp) - *next_timestamp = alloc->timestamp; - } - - // Handle credentials - juice_credentials_list_t **pnode = &server->credentials; // We are deleting some elements - while (*pnode) { - if ((*pnode)->timestamp && (*pnode)->timestamp <= now) { - JLOG_DEBUG("Credentials timed out"); - juice_credentials_list_t *next = (*pnode)->next; - free((void *)(*pnode)->credentials.username); - free((void *)(*pnode)->credentials.password); - free((*pnode)); - *pnode = next; - continue; - } - - pnode = &(*pnode)->next; - } - - return 0; -} - -void server_get_nonce(juice_server_t *server, const addr_record_t *src, char *nonce) { - timestamp_t now = current_timestamp(); - if (now >= server->nonce_key_timestamp) { - juice_random(server->nonce_key, SERVER_NONCE_KEY_SIZE); - server->nonce_key_timestamp = now + SERVER_NONCE_KEY_LIFETIME; - } - - uint8_t digest[HMAC_SHA256_SIZE]; - hmac_sha256(&src->addr, src->len, server->nonce_key, SERVER_NONCE_KEY_SIZE, digest); - - size_t len = HMAC_SHA256_SIZE; - if (len > STUN_MAX_NONCE_LEN) - len = STUN_MAX_NONCE_LEN; - - // RFC 4648 base64url character table - const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - for (size_t i = 0; i < len; ++i) - nonce[i] = table[digest[i] % 64]; - - nonce[len] = '\0'; - - stun_prepend_nonce_cookie(nonce); -} - -void server_prepare_credentials(juice_server_t *server, const addr_record_t *src, - const juice_server_credentials_t *credentials, - stun_message_t *msg) { - snprintf(msg->credentials.realm, STUN_MAX_REALM_LEN, "%s", server->config.realm); - server_get_nonce(server, src, msg->credentials.nonce); - - if (credentials) - snprintf(msg->credentials.username, STUN_MAX_USERNAME_LEN, "%s", credentials->username); -} - -int server_dispatch_stun(juice_server_t *server, void *buf, size_t size, stun_message_t *msg, - const addr_record_t *src) { - - if (!(msg->msg_class == STUN_CLASS_REQUEST || - (msg->msg_class == STUN_CLASS_INDICATION && - (msg->msg_method == STUN_METHOD_BINDING || msg->msg_method == STUN_METHOD_SEND)))) { - JLOG_WARN("Unexpected STUN message, class=0x%X, method=0x%X", msg->msg_class, - msg->msg_method); - return -1; - } - - if (server->allocs_count == 0 && msg->msg_method != STUN_METHOD_BINDING) { - // TURN support is disabled - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 400, // Bad request - NULL); - } - - if (msg->error_code == STUN_ERROR_INTERNAL_VALIDATION_FAILED) { - if (msg->msg_class == STUN_CLASS_REQUEST) { - JLOG_WARN("Invalid STUN message, answering bad request error response"); - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 400, // Bad request - NULL); - } else { - JLOG_WARN("Invalid STUN message, dropping"); - return -1; - } - } - - juice_server_credentials_t *credentials = NULL; - if (msg->msg_method != STUN_METHOD_BINDING && msg->msg_class != STUN_CLASS_INDICATION) { - if (!msg->has_integrity || // - *msg->credentials.realm == '\0' || *msg->credentials.nonce == '\0' || - (*msg->credentials.username == '\0' && !msg->credentials.enable_userhash)) { - JLOG_DEBUG("Answering STUN unauthorized error response"); - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 401, // Unauthorized - NULL); // No username - } - - char nonce[STUN_MAX_NONCE_LEN]; - server_get_nonce(server, src, nonce); - if (strcmp(msg->credentials.nonce, nonce) != 0 || - strcmp(msg->credentials.realm, server->config.realm) != 0) { - JLOG_DEBUG("Answering STUN stale nonce error response"); - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 438, // Stale nonce - NULL); // No username - } - - timestamp_t now = current_timestamp(); - if (msg->credentials.enable_userhash) { - juice_credentials_list_t *node = server->credentials; - while (node) { - if ((!node->timestamp || node->timestamp > now) && - const_time_memcmp(node->userhash, msg->credentials.userhash, USERHASH_SIZE) == - 0) { - credentials = &node->credentials; - } - node = node->next; - } - - if (credentials) - snprintf(msg->credentials.username, STUN_MAX_USERNAME_LEN, "%s", - credentials->username); - else - JLOG_WARN("No credentials for userhash"); - - } else { - juice_credentials_list_t *node = server->credentials; - while (node) { - if ((!node->timestamp || node->timestamp > now) && - const_time_strcmp(node->credentials.username, msg->credentials.username) == 0) { - credentials = &node->credentials; - } - node = node->next; - } - - if (!credentials) - JLOG_WARN("No credentials for username \"%s\"", msg->credentials.username); - } - if (!credentials) { - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 401, // Unauthorized - NULL); // No username - return -1; - } - - // Check credentials - if (!stun_check_integrity(buf, size, msg, credentials->password)) { - JLOG_WARN("STUN authentication failed for username \"%s\"", msg->credentials.username); - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 401, // Unauthorized - NULL); // No username - return -1; - } - } - - switch (msg->msg_method) { - case STUN_METHOD_BINDING: - return server_process_stun_binding(server, msg, src); - - case STUN_METHOD_ALLOCATE: - case STUN_METHOD_REFRESH: - return server_process_turn_allocate(server, msg, src, credentials); - - case STUN_METHOD_CREATE_PERMISSION: - return server_process_turn_create_permission(server, msg, src, credentials); - - case STUN_METHOD_CHANNEL_BIND: - return server_process_turn_channel_bind(server, msg, src, credentials); - - case STUN_METHOD_SEND: - return server_process_turn_send(server, msg, src); - - default: - JLOG_WARN("Unknown STUN method 0x%X, ignoring", msg->msg_method); - return -1; - } -} - -int server_answer_stun_binding(juice_server_t *server, const uint8_t *transaction_id, - const addr_record_t *src) { - JLOG_DEBUG("Answering STUN Binding request"); - - stun_message_t ans; - memset(&ans, 0, sizeof(ans)); - ans.msg_class = STUN_CLASS_RESP_SUCCESS; - ans.msg_method = STUN_METHOD_BINDING; - ans.mapped = *src; - memcpy(ans.transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - - char buffer[BUFFER_SIZE]; - int size = stun_write(buffer, BUFFER_SIZE, &ans, NULL); - if (size <= 0) { - JLOG_ERROR("STUN message write failed"); - return -1; - } - - if (server_send(server, src, buffer, size) < 0) { - JLOG_WARN("STUN message send failed, errno=%d", sockerrno); - return -1; - } - - return 0; -} - -int server_answer_stun_error(juice_server_t *server, const uint8_t *transaction_id, - const addr_record_t *src, stun_method_t method, unsigned int code, - const juice_server_credentials_t *credentials) { - JLOG_DEBUG("Answering STUN error response with code %u", code); - - stun_message_t ans; - memset(&ans, 0, sizeof(ans)); - ans.msg_class = STUN_CLASS_RESP_ERROR; - ans.msg_method = method; - ans.error_code = code; - memcpy(ans.transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - - if (method != STUN_METHOD_BINDING) - server_prepare_credentials(server, src, credentials, &ans); - - return server_stun_send(server, src, &ans, credentials ? credentials->password : NULL); -} - -int server_process_stun_binding(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src) { - if (JLOG_INFO_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - JLOG_INFO("Got STUN binding from client %s", src_str); - } - - return server_answer_stun_binding(server, msg->transaction_id, src); -} - -int server_process_turn_allocate(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src, - juice_server_credentials_t *credentials) { - if (msg->msg_class != STUN_CLASS_REQUEST) - return -1; - - if (msg->msg_method != STUN_METHOD_ALLOCATE && msg->msg_method != STUN_METHOD_REFRESH) - return -1; - - JLOG_DEBUG("Processing TURN Allocate request"); - - server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, true); - if (!alloc) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 486, // Allocation quota reached - credentials); - } - - if (alloc->state == SERVER_TURN_ALLOC_FULL) { - // Allocation exists - if (msg->msg_method == STUN_METHOD_ALLOCATE && - memcmp(alloc->transaction_id, msg->transaction_id, STUN_TRANSACTION_ID_SIZE) != 0) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 437, // Allocation mismatch - credentials); - } - - if (alloc->credentials != credentials) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 441, // Wrong credentials - credentials); - } - } else { - // Allocation does not exist - if (msg->msg_method == STUN_METHOD_REFRESH) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 437, // Allocation mismatch - credentials); - } - - if (credentials->allocations_quota <= 0) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 486, // Allocation quota reached - credentials); - } - - udp_socket_config_t socket_config; - memset(&socket_config, 0, sizeof(socket_config)); - socket_config.bind_address = server->config.bind_address; - socket_config.port_begin = server->config.relay_port_range_begin; - socket_config.port_end = server->config.relay_port_range_end; - alloc->sock = udp_create_socket(&socket_config); - if (alloc->sock == INVALID_SOCKET) { - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500, - credentials); - return -1; - } - if (turn_init_map(&alloc->map, server->config.max_peers) < 0) { - closesocket(alloc->sock); - alloc->sock = INVALID_SOCKET; - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500, - credentials); - return -1; - } - - alloc->state = SERVER_TURN_ALLOC_FULL; - alloc->record = *src; - alloc->credentials = credentials; - - --credentials->allocations_quota; - } - - uint32_t lifetime = ALLOCATION_LIFETIME / 1000; - if (msg->lifetime_set && msg->lifetime < lifetime) - lifetime = msg->lifetime; - - alloc->timestamp = current_timestamp() + lifetime * 1000; - memcpy(alloc->transaction_id, msg->transaction_id, STUN_TRANSACTION_ID_SIZE); - - addr_record_t records[MAX_RELAYED_RECORDS_COUNT]; - const addr_record_t *relayed = NULL; - if (lifetime == 0) { - delete_allocation(alloc); - - } else { - int count = 0; - if (server->config.external_address) { - char service[8]; - snprintf(service, 8, "%hu", udp_get_port(alloc->sock)); - count = addr_resolve(server->config.external_address, service, records, - MAX_RELAYED_RECORDS_COUNT); - if (count <= 0) { - JLOG_ERROR("Specified external address is invalid"); - goto error; - } - } else { - count = udp_get_addrs(alloc->sock, records, MAX_RELAYED_RECORDS_COUNT); - if (count <= 0) { - JLOG_ERROR("No local address found"); - goto error; - } - } - - if (count > MAX_RELAYED_RECORDS_COUNT) - count = MAX_RELAYED_RECORDS_COUNT; - - for (int i = 0; i < count; ++i) { - const addr_record_t *record = records + i; - if (record->addr.ss_family == AF_INET || !relayed) { - relayed = record; - if (record->addr.ss_family == AF_INET) - break; - } - } - - if (!relayed) { - JLOG_ERROR("No advertisable relayed address found"); - goto error; - } - - if (JLOG_INFO_ENABLED) { - char src_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(src, src_str, ADDR_MAX_STRING_LEN); - char relayed_str[ADDR_MAX_STRING_LEN]; - addr_record_to_string(relayed, relayed_str, ADDR_MAX_STRING_LEN); - JLOG_INFO("Allocated TURN relayed address %s for client %s", relayed_str, src_str); - } - } - - stun_message_t ans; - memset(&ans, 0, sizeof(ans)); - ans.msg_class = STUN_CLASS_RESP_SUCCESS; - ans.msg_method = msg->msg_method; - ans.lifetime = lifetime; - ans.lifetime_set = true; - ans.mapped = *src; - if (relayed) - ans.relayed = *relayed; - memcpy(ans.transaction_id, msg->transaction_id, STUN_TRANSACTION_ID_SIZE); - - server_prepare_credentials(server, src, credentials, &ans); - - return server_stun_send(server, src, &ans, credentials->password); - -error: - delete_allocation(alloc); - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500, credentials); - return -1; -} - -int server_process_turn_create_permission(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src, - const juice_server_credentials_t *credentials) { - if (msg->msg_class != STUN_CLASS_REQUEST) - return -1; - - JLOG_DEBUG("Processing STUN CreatePermission request"); - - if (!msg->peer.len) { - JLOG_WARN("Missing peer address in TURN CreatePermission request"); - return -1; - } - - server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, false); - if (!alloc || alloc->state != SERVER_TURN_ALLOC_FULL) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 437, // Allocation mismatch - credentials); - } - if (alloc->credentials != credentials) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 441, // Wrong credentials - credentials); - } - - if (!turn_set_permission(&alloc->map, msg->transaction_id, &msg->peer, PERMISSION_LIFETIME)) { - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500, - credentials); - return -1; - } - - stun_message_t ans; - memset(&ans, 0, sizeof(ans)); - ans.msg_class = STUN_CLASS_RESP_SUCCESS; - ans.msg_method = STUN_METHOD_CREATE_PERMISSION; - memcpy(ans.transaction_id, msg->transaction_id, STUN_TRANSACTION_ID_SIZE); - - server_prepare_credentials(server, src, credentials, &ans); - - return server_stun_send(server, src, &ans, credentials->password); -} - -int server_process_turn_channel_bind(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src, - const juice_server_credentials_t *credentials) { - if (msg->msg_class != STUN_CLASS_REQUEST) - return -1; - - JLOG_DEBUG("Processing STUN ChannelBind request"); - - if (!msg->peer.len) { - JLOG_WARN("Missing peer address in TURN ChannelBind request"); - return -1; - } - if (!msg->channel_number) { - JLOG_WARN("Missing channel number in TURN ChannelBind request"); - return -1; - } - - server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, false); - if (!alloc || alloc->state != SERVER_TURN_ALLOC_FULL) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 437, // Allocation mismatch - credentials); - } - if (alloc->credentials != credentials) { - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 441, // Wrong credentials - credentials); - } - - uint16_t channel = msg->channel_number; - if (!is_valid_channel(channel)) { - JLOG_WARN("TURN channel 0x%hX is invalid", channel); - return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, - 400, // Bad request - credentials); - } - - if (!turn_bind_channel(&alloc->map, &msg->peer, msg->transaction_id, channel, BIND_LIFETIME)) { - server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500, - credentials); - return -1; - } - - stun_message_t ans; - memset(&ans, 0, sizeof(ans)); - ans.msg_class = STUN_CLASS_RESP_SUCCESS; - ans.msg_method = STUN_METHOD_CHANNEL_BIND; - memcpy(ans.transaction_id, msg->transaction_id, STUN_TRANSACTION_ID_SIZE); - - server_prepare_credentials(server, src, credentials, &ans); - - return server_stun_send(server, src, &ans, credentials->password); -} - -int server_process_turn_send(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src) { - if (msg->msg_class != STUN_CLASS_INDICATION) - return -1; - - JLOG_DEBUG("Processing STUN Send indication"); - - if (!msg->data) { - JLOG_WARN("Missing data in TURN Send indication"); - return -1; - } - if (!msg->peer.len) { - JLOG_WARN("Missing peer address in TURN Send indication"); - return -1; - } - - server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, false); - if (!alloc || alloc->state != SERVER_TURN_ALLOC_FULL) { - JLOG_WARN("Allocation mismatch for TURN Send indication"); - return -1; - } - - if (!turn_has_permission(&alloc->map, &msg->peer)) { - JLOG_WARN("No permission for peer address"); - return -1; - } - - JLOG_VERBOSE("Forwarding datagram to peer, size=%zu", msg->data_size); - - int ret = udp_sendto(alloc->sock, msg->data, msg->data_size, &msg->peer); - if (ret < 0 && sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) - JLOG_WARN("Forwarding failed, errno=%d", sockerrno); - - return ret; -} - -int server_process_channel_data(juice_server_t *server, char *buf, size_t len, - const addr_record_t *src) { - server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, false); - if (!alloc || alloc->state != SERVER_TURN_ALLOC_FULL) { - JLOG_WARN("Allocation mismatch for TURN Channel Data"); - return -1; - } - - if (len < sizeof(struct channel_data_header)) { - JLOG_WARN("ChannelData is too short"); - return -1; - } - - const struct channel_data_header *header = (const struct channel_data_header *)buf; - buf += sizeof(struct channel_data_header); - len -= sizeof(struct channel_data_header); - uint16_t channel = ntohs(header->channel_number); - uint16_t length = ntohs(header->length); - JLOG_VERBOSE("Received ChannelData, channel=0x%hX, length=%hu", channel, length); - if (length > len) { - JLOG_WARN("ChannelData has invalid length"); - return -1; - } - len = length; - - addr_record_t record; - if (!turn_find_bound_channel(&alloc->map, channel, &record)) { - JLOG_WARN("Channel 0x%hX is not bound", channel); - return -1; - } - - JLOG_VERBOSE("Forwarding datagram to peer, size=%zu", len); - - int ret = udp_sendto(alloc->sock, buf, len, &record); - if (ret < 0 && sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) - JLOG_WARN("Send failed, errno=%d", sockerrno); - - return 0; -} - -#endif // ifndef NO_SERVER diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/server.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/server.h deleted file mode 100644 index a7adf104..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/server.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_SERVER_H -#define JUICE_SERVER_H - -#ifndef NO_SERVER - -#include "addr.h" -#include "juice.h" -#include "socket.h" -#include "stun.h" -#include "thread.h" -#include "timestamp.h" -#include "turn.h" - -#include -#include - -#define SERVER_DEFAULT_REALM "libjuice" -#define SERVER_DEFAULT_MAX_ALLOCATIONS 1000 // should be 1024-1 or less to be safe for poll() -#define SERVER_DEFAULT_MAX_PEERS 16 - -#define SERVER_NONCE_KEY_SIZE 32 - -// RFC 8656: The server [...] SHOULD expire the nonce at least once every hour during the lifetime -// of the allocation -#define SERVER_NONCE_KEY_LIFETIME 600 * 1000 // 10 min - -typedef enum server_turn_alloc_state { - SERVER_TURN_ALLOC_EMPTY, - SERVER_TURN_ALLOC_DELETED, - SERVER_TURN_ALLOC_FULL -} server_turn_alloc_state_t; - -typedef struct server_turn_alloc { - server_turn_alloc_state_t state; - addr_record_t record; - juice_server_credentials_t *credentials; - uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE]; - timestamp_t timestamp; - socket_t sock; - turn_map_t map; -} server_turn_alloc_t; - -typedef struct juice_credentials_list { - struct juice_credentials_list *next; - juice_server_credentials_t credentials; - uint8_t userhash[USERHASH_SIZE]; - timestamp_t timestamp; -} juice_credentials_list_t; - -typedef struct juice_server { - juice_server_config_t config; // Note config.credentials will be empty - juice_credentials_list_t *credentials; // Credentials are stored in this list - uint8_t nonce_key[SERVER_NONCE_KEY_SIZE]; - timestamp_t nonce_key_timestamp; - socket_t sock; - thread_t thread; - mutex_t mutex; - bool thread_stopped; - server_turn_alloc_t *allocs; - int allocs_count; -} juice_server_t; - -juice_server_t *server_create(const juice_server_config_t *config); -void server_do_destroy(juice_server_t *server); -void server_destroy(juice_server_t *server); - -uint16_t server_get_port(juice_server_t *server); -int server_add_credentials(juice_server_t *server, const juice_server_credentials_t *credentials, - timediff_t lifetime); - -juice_credentials_list_t *server_do_add_credentials(juice_server_t *server, - const juice_server_credentials_t *credentials, - timediff_t lifetime); // internal - -void server_run(juice_server_t *server); -int server_send(juice_server_t *agent, const addr_record_t *dst, const char *data, size_t size); -int server_stun_send(juice_server_t *server, const addr_record_t *dst, const stun_message_t *msg, - const char *password // password may be NULL -); -int server_recv(juice_server_t *server); -int server_forward(juice_server_t *server, server_turn_alloc_t *alloc); -int server_input(juice_server_t *agent, char *buf, size_t len, const addr_record_t *src); -int server_interrupt(juice_server_t *server); -int server_bookkeeping(juice_server_t *agent, timestamp_t *next_timestamp); - -void server_get_nonce(juice_server_t *server, const addr_record_t *src, char *nonce); -void server_prepare_credentials(juice_server_t *server, const addr_record_t *src, - const juice_server_credentials_t *credentials, stun_message_t *msg); - -int server_dispatch_stun(juice_server_t *server, void *buf, size_t size, stun_message_t *msg, - const addr_record_t *src); -int server_answer_stun_binding(juice_server_t *server, const uint8_t *transaction_id, - const addr_record_t *src); -int server_answer_stun_error(juice_server_t *server, const uint8_t *transaction_id, - const addr_record_t *src, stun_method_t method, unsigned int code, - const juice_server_credentials_t *credentials); - -int server_process_stun_binding(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src); -int server_process_turn_allocate(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src, juice_server_credentials_t *credentials); -int server_process_turn_create_permission(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src, - const juice_server_credentials_t *credentials); -int server_process_turn_channel_bind(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src, - const juice_server_credentials_t *credentials); -int server_process_turn_send(juice_server_t *server, const stun_message_t *msg, - const addr_record_t *src); -int server_process_channel_data(juice_server_t *server, char *buf, size_t len, - const addr_record_t *src); - -#endif // ifndef NO_SERVER - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/socket.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/socket.h deleted file mode 100644 index d126f340..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/socket.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_SOCKET_H -#define JUICE_SOCKET_H - -#ifdef _WIN32 - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 // Windows 7 -#endif -#ifndef __MSVCRT_VERSION__ -#define __MSVCRT_VERSION__ 0x0601 -#endif - -#include -#include -// -#include -#include - -#ifdef __MINGW32__ -#include -#include -#ifndef IPV6_V6ONLY -#define IPV6_V6ONLY 27 -#endif -#endif - -#define NO_IFADDRS -#define NO_PMTUDISC - -typedef SOCKET socket_t; -typedef SOCKADDR sockaddr; -typedef ULONG ctl_t; -typedef DWORD sockopt_t; -#define sockerrno ((int)WSAGetLastError()) -#define IP_DONTFRAG IP_DONTFRAGMENT -#define HOST_NAME_MAX 256 - -#define poll WSAPoll -typedef ULONG nfds_t; - -#define SEADDRINUSE WSAEADDRINUSE -#define SEINTR WSAEINTR -#define SEAGAIN WSAEWOULDBLOCK -#define SEACCES WSAEACCES -#define SEWOULDBLOCK WSAEWOULDBLOCK -#define SEINPROGRESS WSAEINPROGRESS -#define SECONNREFUSED WSAECONNREFUSED -#define SECONNRESET WSAECONNRESET -#define SENETRESET WSAENETRESET -#define SEMSGSIZE WSAEMSGSIZE - -#else // assume POSIX - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __linux__ -#define NO_PMTUDISC -#endif - -#ifdef __ANDROID__ -#define NO_IFADDRS -#else -#include -#endif - -typedef int socket_t; -typedef int ctl_t; -typedef int sockopt_t; -#define sockerrno errno -#define INVALID_SOCKET -1 -#define ioctlsocket ioctl -#define closesocket close - -#define SEADDRINUSE EADDRINUSE -#define SEINTR EINTR -#define SEAGAIN EAGAIN -#define SEACCES EACCES -#define SEWOULDBLOCK EWOULDBLOCK -#define SEINPROGRESS EINPROGRESS -#define SECONNREFUSED ECONNREFUSED -#define SECONNRESET ECONNRESET -#define SENETRESET ENETRESET -#define SEMSGSIZE EMSGSIZE - -#endif // _WIN32 - -#ifndef IN6_IS_ADDR_LOOPBACK -#define IN6_IS_ADDR_LOOPBACK(a) \ - (((const uint32_t *)(a))[0] == 0 && ((const uint32_t *)(a))[1] == 0 && \ - ((const uint32_t *)(a))[2] == 0 && ((const uint32_t *)(a))[3] == htonl(1)) -#endif - -#ifndef IN6_IS_ADDR_LINKLOCAL -#define IN6_IS_ADDR_LINKLOCAL(a) \ - ((((const uint32_t *)(a))[0] & htonl(0xffc00000)) == htonl(0xfe800000)) -#endif - -#ifndef IN6_IS_ADDR_SITELOCAL -#define IN6_IS_ADDR_SITELOCAL(a) \ - ((((const uint32_t *)(a))[0] & htonl(0xffc00000)) == htonl(0xfec00000)) -#endif - -#ifndef IN6_IS_ADDR_V4MAPPED -#define IN6_IS_ADDR_V4MAPPED(a) \ - ((((const uint32_t *)(a))[0] == 0) && (((const uint32_t *)(a))[1] == 0) && \ - (((const uint32_t *)(a))[2] == htonl(0xFFFF))) -#endif - -#endif // JUICE_SOCKET_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/stun.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/stun.c deleted file mode 100644 index f14b1d34..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/stun.c +++ /dev/null @@ -1,1236 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "stun.h" -#include "base64.h" -#include "const_time.h" -#include "crc32.h" -#include "juice.h" -#include "log.h" -#include "udp.h" - -#include -#include -#include -#include -#include -#include - -#define STUN_MAGIC 0x2112A442 -#define STUN_FINGERPRINT_XOR 0x5354554E // "STUN" -#define STUN_ATTR_SIZE sizeof(struct stun_attr) - -// STUN_MAX_PASSWORD_LEN > HASH_SHA256_SIZE > HASH_MD5_SIZE -#define MAX_HMAC_KEY_LEN STUN_MAX_PASSWORD_LEN - -#define MAX_HMAC_INPUT_LEN (STUN_MAX_USERNAME_LEN + STUN_MAX_REALM_LEN + STUN_MAX_PASSWORD_LEN + 2) - -#define MAX_USERHASH_INPUT_LEN (STUN_MAX_USERNAME_LEN + STUN_MAX_REALM_LEN + 1) - -#ifndef htonll -#define htonll(x) \ - ((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32))) -#endif -#ifndef ntohll -#define ntohll(x) htonll(x) -#endif - -static size_t align32(size_t len) { - while (len & 0x03) - ++len; - return len; -} - -static size_t generate_hmac_key(const stun_message_t *msg, const char *password, void *key) { - if (*msg->credentials.realm != '\0') { - // long-term credentials - if (*msg->credentials.username == '\0') - JLOG_WARN("Generating HMAC key for long-term credentials with empty STUN username"); - - char input[MAX_HMAC_INPUT_LEN]; - int input_len = snprintf(input, MAX_HMAC_INPUT_LEN, "%s:%s:%s", msg->credentials.username, - msg->credentials.realm, password ? password : ""); - if (input_len < 0) - return 0; - - if (input_len >= MAX_HMAC_INPUT_LEN) - input_len = MAX_HMAC_INPUT_LEN - 1; - - switch (msg->credentials.password_algorithm) { - case STUN_PASSWORD_ALGORITHM_SHA256: - hash_sha256(input, input_len, key); - return HASH_SHA256_SIZE; - default: - hash_md5(input, input_len, key); - return HASH_MD5_SIZE; - } - } else { - // short-term credentials - int key_len = snprintf((char *)key, MAX_HMAC_KEY_LEN, "%s", password ? password : ""); - if (key_len < 0) - return 0; - - if (key_len >= MAX_HMAC_KEY_LEN) - key_len = MAX_HMAC_KEY_LEN - 1; - - return key_len; - } -} - -static size_t generate_password_algorithms_attr(uint8_t *attr) { - // attr size must be at least STUN_PASSWORD_ALGORITHMS_ATTR_MAX_SIZE - struct stun_value_password_algorithm *pwa = (struct stun_value_password_algorithm *)attr; - pwa->algorithm = htons(STUN_PASSWORD_ALGORITHM_SHA256); - pwa->parameters_length = 0; - ++pwa; - pwa->algorithm = htons(STUN_PASSWORD_ALGORITHM_MD5); - pwa->parameters_length = 0; - ++pwa; - return (uint8_t *)pwa - attr; -} - -int stun_write(void *buf, size_t size, const stun_message_t *msg, const char *password) { - uint8_t *begin = buf; - uint8_t *pos = begin; - uint8_t *end = begin + size; - - JLOG_VERBOSE("Writing STUN message, class=0x%X, method=0x%X", (unsigned int)msg->msg_class, - (unsigned int)msg->msg_method); - - size_t len = - stun_write_header(pos, end - pos, msg->msg_class, msg->msg_method, msg->transaction_id); - if (len <= 0) - goto overflow; - pos += len; - uint8_t *attr_begin = pos; - - if (msg->error_code) { - const char *reason = stun_get_error_reason(msg->error_code); - char buffer[sizeof(struct stun_value_error_code) + STUN_MAX_ERROR_REASON_LEN + 1]; - struct stun_value_error_code *error = (struct stun_value_error_code *)buffer; - memset(error, 0, sizeof(*error)); - error->code_class = (msg->error_code / 100) & 0x07; - error->code_number = msg->error_code % 100; - strcpy((char *)error->reason, reason); - len = stun_write_attr(pos, end - pos, STUN_ATTR_ERROR_CODE, error, - sizeof(struct stun_value_error_code) + strlen(reason)); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->mapped.len) { - JLOG_VERBOSE("Writing XOR mapped address"); - uint8_t value[32]; - uint8_t mask[16]; - *((uint32_t *)mask) = htonl(STUN_MAGIC); - memcpy(mask + 4, msg->transaction_id, 12); - int value_len = stun_write_value_mapped_address( - value, 32, (const struct sockaddr *)&msg->mapped.addr, msg->mapped.len, mask); - if (value_len > 0) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_MAPPED_ADDRESS, value, value_len); - if (len <= 0) - goto overflow; - pos += len; - } - } - if (msg->priority) { - uint32_t priority = htonl(msg->priority); - len = stun_write_attr(pos, end - pos, STUN_ATTR_PRIORITY, &priority, 4); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->use_candidate) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_USE_CANDIDATE, NULL, 0); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->ice_controlling) { - uint64_t ice_controlling = htonll(msg->ice_controlling); - len = stun_write_attr(pos, end - pos, STUN_ATTR_ICE_CONTROLLING, &ice_controlling, 8); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->ice_controlled) { - uint64_t ice_controlled = htonll(msg->ice_controlled); - len = stun_write_attr(pos, end - pos, STUN_ATTR_ICE_CONTROLLED, &ice_controlled, 8); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->channel_number) { - struct stun_value_channel_number channel_number; - memset(&channel_number, 0, sizeof(channel_number)); - channel_number.channel_number = htons(msg->channel_number); - len = stun_write_attr(pos, end - pos, STUN_ATTR_CHANNEL_NUMBER, &channel_number, - sizeof(channel_number)); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->lifetime_set || msg->lifetime) { - uint32_t lifetime = htonl(msg->lifetime); - len = stun_write_attr(pos, end - pos, STUN_ATTR_LIFETIME, &lifetime, 4); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->peer.len) { - JLOG_VERBOSE("Writing XOR peer address"); - uint8_t value[32]; - uint8_t mask[16]; - *((uint32_t *)mask) = htonl(STUN_MAGIC); - memcpy(mask + 4, msg->transaction_id, 12); - int value_len = stun_write_value_mapped_address( - value, 32, (const struct sockaddr *)&msg->peer.addr, msg->peer.len, mask); - if (value_len > 0) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_PEER_ADDRESS, value, value_len); - if (len <= 0) - goto overflow; - pos += len; - } - } - if (msg->relayed.len) { - JLOG_VERBOSE("Writing XOR relay address"); - uint8_t value[32]; - uint8_t mask[16]; - *((uint32_t *)mask) = htonl(STUN_MAGIC); - memcpy(mask + 4, msg->transaction_id, 12); - int value_len = stun_write_value_mapped_address( - value, 32, (const struct sockaddr *)&msg->relayed.addr, msg->relayed.len, mask); - if (value_len > 0) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_RELAYED_ADDRESS, value, value_len); - if (len <= 0) - goto overflow; - pos += len; - } - } - if (msg->data) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_DATA, (const uint8_t *)msg->data, - msg->data_size); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->even_port) { - struct stun_value_even_port even_port; - memset(&even_port, 0, sizeof(even_port)); - if (msg->next_port) - even_port.r |= 0x80; - len = stun_write_attr(pos, end - pos, STUN_ATTR_CHANNEL_NUMBER, &even_port, - sizeof(even_port)); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->requested_transport) { - struct stun_value_requested_transport requested_transport; - memset(&requested_transport, 0, sizeof(requested_transport)); - requested_transport.protocol = 17; - len = stun_write_attr(pos, end - pos, STUN_ATTR_REQUESTED_TRANSPORT, &requested_transport, - sizeof(requested_transport)); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->dont_fragment) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_DONT_FRAGMENT, NULL, 0); - if (len <= 0) - goto overflow; - pos += len; - } - if (msg->reservation_token) { - uint64_t reservation_token = htonll(msg->reservation_token); - len = stun_write_attr(pos, end - pos, STUN_ATTR_RESERVATION_TOKEN, &reservation_token, 8); - if (len <= 0) - goto overflow; - pos += len; - } - - const char *software = "libjuice"; - len = stun_write_attr(pos, end - pos, STUN_ATTR_SOFTWARE, software, strlen(software)); - if (len <= 0) - goto overflow; - pos += len; - - if (msg->msg_class == STUN_CLASS_REQUEST) { - if (msg->credentials.enable_userhash) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_USERHASH, msg->credentials.userhash, - USERHASH_SIZE); - if (len <= 0) - goto overflow; - pos += len; - - } else if (*msg->credentials.username != '\0') { - len = stun_write_attr(pos, end - pos, STUN_ATTR_USERNAME, msg->credentials.username, - strlen(msg->credentials.username)); - if (len <= 0) - goto overflow; - pos += len; - } - } - if (msg->msg_class == STUN_CLASS_REQUEST || - (msg->msg_class == STUN_CLASS_RESP_ERROR && - (msg->error_code == 401 || msg->error_code == 438) // Unauthenticated or Stale Nonce - )) { - if (*msg->credentials.realm != '\0') { - len = stun_write_attr(pos, end - pos, STUN_ATTR_REALM, msg->credentials.realm, - strlen(msg->credentials.realm)); - if (len <= 0) - goto overflow; - pos += len; - } - if (*msg->credentials.nonce != '\0') { - len = stun_write_attr(pos, end - pos, STUN_ATTR_NONCE, msg->credentials.nonce, - strlen(msg->credentials.nonce)); - if (len <= 0) - goto overflow; - pos += len; - - if (msg->credentials.password_algorithm > 0) { - len = stun_write_attr(pos, end - pos, STUN_ATTR_PASSWORD_ALGORITHMS, - msg->credentials.password_algorithms_value, - msg->credentials.password_algorithms_value_size); - if (len <= 0) - goto overflow; - pos += len; - - } else if (msg->msg_class != STUN_CLASS_REQUEST) { - uint8_t pwa_value[STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE]; - size_t pwa_size = generate_password_algorithms_attr(pwa_value); - len = stun_write_attr(pos, end - pos, STUN_ATTR_PASSWORD_ALGORITHMS, pwa_value, - pwa_size); - if (len <= 0) - goto overflow; - pos += len; - } - - if (msg->msg_class == STUN_CLASS_REQUEST && - msg->credentials.password_algorithm != STUN_PASSWORD_ALGORITHM_UNSET) { - struct stun_value_password_algorithm pwa; - pwa.algorithm = htons(msg->credentials.password_algorithm); - len = stun_write_attr(pos, end - pos, STUN_ATTR_PASSWORD_ALGORITHM, &pwa, - sizeof(pwa)); - if (len <= 0) - goto overflow; - pos += len; - } - } - } - if (msg->msg_class != STUN_CLASS_INDICATION && password) { - uint8_t key[MAX_HMAC_KEY_LEN]; - size_t key_len = generate_hmac_key(msg, password, key); - - size_t tmp_length = pos - attr_begin + STUN_ATTR_SIZE + HMAC_SHA1_SIZE; - stun_update_header_length(begin, tmp_length); - - uint8_t hmac[HMAC_SHA1_SIZE]; - hmac_sha1(begin, pos - begin, key, key_len, hmac); - len = stun_write_attr(pos, end - pos, STUN_ATTR_MESSAGE_INTEGRITY, hmac, HMAC_SHA1_SIZE); - if (len <= 0) - goto overflow; - pos += len; - - // According to RFC 8489, the agent must include both MESSAGE-INTEGRITY and - // MESSAGE-INTEGRITY-SHA256. However, this makes legacy agents and servers fail with error - // 420 Unknown Attribute. Therefore, unless the password algorithm SHA-256 is enabled, only - // MESSAGE-INTEGRITY is included in the message for compatibility. - if (msg->credentials.password_algorithm != STUN_PASSWORD_ALGORITHM_UNSET) { - // If the response contains a PASSWORD-ALGORITHMS attribute, all the - // subsequent requests MUST be authenticated using MESSAGE-INTEGRITY- - // SHA256 only. - size_t tmp_length = pos - attr_begin + STUN_ATTR_SIZE + HMAC_SHA256_SIZE; - stun_update_header_length(begin, tmp_length); - - uint8_t hmac[HMAC_SHA256_SIZE]; - hmac_sha256(begin, pos - begin, key, key_len, hmac); - len = stun_write_attr(pos, end - pos, STUN_ATTR_MESSAGE_INTEGRITY_SHA256, hmac, - HMAC_SHA256_SIZE); - if (len <= 0) - goto overflow; - pos += len; - } - } - - size_t length = pos - attr_begin + STUN_ATTR_SIZE + 4; - if (length & 0x03) { - JLOG_ERROR("Written STUN message length is not multiple of 4, length=%zu", length); - return -1; - } - stun_update_header_length(begin, length); - - uint32_t fingerprint = htonl(CRC32(buf, pos - begin) ^ STUN_FINGERPRINT_XOR); - len = stun_write_attr(pos, end - pos, STUN_ATTR_FINGERPRINT, &fingerprint, 4); - if (len <= 0) - goto overflow; - pos += len; - - return (int)(pos - begin); - -overflow: - JLOG_ERROR("Not enough space in buffer for STUN message, size=%zu", size); - return -1; -} - -int stun_write_header(void *buf, size_t size, stun_class_t class, stun_method_t method, - const uint8_t *transaction_id) { - if (size < sizeof(struct stun_header)) - return -1; - - uint16_t type = (uint16_t) class | (uint16_t)method; - - struct stun_header *header = buf; - header->type = htons(type); - header->length = htons(0); - header->magic = htonl(STUN_MAGIC); - memcpy(header->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - - return sizeof(struct stun_header); -} - -size_t stun_update_header_length(void *buf, size_t length) { - struct stun_header *header = buf; - size_t previous = ntohs(header->length); - header->length = htons((uint16_t)length); - return previous; -} - -int stun_write_attr(void *buf, size_t size, uint16_t type, const void *value, size_t length) { - JLOG_VERBOSE("Writing STUN attribute type 0x%X, length=%zu", (unsigned int)type, length); - - if (size < sizeof(struct stun_attr) + length) - return -1; - - struct stun_attr *attr = buf; - attr->type = htons(type); - attr->length = htons((uint16_t)length); - - if (length > 0) { - memcpy(attr->value, value, length); - - // Pad to align on 4 bytes - while (length & 0x03) - attr->value[length++] = 0; - } - - return (int)(sizeof(struct stun_attr) + length); -} - -int stun_write_value_mapped_address(void *buf, size_t size, const struct sockaddr *addr, - socklen_t addrlen, const uint8_t *mask) { - if (size < sizeof(struct stun_value_mapped_address)) - return -1; - - struct stun_value_mapped_address *value = buf; - value->padding = 0; - switch (addr->sa_family) { - case AF_INET: { - value->family = STUN_ADDRESS_FAMILY_IPV4; - if (size < sizeof(struct stun_value_mapped_address) + 4) - return -1; - if (addrlen < (socklen_t)sizeof(struct sockaddr_in)) - return -1; - JLOG_VERBOSE("Writing IPv4 address"); - const struct sockaddr_in *sin = (const struct sockaddr_in *)addr; - value->port = sin->sin_port ^ *((uint16_t *)mask); - const uint8_t *bytes = (const uint8_t *)&sin->sin_addr; - for (int i = 0; i < 4; ++i) - value->address[i] = bytes[i] ^ mask[i]; - return sizeof(struct stun_value_mapped_address) + 4; - } - case AF_INET6: { - value->family = STUN_ADDRESS_FAMILY_IPV6; - if (size < sizeof(struct stun_value_mapped_address) + 16) - return -1; - if (addrlen < (socklen_t)sizeof(struct sockaddr_in6)) - return -1; - JLOG_VERBOSE("Writing IPv6 address"); - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr; - value->port = sin6->sin6_port ^ *((uint16_t *)mask); - const uint8_t *bytes = (const uint8_t *)&sin6->sin6_addr; - for (int i = 0; i < 16; ++i) - value->address[i] = bytes[i] ^ mask[i]; - return sizeof(struct stun_value_mapped_address) + 16; - } - default: { - JLOG_DEBUG("Unknown address family %u", (unsigned int)addr->sa_family); - return -1; - } - } -} - -bool is_stun_datagram(const void *data, size_t size) { - // RFC 8489: The most significant 2 bits of every STUN message MUST be zeroes. This can be used - // to differentiate STUN packets from other protocols when STUN is multiplexed with other - // protocols on the same port. - if (!size || *((uint8_t *)data) & 0xC0) { - JLOG_VERBOSE("Not a STUN message: first 2 bits are not zeroes"); - return false; - } - - if (size < sizeof(struct stun_header)) { - JLOG_VERBOSE("Not a STUN message: message too short, size=%zu", size); - return false; - } - - const struct stun_header *header = data; - if (ntohl(header->magic) != STUN_MAGIC) { - JLOG_VERBOSE("Not a STUN message: magic number invalid"); - return false; - } - - // RFC 8489: The message length MUST contain the size of the message in bytes, not including the - // 20-byte STUN header. Since all STUN attributes are padded to a multiple of 4 bytes, the last - // 2 bits of this field are always zero. This provides another way to distinguish STUN packets - // from packets of other protocols. - const size_t length = ntohs(header->length); - if (length & 0x03) { - JLOG_VERBOSE("Not a STUN message: invalid length %zu not multiple of 4", length); - return false; - } - if (size != sizeof(struct stun_header) + length) { - JLOG_VERBOSE("Not a STUN message: invalid length %zu while expecting %zu", length, - size - sizeof(struct stun_header)); - return false; - } - - return true; -} - -int stun_read(void *data, size_t size, stun_message_t *msg) { - memset(msg, 0, sizeof(*msg)); - - if (size < sizeof(struct stun_header)) { - JLOG_ERROR("STUN message too short, size=%zu", size); - return -1; - } - - const struct stun_header *header = data; - const size_t length = ntohs(header->length); - if (size < sizeof(struct stun_header) + length) { - JLOG_ERROR("Invalid STUN message length, length=%zu, available=%zu", length, - size - sizeof(struct stun_header)); - return -1; - } - - uint16_t type = ntohs(header->type); - msg->msg_class = (stun_class_t)(type & STUN_CLASS_MASK); - msg->msg_method = (stun_method_t)(type & ~STUN_CLASS_MASK); - memcpy(msg->transaction_id, header->transaction_id, STUN_TRANSACTION_ID_SIZE); - JLOG_VERBOSE("Reading STUN message, class=0x%X, method=0x%X", (unsigned int)msg->msg_class, - (unsigned int)msg->msg_method); - - uint32_t security_bits = 0; - - uint8_t *begin = data; - uint8_t *attr_begin = begin + sizeof(struct stun_header); - uint8_t *end = attr_begin + length; - const uint8_t *pos = attr_begin; - while (pos < end) { - int ret = stun_read_attr(pos, end - pos, msg, begin, attr_begin, &security_bits); - if (ret <= 0) { - JLOG_DEBUG("Reading STUN attribute failed"); - return -1; - } - pos += ret; - } - - JLOG_VERBOSE("Finished reading STUN attributes"); - - stun_credentials_t *credentials = &msg->credentials; - - // RFC 8489: If the response is an error response with an error code of 401 (Unauthenticated) or - // 438 (Stale Nonce), the client MUST test if the NONCE attribute value starts with the "nonce - // cookie". If so and the "nonce cookie" has the STUN Security Feature "Password algorithms" - // bit set to 1 but no PASSWORD-ALGORITHMS attribute is present, then the client MUST NOT retry - // the request with a new transaction. See - // https://www.rfc-editor.org/rfc/rfc8489.html#section-9.2.5 - if (msg->msg_class == STUN_CLASS_RESP_ERROR && - (msg->error_code == 401 || msg->error_code == 438) && - security_bits & STUN_SECURITY_PASSWORD_ALGORITHMS_BIT && - credentials->password_algorithms_value_size == 0) { - JLOG_INFO("STUN Security Feature \"Password algorithms\" bit is set in %u error response " - "but the corresponding attribute is missing", - msg->error_code); - msg->error_code = STUN_ERROR_INTERNAL_VALIDATION_FAILED; // so the agent will give up - } - - // RFC 8489: If the request contains neither the PASSWORD-ALGORITHMS nor the - // PASSWORD-ALGORITHM algorithm, then the request is processed as though - // PASSWORD-ALGORITHM were MD5. - // Otherwise, unless (1) PASSWORD-ALGORITHM and PASSWORD-ALGORITHMS are both - // present, (2) PASSWORD-ALGORITHMS matches the value sent in the response that sent - // this NONCE, and (3) PASSWORD-ALGORITHM matches one of the entries in - // PASSWORD-ALGORITHMS, the server MUST generate an error response with an error code of - // 400 (Bad Request). See https://www.rfc-editor.org/rfc/rfc8489.html#section-9.2.4 - if (!STUN_IS_RESPONSE(msg->msg_class)) { - if (credentials->password_algorithms_value_size == 0 && - credentials->password_algorithm == STUN_PASSWORD_ALGORITHM_UNSET) { - credentials->password_algorithm = STUN_PASSWORD_ALGORITHM_MD5; - - } else if (credentials->password_algorithm == STUN_PASSWORD_ALGORITHM_UNSET) { - JLOG_INFO("No suitable password algorithm in STUN request"); - msg->error_code = STUN_ERROR_INTERNAL_VALIDATION_FAILED; - - } else if (credentials->password_algorithms_value_size == 0) { - JLOG_INFO("Missing password algorithms list in STUN request"); - msg->error_code = STUN_ERROR_INTERNAL_VALIDATION_FAILED; - - } else { - uint8_t pwa_value[STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE]; - size_t pwa_size = generate_password_algorithms_attr(pwa_value); - if (pwa_size != credentials->password_algorithms_value_size || - memcmp(credentials->password_algorithms_value, pwa_value, pwa_size) != 0) { - JLOG_INFO("Password algorithms list is invalid in STUN request"); - msg->error_code = STUN_ERROR_INTERNAL_VALIDATION_FAILED; - } - } - } - - if (security_bits & STUN_SECURITY_USERNAME_ANONYMITY_BIT) { - JLOG_DEBUG("Remote agent supports user anonymity"); - credentials->enable_userhash = true; - } - - return (int)(sizeof(struct stun_header) + length); -} - -int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *begin, - uint8_t *attr_begin, uint32_t *security_bits) { - // RFC 8489: When present, the FINGERPRINT attribute MUST be the last attribute in the - // message and thus will appear after MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256. - if (msg->has_fingerprint) { - JLOG_DEBUG("Invalid STUN attribute after fingerprint"); - return -1; - } - - if (size < sizeof(struct stun_attr)) { - JLOG_VERBOSE("STUN attribute too short"); - return -1; - } - - const struct stun_attr *attr = data; - size_t length = ntohs(attr->length); - stun_attr_type_t type = (stun_attr_type_t)ntohs(attr->type); - JLOG_VERBOSE("Reading attribute 0x%X, length=%zu", (unsigned int)type, length); - if (size < sizeof(struct stun_attr) + length) { - JLOG_DEBUG("STUN attribute length invalid, length=%zu, available=%zu", length, - size - sizeof(struct stun_attr)); - return -1; - } - - // RFC 8489: Note that agents MUST ignore all attributes that follow MESSAGE-INTEGRITY, with - // the exception of the MESSAGE-INTEGRITY-SHA256 and FINGERPRINT attributes. - if (msg->has_integrity && type != STUN_ATTR_MESSAGE_INTEGRITY && - type != STUN_ATTR_MESSAGE_INTEGRITY_SHA256 && type != STUN_ATTR_FINGERPRINT) { - JLOG_DEBUG("Ignoring STUN attribute 0x%X after message integrity", (unsigned int)type); - while (length & 0x03) - ++length; // attributes are aligned on 4 bytes - return (int)(sizeof(struct stun_attr) + length); - } - - switch (type) { - case STUN_ATTR_MAPPED_ADDRESS: { - JLOG_VERBOSE("Reading mapped address"); - uint8_t zero_mask[16] = {0}; - if (stun_read_value_mapped_address(attr->value, length, &msg->mapped, zero_mask) < 0) - return -1; - break; - } - case STUN_ATTR_XOR_MAPPED_ADDRESS: { - JLOG_VERBOSE("Reading XOR mapped address"); - uint8_t mask[16]; - *((uint32_t *)mask) = htonl(STUN_MAGIC); - memcpy(mask + 4, msg->transaction_id, 12); - if (stun_read_value_mapped_address(attr->value, length, &msg->mapped, mask) < 0) - return -1; - break; - } - case STUN_ATTR_ALTERNATE_SERVER: { - JLOG_VERBOSE("Reading alternate server"); - uint8_t zero_mask[16] = {0}; - if (stun_read_value_mapped_address(attr->value, length, &msg->alternate_server, zero_mask) < - 0) - return -1; - break; - } - case STUN_ATTR_ERROR_CODE: { - JLOG_VERBOSE("Reading error code"); - if (length < sizeof(struct stun_value_error_code)) { - JLOG_DEBUG("STUN error code value too short, length=%zu", length); - return -1; - } - const struct stun_value_error_code *error = - (const struct stun_value_error_code *)attr->value; - msg->error_code = (error->code_class & 0x07) * 100 + error->code_number; - - if (msg->error_code == 401 || msg->error_code == 438) { // Unauthenticated or Stale Nonce - JLOG_DEBUG("Got STUN error code %u", msg->error_code); - - } else if (JLOG_INFO_ENABLED) { - size_t reason_length = length - sizeof(struct stun_value_error_code); - if (reason_length >= STUN_MAX_ERROR_REASON_LEN) - reason_length = STUN_MAX_ERROR_REASON_LEN - 1; - - char buffer[STUN_MAX_ERROR_REASON_LEN]; - memcpy(buffer, (const char *)error->reason, reason_length); - buffer[reason_length] = '\0'; - - JLOG_INFO("Got STUN error code %u, reason \"%s\"", msg->error_code, buffer); - } - break; - } - case STUN_ATTR_UNKNOWN_ATTRIBUTES: { - JLOG_VERBOSE("Reading STUN unknown attributes"); - const uint16_t *attributes = (const uint16_t *)attr->value; - for (int i = 0; i < (int)ntohs(attr->length) / 2; ++i) { - stun_attr_type_t type = (stun_attr_type_t)ntohs(attributes[i]); - JLOG_INFO("Got unknown attribute response for attribute 0x%X", (unsigned int)type); - } - break; - } - case STUN_ATTR_USERNAME: { - JLOG_VERBOSE("Reading username"); - if (length + 1 > STUN_MAX_USERNAME_LEN) { - JLOG_WARN("STUN username attribute value too long, length=%zu", length); - return -1; - } - memcpy(msg->credentials.username, (const char *)attr->value, length); - msg->credentials.username[length] = '\0'; - JLOG_VERBOSE("Got username: %s", msg->credentials.username); - break; - } - case STUN_ATTR_MESSAGE_INTEGRITY: { - JLOG_VERBOSE("Reading message integrity"); - if (length != HMAC_SHA1_SIZE) { - JLOG_DEBUG("STUN message integrity length invalid, length=%zu", length); - return -1; - } - msg->has_integrity = true; - break; - } - case STUN_ATTR_MESSAGE_INTEGRITY_SHA256: { - JLOG_VERBOSE("Reading message integrity SHA256"); - if (length != HMAC_SHA256_SIZE) { - JLOG_DEBUG("STUN message integrity SHA256 length invalid, length=%zu", length); - return -1; - } - msg->has_integrity = true; - break; - } - case STUN_ATTR_FINGERPRINT: { - JLOG_VERBOSE("Reading fingerprint"); - if (length != 4) { - JLOG_DEBUG("STUN fingerprint length invalid, length=%zu", length); - return -1; - } - size_t tmp_length = (uint8_t *)data - attr_begin + STUN_ATTR_SIZE + 4; - size_t prev_length = stun_update_header_length(begin, tmp_length); - uint32_t expected = CRC32(begin, (uint8_t *)data - begin) ^ STUN_FINGERPRINT_XOR; - stun_update_header_length(begin, prev_length); - - uint32_t fingerprint = ntohl(*((uint32_t *)attr->value)); - if (fingerprint != expected) { - JLOG_ERROR("STUN fingerprint check failed, expected=%lX, actual=%lX", - (unsigned long)expected, (unsigned long)fingerprint); - return -1; - } - JLOG_VERBOSE("STUN fingerprint check succeeded"); - msg->has_fingerprint = true; - break; - } - case STUN_ATTR_REALM: { - JLOG_VERBOSE("Reading realm"); - if (length + 1 > STUN_MAX_REALM_LEN) { - JLOG_WARN("STUN realm attribute value too long, length=%zu", length); - return -1; - } - memcpy(msg->credentials.realm, (const char *)attr->value, length); - msg->credentials.realm[length] = '\0'; - JLOG_VERBOSE("Got realm: %s", msg->credentials.realm); - break; - } - case STUN_ATTR_NONCE: { - JLOG_VERBOSE("Reading nonce"); - if (length + 1 > STUN_MAX_NONCE_LEN) { - JLOG_WARN("STUN nonce attribute value too long, length=%zu", length); - return -1; - } - memcpy(msg->credentials.nonce, (const char *)attr->value, length); - msg->credentials.nonce[length] = '\0'; - JLOG_VERBOSE("Got nonce: %s", msg->credentials.nonce); - - // If the nonce of a response starts with the nonce cookie, decode the Security Feature bits - // See https://www.rfc-editor.org/rfc/rfc8489.html#section-9.2 - if (STUN_IS_RESPONSE(msg->msg_class) && - strlen(msg->credentials.nonce) > STUN_NONCE_COOKIE_LEN + 4 && - strncmp(msg->credentials.nonce, STUN_NONCE_COOKIE, STUN_NONCE_COOKIE_LEN) == 0) { - char encoded_security_bits[5]; - memcpy(encoded_security_bits, msg->credentials.nonce + STUN_NONCE_COOKIE_LEN, 4); - encoded_security_bits[4] = '\0'; - - uint8_t bytes[4]; - bytes[0] = 0; - int len = BASE64_DECODE(encoded_security_bits, bytes + 1, 3); - if (len == 3) { - *security_bits = ntohl(*((uint32_t *)bytes)); - JLOG_VERBOSE("Nonce has cookie, Security Feature bits are 0x%lX", - (unsigned long)*security_bits); - } else { - JLOG_WARN("Nonce has cookie, but the encoded Security Feature bits field \"%s\" is " - "invalid", - encoded_security_bits); - security_bits = 0; - } - } else if (msg->msg_class == STUN_CLASS_RESP_ERROR) { - JLOG_DEBUG("Remote agent does not support RFC 8489"); - } - break; - } - case STUN_ATTR_PASSWORD_ALGORITHM: { - JLOG_VERBOSE("Reading password algorithm"); - if (length < sizeof(struct stun_value_password_algorithm)) { - JLOG_WARN("STUN password algorithm value too short, length=%zu", length); - return -1; - } - if (!STUN_IS_RESPONSE(msg->msg_class)) { - const struct stun_value_password_algorithm *pwa = - (const struct stun_value_password_algorithm *)attr->value; - stun_password_algorithm_t algorithm = ntohs(pwa->algorithm); - if (algorithm == STUN_PASSWORD_ALGORITHM_MD5 || - algorithm == STUN_PASSWORD_ALGORITHM_SHA256) - msg->credentials.password_algorithm = algorithm; - else - JLOG_WARN("Unknown password algorithm 0x%hX", algorithm); - } else { - JLOG_WARN("Found password algorithm in response, ignoring"); - } - break; - } - case STUN_ATTR_PASSWORD_ALGORITHMS: { - JLOG_VERBOSE("Reading password algorithms list"); - if (length < sizeof(struct stun_value_password_algorithm)) { - JLOG_WARN("STUN password algorithms list too short, length=%zu", length); - return -1; - } - if (length > STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE) { - JLOG_WARN("STUN password algorithms list too long, length=%zu", length); - return -1; - } - - memcpy(msg->credentials.password_algorithms_value, attr->value, length); - msg->credentials.password_algorithms_value_size = length; - - if (!STUN_IS_RESPONSE(msg->msg_class)) { - const uint8_t *pos = attr->value; - const uint8_t *end = pos + length; - while (pos < end) { - if ((size_t)(end - pos) < sizeof(struct stun_value_password_algorithm)) { - JLOG_WARN("STUN password algorithms list truncated, available=%zu", end - pos); - return -1; - } - const struct stun_value_password_algorithm *pwa = - (const struct stun_value_password_algorithm *)pos; - stun_password_algorithm_t algorithm = ntohs(pwa->algorithm); - size_t parameters_length = ntohs(pwa->parameters_length); - size_t padded_length = align32(parameters_length); - - pos += sizeof(struct stun_value_password_algorithm); - - if ((size_t)(end - pos) < padded_length) { - JLOG_WARN( - "STUN password algorithm parameters too long, length=%zu, padded=%zu, " - "available=%zu", - parameters_length, padded_length, end - pos); - return -1; - } - - pos += padded_length; - - if (algorithm == STUN_PASSWORD_ALGORITHM_MD5 || - algorithm == STUN_PASSWORD_ALGORITHM_SHA256) { - msg->credentials.password_algorithm = algorithm; - break; - } - - JLOG_DEBUG("Unknown password algorithm 0x%hX", algorithm); - } - } - break; - } - case STUN_ATTR_USERHASH: { - JLOG_VERBOSE("Reading user hash"); - if (length != USERHASH_SIZE) { - JLOG_WARN("STUN user hash value too long, length=%zu", length); - return -1; - } - memcpy(msg->credentials.userhash, attr->value, USERHASH_SIZE); - msg->credentials.enable_userhash = true; - break; - } - case STUN_ATTR_SOFTWARE: { - JLOG_VERBOSE("Reading software"); - if (length + 1 > STUN_MAX_SOFTWARE_LEN) { - JLOG_WARN("STUN software attribute value too long, length=%zu", length); - return -1; - } - char buffer[STUN_MAX_SOFTWARE_LEN]; - memcpy(buffer, (const char *)attr->value, length); - buffer[length] = '\0'; - JLOG_VERBOSE("Remote agent is \"%s\"", buffer); - break; - } - case STUN_ATTR_PRIORITY: { - JLOG_VERBOSE("Reading priority"); - if (length != 4) { - JLOG_DEBUG("STUN priority length invalid, length=%zu", length); - return -1; - } - msg->priority = ntohl(*((uint32_t *)attr->value)); - JLOG_VERBOSE("Got priority: %lu", (unsigned long)msg->priority); - break; - } - case STUN_ATTR_USE_CANDIDATE: { - JLOG_VERBOSE("Found use candidate flag"); - msg->use_candidate = true; - break; - } - case STUN_ATTR_ICE_CONTROLLING: { - JLOG_VERBOSE("Found ICE controlling attribute"); - if (length != 8) { - JLOG_DEBUG("STUN ICE controlling attribute length invalid, length=%zu", length); - return -1; - } - msg->ice_controlling = ntohll(*((uint64_t *)attr->value)); - break; - } - case STUN_ATTR_ICE_CONTROLLED: { - JLOG_VERBOSE("Found ICE controlled attribute"); - if (length != 8) { - JLOG_DEBUG("STUN ICE controlled attribute length invalid, length=%zu", length); - return -1; - } - msg->ice_controlled = ntohll(*((uint64_t *)attr->value)); - break; - } - case STUN_ATTR_CHANNEL_NUMBER: { - JLOG_VERBOSE("Reading channel number attribute"); - if (length < sizeof(struct stun_value_channel_number)) { - JLOG_DEBUG("STUN channel number attribute value too short, length=%zu", length); - return -1; - } - const struct stun_value_channel_number *channel_number = - (const struct stun_value_channel_number *)attr->value; - msg->channel_number = ntohs(channel_number->channel_number); - break; - } - case STUN_ATTR_LIFETIME: { - JLOG_VERBOSE("Reading lifetime attribute"); - if (length != 4) { - JLOG_DEBUG("STUN lifetime attribute length invalid, length=%zu", length); - return -1; - } - msg->lifetime = ntohl(*((uint32_t *)attr->value)); - msg->lifetime_set = true; - break; - } - case STUN_ATTR_XOR_PEER_ADDRESS: { - JLOG_VERBOSE("Reading XOR peer address"); - uint8_t mask[16]; - *((uint32_t *)mask) = htonl(STUN_MAGIC); - memcpy(mask + 4, msg->transaction_id, 12); - if (stun_read_value_mapped_address(attr->value, length, &msg->peer, mask) < 0) - return -1; - break; - } - case STUN_ATTR_XOR_RELAYED_ADDRESS: { - JLOG_VERBOSE("Reading XOR relayed address"); - uint8_t mask[16]; - *((uint32_t *)mask) = htonl(STUN_MAGIC); - memcpy(mask + 4, msg->transaction_id, 12); - if (stun_read_value_mapped_address(attr->value, length, &msg->relayed, mask) < 0) - return -1; - break; - } - case STUN_ATTR_DATA: { - JLOG_VERBOSE("Found data"); - msg->data = (const char *)attr->value; - msg->data_size = length; - break; - } - case STUN_ATTR_EVEN_PORT: { - JLOG_VERBOSE("Found even port attribute"); - if (length < 1) { - JLOG_DEBUG("STUN even port attribute length invalid, length=%zu", length); - return -1; - } - msg->even_port = true; - msg->next_port = ((struct stun_value_even_port *)attr->value)->r & 0x80; - break; - } - case STUN_ATTR_REQUESTED_TRANSPORT: { - JLOG_VERBOSE("Found requested transport attribute"); - if (length < sizeof(struct stun_value_requested_transport)) { - JLOG_DEBUG("STUN requested transport attribute length invalid, length=%zu", length); - return -1; - } - const struct stun_value_requested_transport *requested_transport = - (const struct stun_value_requested_transport *)attr->value; - if (requested_transport->protocol != 17) { // UDP - JLOG_WARN("Unexpected requested transport protocol: %d", - (int)requested_transport->protocol); - return -1; - } - msg->requested_transport = true; - break; - } - case STUN_ATTR_DONT_FRAGMENT: { - JLOG_VERBOSE("Found don't fragment attribute"); - msg->dont_fragment = true; - break; - } - case STUN_ATTR_RESERVATION_TOKEN: { - JLOG_VERBOSE("Found reservation token"); - if (length != 8) { - JLOG_DEBUG("STUN reservation token length invalid, length=%zu", length); - return -1; - } - msg->reservation_token = ntohll(*((uint64_t *)attr->value)); - break; - } - default: { - // Ignore - if (STUN_IS_OPTIONAL_ATTR(type)) - JLOG_DEBUG("Ignoring unknown optional STUN attribute type 0x%X", (unsigned int)type); - else - JLOG_WARN("Unknown STUN attribute type 0x%X, ignoring", (unsigned int)type); - break; - } - } - return (int)(sizeof(struct stun_attr) + align32(length)); -} - -int stun_read_value_mapped_address(const void *data, size_t size, addr_record_t *mapped, - const uint8_t *mask) { - size_t len = sizeof(struct stun_value_mapped_address); - if (size < len) { - JLOG_VERBOSE("STUN mapped address value too short, size=%zu", size); - return -1; - } - const struct stun_value_mapped_address *value = data; - stun_address_family_t family = (stun_address_family_t)value->family; - switch (family) { - case STUN_ADDRESS_FAMILY_IPV4: { - len += 4; - if (size < len) { - JLOG_DEBUG("IPv4 mapped address value too short, size=%zu", size); - return -1; - } - JLOG_VERBOSE("Reading IPv4 address"); - mapped->len = sizeof(struct sockaddr_in); - struct sockaddr_in *sin = (struct sockaddr_in *)&mapped->addr; - sin->sin_family = AF_INET; - sin->sin_port = value->port ^ *((uint16_t *)mask); - uint8_t *bytes = (uint8_t *)&sin->sin_addr; - for (int i = 0; i < 4; ++i) - bytes[i] = value->address[i] ^ mask[i]; - break; - } - case STUN_ADDRESS_FAMILY_IPV6: { - len += 16; - if (size < len) { - JLOG_DEBUG("IPv6 mapped address value too short, size=%zu", size); - return -1; - } - JLOG_VERBOSE("Reading IPv6 address"); - mapped->len = sizeof(struct sockaddr_in6); - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&mapped->addr; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = value->port ^ *((uint16_t *)mask); - uint8_t *bytes = (uint8_t *)&sin6->sin6_addr; - for (int i = 0; i < 16; ++i) - bytes[i] = value->address[i] ^ mask[i]; - break; - } - default: { - JLOG_DEBUG("Unknown STUN address family 0x%X", (unsigned int)family); - len = size; - break; - } - } - return (int)len; -} - -bool stun_check_integrity(void *buf, size_t size, const stun_message_t *msg, const char *password) { - if (!msg->has_integrity) - return false; - - const struct stun_header *header = buf; - const size_t length = ntohs(header->length); - if (size < sizeof(struct stun_header) + length) - return false; - - uint8_t key[MAX_HMAC_KEY_LEN]; - size_t key_len = generate_hmac_key(msg, password, key); - - bool success = false; - uint8_t *begin = buf; - const uint8_t *attr_begin = begin + sizeof(struct stun_header); - const uint8_t *end = attr_begin + length; - const uint8_t *pos = attr_begin; - while (pos < end) { - const struct stun_attr *attr = (const struct stun_attr *)pos; - size_t attr_length = ntohs(attr->length); - if (size < sizeof(struct stun_attr) + attr_length) - return false; - - stun_attr_type_t type = (stun_attr_type_t)ntohs(attr->type); - switch (type) { - case STUN_ATTR_MESSAGE_INTEGRITY: { - if (attr_length != HMAC_SHA1_SIZE) - return false; - - size_t tmp_length = pos - attr_begin + STUN_ATTR_SIZE + HMAC_SHA1_SIZE; - size_t prev_length = stun_update_header_length(begin, tmp_length); - uint8_t hmac[HMAC_SHA1_SIZE]; - hmac_sha1(begin, pos - begin, key, key_len, hmac); - stun_update_header_length(begin, prev_length); - - const uint8_t *expected_hmac = attr->value; - if (const_time_memcmp(hmac, expected_hmac, HMAC_SHA1_SIZE) != 0) { - JLOG_DEBUG("STUN message integrity SHA1 check failed"); - return false; - } - - success = true; - break; - } - case STUN_ATTR_MESSAGE_INTEGRITY_SHA256: { - if (attr_length != HMAC_SHA256_SIZE) - return false; - - size_t tmp_length = pos - attr_begin + STUN_ATTR_SIZE + HMAC_SHA256_SIZE; - size_t prev_length = stun_update_header_length(begin, tmp_length); - uint8_t hmac[HMAC_SHA256_SIZE]; - hmac_sha256(begin, pos - begin, key, key_len, hmac); - stun_update_header_length(begin, prev_length); - - const uint8_t *expected_hmac = attr->value; - if (const_time_memcmp(hmac, expected_hmac, HMAC_SHA256_SIZE) != 0) { - JLOG_DEBUG("STUN message integrity SHA256 check failed"); - return false; - } - - success = true; - break; - } - default: - // Ignore - break; - } - - pos += sizeof(struct stun_attr) + align32(attr_length); - } - - if (!success) - return false; - - JLOG_VERBOSE("STUN message integrity check succeeded"); - return true; -} - -void stun_prepend_nonce_cookie(char *nonce) { - // RFC 8489: To indicate that it supports this specification, a server MUST prepend the - // NONCE attribute value with the character string composed of "obMatJos2" concatenated with - // the (4-character) base64 [RFC4648] encoding of the 24-bit STUN Security Features See - // https://www.rfc-editor.org/rfc/rfc8489.html#section-9.2 - char copy[STUN_MAX_NONCE_LEN]; - strcpy(copy, nonce); - - char encoded_security_bits[5]; - uint32_t security_bits = - htonl(STUN_SECURITY_PASSWORD_ALGORITHMS_BIT | STUN_SECURITY_USERNAME_ANONYMITY_BIT); - BASE64_ENCODE((uint8_t *)&security_bits + 1, 3, encoded_security_bits, 5); - - snprintf(nonce, STUN_MAX_NONCE_LEN, "%s%s%.*s", STUN_NONCE_COOKIE, encoded_security_bits, - STUN_MAX_NONCE_LEN - (STUN_NONCE_COOKIE_LEN + 5), copy); -} - -void stun_compute_userhash(const char *username, const char *realm, uint8_t *out) { - char input[MAX_USERHASH_INPUT_LEN]; - int input_len = snprintf(input, MAX_USERHASH_INPUT_LEN, "%s:%s", username, realm); - if (input_len < 0) - return; - - if (input_len >= MAX_USERHASH_INPUT_LEN) - input_len = MAX_USERHASH_INPUT_LEN - 1; - - hash_sha256(input, input_len, out); -} - -void stun_process_credentials(const stun_credentials_t *credentials, stun_credentials_t *dst) { - char username[STUN_MAX_USERNAME_LEN]; - strcpy(username, dst->username); - *dst = *credentials; - strcpy(dst->username, username); - - if (credentials->enable_userhash) - stun_compute_userhash(username, credentials->realm, dst->userhash); -} - -const char *stun_get_error_reason(unsigned int code) { - switch (code) { - case 0: - return ""; - case 300: - return "Try Alternate"; - case 400: - return "Bad Request"; - case 401: - return "Unauthenticated"; - case 403: - return "Forbidden"; - case 420: - return "Unknown Attribute"; - case 437: - return "Allocation Mismatch"; - case 438: - return "Stale Nonce"; - case 440: - return "Address Family not Supported"; - case 441: - return "Wrong credentials"; - case 442: - return "Unsupported Transport Protocol"; - case 443: - return "Peer Address Family Mismatch"; - case 486: - return "Allocation Quota Reached"; - case 500: - return "Server Error"; - case 508: - return "Insufficient Capacity"; - default: - return "Error"; - } -} - -JUICE_EXPORT bool _juice_is_stun_datagram(const void *data, size_t size) { - return is_stun_datagram(data, size); -} - -JUICE_EXPORT int _juice_stun_read(void *data, size_t size, stun_message_t *msg) { - return stun_read(data, size, msg); -} - -JUICE_EXPORT bool _juice_stun_check_integrity(void *buf, size_t size, const stun_message_t *msg, - const char *password) { - return stun_check_integrity(buf, size, msg, password); -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/stun.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/stun.h deleted file mode 100644 index b3aeade4..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/stun.h +++ /dev/null @@ -1,376 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_STUN_H -#define JUICE_STUN_H - -#include "juice.h" - -#include "addr.h" -#include "hash.h" -#include "hmac.h" - -#include -#include - -#pragma pack(push, 1) -/* - * STUN message header (20 bytes) - * See https://www.rfc-editor.org/rfc/rfc8489.html#section-5 - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |0 0| STUN Message Type | Message Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Magic Cookie = 0x2112A442 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * | Transaction ID (96 bits) | - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -#define STUN_TRANSACTION_ID_SIZE 12 - -struct stun_header { - uint16_t type; - uint16_t length; - uint32_t magic; - uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE]; -}; - -/* - * Format of STUN Message Type Field - * - * 0 1 - * 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ - * |M |M |M|M|M|C|M|M|M|C|M|M|M|M| - * |11|10|9|8|7|1|6|5|4|0|3|2|1|0| - * +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ - * Request: C=b00 - * Indication: C=b01 - * Response: C=b10 (success) - * C=b11 (error) - */ -#define STUN_CLASS_MASK 0x0110 - -typedef enum stun_class { - STUN_CLASS_REQUEST = 0x0000, - STUN_CLASS_INDICATION = 0x0010, - STUN_CLASS_RESP_SUCCESS = 0x0100, - STUN_CLASS_RESP_ERROR = 0x0110 -} stun_class_t; - -typedef enum stun_method { - STUN_METHOD_BINDING = 0x0001, - - // Methods for TURN - // See https://www.rfc-editor.org/rfc/rfc8656.html#section-17 - STUN_METHOD_ALLOCATE = 0x003, - STUN_METHOD_REFRESH = 0x004, - STUN_METHOD_SEND = 0x006, - STUN_METHOD_DATA = 0x007, - STUN_METHOD_CREATE_PERMISSION = 0x008, - STUN_METHOD_CHANNEL_BIND = 0x009 -} stun_method_t; - -#define STUN_IS_RESPONSE(msg_class) (msg_class & 0x0100) - -/* - * STUN attribute header - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Value (variable) ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct stun_attr { - uint16_t type; - uint16_t length; - uint8_t value[]; -}; - -typedef enum stun_attr_type { - // Comprehension-required - STUN_ATTR_MAPPED_ADDRESS = 0x0001, - STUN_ATTR_USERNAME = 0x0006, - STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, - STUN_ATTR_ERROR_CODE = 0x0009, - STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000A, - STUN_ATTR_REALM = 0x0014, - STUN_ATTR_NONCE = 0x0015, - STUN_ATTR_MESSAGE_INTEGRITY_SHA256 = 0x001C, - STUN_ATTR_PASSWORD_ALGORITHM = 0x001D, - STUN_ATTR_USERHASH = 0x001E, - STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, - STUN_ATTR_PRIORITY = 0x0024, - STUN_ATTR_USE_CANDIDATE = 0x0025, - - // Comprehension-optional - STUN_ATTR_PASSWORD_ALGORITHMS = 0x8002, - STUN_ATTR_ALTERNATE_DOMAIN = 0x8003, - STUN_ATTR_SOFTWARE = 0x8022, - STUN_ATTR_ALTERNATE_SERVER = 0x8023, - STUN_ATTR_FINGERPRINT = 0x8028, - STUN_ATTR_ICE_CONTROLLED = 0x8029, - STUN_ATTR_ICE_CONTROLLING = 0x802A, - - // Attributes for TURN - // See https://www.rfc-editor.org/rfc/rfc8656.html#section-18 - STUN_ATTR_CHANNEL_NUMBER = 0x000C, - STUN_ATTR_LIFETIME = 0x000D, - STUN_ATTR_XOR_PEER_ADDRESS = 0x0012, - STUN_ATTR_DATA = 0x0013, - STUN_ATTR_XOR_RELAYED_ADDRESS = 0x0016, - STUN_ATTR_EVEN_PORT = 0x0018, - STUN_ATTR_REQUESTED_TRANSPORT = 0x0019, - STUN_ATTR_DONT_FRAGMENT = 0x001A, - STUN_ATTR_RESERVATION_TOKEN = 0x0022 -} stun_attr_type_t; - -#define STUN_IS_OPTIONAL_ATTR(attr_type) (attr_type & 0x8000) - -/* - * STUN attribute value for MAPPED-ADDRESS or XOR-MAPPED-ADDRESS - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |X X X X X X X X| Family | Port or X-Port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * | Address or X-Address (32 bits or 128 bits) | - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct stun_value_mapped_address { - uint8_t padding; - uint8_t family; - uint16_t port; - uint8_t address[]; -}; - -typedef enum stun_address_family { - STUN_ADDRESS_FAMILY_IPV4 = 0x01, - STUN_ADDRESS_FAMILY_IPV6 = 0x02, -} stun_address_family_t; - -/* - * STUN attribute value for ERROR-CODE - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reserved, should be 0 |Class| Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reason Phrase (variable) ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct stun_value_error_code { - uint16_t reserved; - uint8_t code_class; // lower 3 bits only, higher bits are reserved - uint8_t code_number; - uint8_t reason[]; -}; - -#define STUN_ERROR_INTERNAL_VALIDATION_FAILED 599 - -/* - * STUN attribute for CHANNEL-NUMBER - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Channel Number | RFFU = 0 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct stun_value_channel_number { - uint16_t channel_number; - uint16_t reserved; -}; - -/* - * STUN attribute for EVEN-PORT - * - * 0 - * 0 1 2 3 4 5 6 7 - * +-+-+-+-+-+-+-+-+ - * |R| RFFU | - * +-+-+-+-+-+-+-+-+ - */ -struct stun_value_even_port { - uint8_t r; -}; - -/* - * STUN attribute for REQUESTED-TRANSPORT - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Protocol | RFFU | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct stun_value_requested_transport { - uint8_t protocol; - uint8_t reserved1; - uint16_t reserved2; -}; - -/* - * STUN attribute value for PASSWORD-ALGORITHM and PASSWORD-ALGORITHMS - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Algorithm 1 | Algorithm 1 Parameters Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Algorithm 1 Parameters (variable) - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Algorithm 2 | Algorithm 2 Parameters Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Algorithm 2 Parameters (variable) - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ... - */ -struct stun_value_password_algorithm { - uint16_t algorithm; - uint16_t parameters_length; - uint8_t parameters[]; -}; - -typedef enum stun_password_algorithm { - STUN_PASSWORD_ALGORITHM_UNSET = 0x0000, - STUN_PASSWORD_ALGORITHM_MD5 = 0x0001, - STUN_PASSWORD_ALGORITHM_SHA256 = 0x0002, -} stun_password_algorithm_t; - -#pragma pack(pop) - -// The value of USERNAME is a variable-length value. It MUST contain a UTF-8 [RFC3629] encoded -// sequence of less than 513 bytes [...] -#define STUN_MAX_USERNAME_LEN 513 + 1 - -// The REALM attribute [...] MUST be a UTF-8 [RFC3629] encoded sequence of less than 128 characters -// (which can be as long as 763 bytes) -#define STUN_MAX_REALM_LEN 763 + 1 - -// The NONCE attribute may be present in requests and responses. It [...] MUST be less than 128 -// characters (which can be as long as 763 bytes) -#define STUN_MAX_NONCE_LEN 763 + 1 - -// The value of SOFTWARE is variable length. It MUST be a UTF-8 [RFC3629] encoded sequence of less -// than 128 characters (which can be as long as 763 bytes) -#define STUN_MAX_SOFTWARE_LEN 763 + 1 - -// The reason phrase MUST be a UTF-8-encoded [RFC3629] sequence of fewer than 128 characters (which -// can be as long as 509 bytes when encoding them or 763 bytes when decoding them). -#define STUN_MAX_ERROR_REASON_LEN 763 + 1 - -#define STUN_MAX_PASSWORD_LEN STUN_MAX_USERNAME_LEN - -// Nonce cookie prefix as specified in https://www.rfc-editor.org/rfc/rfc8489.html#section-9.2 -#define STUN_NONCE_COOKIE "obMatJos2" -#define STUN_NONCE_COOKIE_LEN 9 - -// USERHASH is a SHA256 digest -#define USERHASH_SIZE HASH_SHA256_SIZE - -// STUN Security Feature bits as defined in https://www.rfc-editor.org/rfc/rfc8489.html#section-18.1 -// See errata about bit order: https://www.rfc-editor.org/errata_search.php?rfc=8489 -// Bits are assigned starting from the least significant side of the bit set, so Bit 0 is the rightmost bit, and Bit 23 is the leftmost bit. -// Bit 0: Password algorithms -// Bit 1: Username anonymity -// Bit 2-23: Unassigned - -#define STUN_SECURITY_PASSWORD_ALGORITHMS_BIT 0x01 -#define STUN_SECURITY_USERNAME_ANONYMITY_BIT 0x02 - -#define STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE 256 - -typedef struct stun_credentials { - char username[STUN_MAX_USERNAME_LEN]; - char realm[STUN_MAX_REALM_LEN]; - char nonce[STUN_MAX_NONCE_LEN]; - uint8_t userhash[USERHASH_SIZE]; - bool enable_userhash; - stun_password_algorithm_t password_algorithm; - uint8_t password_algorithms_value[STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE]; - size_t password_algorithms_value_size; -} stun_credentials_t; - -typedef struct stun_message { - stun_class_t msg_class; - stun_method_t msg_method; - uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE]; - unsigned int error_code; - uint32_t priority; - uint64_t ice_controlling; - uint64_t ice_controlled; - bool use_candidate; - addr_record_t mapped; - - stun_credentials_t credentials; - - // Only for reading - bool has_integrity; - bool has_fingerprint; - - // TURN - addr_record_t peer; - addr_record_t relayed; - addr_record_t alternate_server; - const char *data; - size_t data_size; - uint32_t lifetime; - uint16_t channel_number; - bool lifetime_set; - bool even_port; - bool next_port; - bool dont_fragment; - bool requested_transport; - uint64_t reservation_token; - -} stun_message_t; - -int stun_write(void *buf, size_t size, const stun_message_t *msg, - const char *password); // password may be NULL -int stun_write_header(void *buf, size_t size, stun_class_t class, stun_method_t method, - const uint8_t *transaction_id); -size_t stun_update_header_length(void *buf, size_t length); -int stun_write_attr(void *buf, size_t size, uint16_t type, const void *value, size_t length); -int stun_write_value_mapped_address(void *buf, size_t size, const struct sockaddr *addr, - socklen_t addrlen, const uint8_t *mask); - -bool is_stun_datagram(const void *data, size_t size); - -int stun_read(void *data, size_t size, stun_message_t *msg); -int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *begin, - uint8_t *attr_begin, uint32_t *security_bits); -int stun_read_value_mapped_address(const void *data, size_t size, addr_record_t *mapped, - const uint8_t *mask); - -bool stun_check_integrity(void *buf, size_t size, const stun_message_t *msg, const char *password); - -void stun_compute_userhash(const char *username, const char *realm, uint8_t *out); -void stun_prepend_nonce_cookie(char *nonce); -void stun_process_credentials(const stun_credentials_t *credentials, stun_credentials_t *dst); - -const char *stun_get_error_reason(unsigned int code); - -// Export for tests -JUICE_EXPORT bool _juice_is_stun_datagram(const void *data, size_t size); -JUICE_EXPORT int _juice_stun_read(void *data, size_t size, stun_message_t *msg); -JUICE_EXPORT bool _juice_stun_check_integrity(void *buf, size_t size, const stun_message_t *msg, - const char *password); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/thread.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/thread.h deleted file mode 100644 index 2f8712c9..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/thread.h +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_THREAD_H -#define JUICE_THREAD_H - -#ifdef _WIN32 - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 // Windows 7 -#endif -#ifndef __MSVCRT_VERSION__ -#define __MSVCRT_VERSION__ 0x0601 -#endif - -#include - -typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR); // for thread_set_name_self() - -typedef HANDLE mutex_t; -typedef HANDLE thread_t; -typedef DWORD thread_return_t; -#define THREAD_CALL __stdcall - -#define MUTEX_INITIALIZER NULL - -#define MUTEX_PLAIN 0x0 -#define MUTEX_RECURSIVE 0x0 // mutexes are recursive on Windows - -static inline int mutex_init_impl(mutex_t *m) { - return ((*(m) = CreateMutex(NULL, FALSE, NULL)) != NULL ? 0 : (int)GetLastError()); -} - -static inline int mutex_lock_impl(volatile mutex_t *m) { - // Atomically initialize the mutex on first lock - if (*(m) == NULL) { - HANDLE cm = CreateMutex(NULL, FALSE, NULL); - if (cm == NULL) - return (int)GetLastError(); - if (InterlockedCompareExchangePointer(m, cm, NULL) != NULL) - CloseHandle(cm); - } - return WaitForSingleObject(*m, INFINITE) != WAIT_FAILED ? 0 : (int)GetLastError(); -} - -#define mutex_init(m, flags) mutex_init_impl(m) -#define mutex_lock(m) mutex_lock_impl(m) -#define mutex_unlock(m) (void)ReleaseMutex(*(m)) -#define mutex_destroy(m) (void)CloseHandle(*(m)) - -static inline void thread_join_impl(thread_t t, thread_return_t *res) { - WaitForSingleObject(t, INFINITE); - if (res) - GetExitCodeThread(t, res); - CloseHandle(t); -} - -#define thread_init(t, func, arg) \ - ((*(t) = CreateThread(NULL, 0, func, arg, 0, NULL)) != NULL ? 0 : (int)GetLastError()) -#define thread_join(t, res) thread_join_impl(t, res) - -#else // POSIX - -#include - -#if defined(__linux__) -#include // for prctl(PR_SET_NAME) -#endif -#if defined(__FreeBSD__) -#include // for pthread_set_name_np -#endif - -typedef pthread_mutex_t mutex_t; -typedef pthread_t thread_t; -typedef void *thread_return_t; -#define THREAD_CALL - -#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER - -#define MUTEX_PLAIN PTHREAD_MUTEX_NORMAL -#define MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE - -static inline int mutex_init_impl(mutex_t *m, int flags) { - pthread_mutexattr_t mutexattr; - pthread_mutexattr_init(&mutexattr); - pthread_mutexattr_settype(&mutexattr, flags); - int ret = pthread_mutex_init(m, &mutexattr); - pthread_mutexattr_destroy(&mutexattr); - return ret; -} - -#define mutex_init(m, flags) mutex_init_impl(m, flags) -#define mutex_lock(m) pthread_mutex_lock(m) -#define mutex_unlock(m) (void)pthread_mutex_unlock(m) -#define mutex_destroy(m) (void)pthread_mutex_destroy(m) - -#define thread_init(t, func, arg) pthread_create(t, NULL, func, arg) -#define thread_join(t, res) (void)pthread_join(t, res) - -#endif // ifdef _WIN32 - -static inline void thread_set_name_self(const char *name) { -#if defined(_WIN32) - wchar_t wname[256]; - if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, name, -1, wname, 256) > 0) { - HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); - if (kernel32) { - pfnSetThreadDescription pSetThreadDescription = - (pfnSetThreadDescription)GetProcAddress(kernel32, "SetThreadDescription"); - if (pSetThreadDescription) { - pSetThreadDescription(GetCurrentThread(), wname); - } - } - } -#elif defined(__linux__) - prctl(PR_SET_NAME, name); -#elif defined(__APPLE__) - pthread_setname_np(name); -#elif defined(__FreeBSD__) - pthread_set_name_np(pthread_self(), name); -#else - (void)name; -#endif -} - -#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) - -#include -#define atomic(T) _Atomic(T) -#define atomic_ptr(T) _Atomic(T *) - -#else // no atomics - -// Since we don't need compare-and-swap, just assume store and load are atomic -#define atomic(T) volatile T -#define atomic_ptr(T) T *volatile -#define atomic_store(a, v) (void)(*(a) = (v)) -#define atomic_load(a) (*(a)) -#define ATOMIC_VAR_INIT(v) (v) - -#endif // if atomics - -#endif // JUICE_THREAD_H diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.c deleted file mode 100644 index 2a7cc989..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "timestamp.h" - -#ifdef _WIN32 -#include -#else -#include - -// clock_gettime() is not implemented on older versions of OS X (< 10.12) -#if defined(__APPLE__) && !defined(CLOCK_MONOTONIC) -#include -#define CLOCK_MONOTONIC 0 -int clock_gettime(int clk_id, struct timespec *t) { - (void)clk_id; - - // gettimeofday() does not return monotonic time but it should be good enough. - struct timeval now; - if (gettimeofday(&now, NULL)) - return -1; - - t->tv_sec = now.tv_sec; - t->tv_nsec = now.tv_usec * 1000; - return 0; -} -#endif // defined(__APPLE__) && !defined(CLOCK_MONOTONIC) - -#endif - -timestamp_t current_timestamp() { -#ifdef _WIN32 - return (timestamp_t)GetTickCount(); -#else // POSIX - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts)) - return 0; - return (timestamp_t)ts.tv_sec * 1000 + (timestamp_t)ts.tv_nsec / 1000000; -#endif -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.h deleted file mode 100644 index fabc8bba..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/timestamp.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_TIMESTAMP_H -#define JUICE_TIMESTAMP_H - -#include -#include - -typedef int64_t timestamp_t; -typedef timestamp_t timediff_t; - -timestamp_t current_timestamp(); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/turn.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/turn.c deleted file mode 100644 index 5f4abdbe..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/turn.c +++ /dev/null @@ -1,495 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "turn.h" -#include "log.h" -#include "random.h" -#include "socket.h" - -#include - -static bool memory_is_zero(const void *data, size_t size) { - const char *d = data; - for (size_t i = 0; i < size; ++i) - if (d[i]) - return false; - - return true; -} - -static uint16_t random_channel_number() { - /* - * RFC 8656 12. Channels - * The ChannelData message (see Section 12.4) starts with a two-byte - * field that carries the channel number. The values of this field are - * allocated as follows: - * - * +------------------------+--------------------------------------+ - * | 0x0000 through 0x3FFF: | These values can never be used for | - * | | channel numbers. | - * +------------------------+--------------------------------------+ - * | 0x4000 through 0x4FFF: | These values are the allowed channel | - * | | numbers (4096 possible values). | - * +------------------------+--------------------------------------+ - * | 0x5000 through 0xFFFF: | Reserved (For DTLS-SRTP multiplexing | - * | | collision avoidance, see [RFC7983]). | - * +------------------------+--------------------------------------+ - */ - uint16_t r; - juice_random(&r, 2); - return 0x4000 | (r & 0x0FFF); -} - -bool is_channel_data(const void *data, size_t size) { - // According RFC 8656, first byte in [64..79] is TURN Channel - if (size == 0) - return false; - uint8_t b = *((const uint8_t *)data); - return b >= 64 && b <= 79; -} - -bool is_valid_channel(uint16_t channel) { return channel >= 0x4000; } - -int turn_wrap_channel_data(char *buffer, size_t size, const char *data, size_t data_size, - uint16_t channel) { - if (!is_valid_channel(channel)) { - JLOG_WARN("Invalid channel number: 0x%hX", channel); - return -1; - } - if (data_size >= 65536) { - JLOG_WARN("ChannelData is too long, size=%zu", size); - return -1; - } - if (size < sizeof(struct channel_data_header) + data_size) { - JLOG_WARN("Buffer is too small to add ChannelData header, size=%zu, needed=%zu", size, - sizeof(struct channel_data_header) + data_size); - return -1; - } - - memmove(buffer + sizeof(struct channel_data_header), data, data_size); - struct channel_data_header *header = (struct channel_data_header *)buffer; - header->channel_number = htons((uint16_t)channel); - header->length = htons((uint16_t)data_size); - return (int)(sizeof(struct channel_data_header) + data_size); -} - -static int find_ordered_channel_rec(turn_entry_t *const ordered_channels[], uint16_t channel, - int begin, int end) { - int d = end - begin; - if (d <= 0) - return begin; - - int pivot = begin + d / 2; - const turn_entry_t *entry = ordered_channels[pivot]; - if (channel < entry->channel) - return find_ordered_channel_rec(ordered_channels, channel, begin, pivot); - else if (channel > entry->channel) - return find_ordered_channel_rec(ordered_channels, channel, pivot + 1, end); - else - return pivot; -} - -static int find_ordered_channel(const turn_map_t *map, uint16_t channel) { - return find_ordered_channel_rec(map->ordered_channels, channel, 0, map->channels_count); -} - -static int find_ordered_transaction_id_rec(turn_entry_t *const ordered_transaction_ids[], - const uint8_t *transaction_id, int begin, int end) { - int d = end - begin; - if (d <= 0) - return begin; - - int pivot = begin + d / 2; - const turn_entry_t *entry = ordered_transaction_ids[pivot]; - int ret = memcmp(transaction_id, entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - if (ret < 0) - return find_ordered_transaction_id_rec(ordered_transaction_ids, transaction_id, begin, - pivot); - else if (ret > 0) - return find_ordered_transaction_id_rec(ordered_transaction_ids, transaction_id, pivot + 1, - end); - else - return pivot; -} - -static int find_ordered_transaction_id(const turn_map_t *map, const uint8_t *transaction_id) { - return find_ordered_transaction_id_rec(map->ordered_transaction_ids, transaction_id, 0, - map->transaction_ids_count); -} - -static void remove_ordered_transaction_id(turn_map_t *map, const uint8_t *transaction_id) { - int pos = find_ordered_transaction_id(map, transaction_id); - if (pos < map->transaction_ids_count) { - memmove(map->ordered_transaction_ids + pos, map->ordered_transaction_ids + pos + 1, - (map->transaction_ids_count - (pos + 1)) * sizeof(turn_entry_t *)); - map->transaction_ids_count--; - } -} -/* -static void remove_ordered_channel(turn_map_t *map, uint16_t channel) { - int pos = find_ordered_channel(map, channel); - if (pos < map->channels_count) { - memmove(map->ordered_channels + pos, map->ordered_channels + pos + 1, - (map->channels_count - (pos + 1)) * sizeof(turn_entry_t *)); - map->channels_count--; - } -} - -static void delete_entry(turn_map_t *map, turn_entry_t *entry) { - if (entry->type == TURN_ENTRY_TYPE_EMPTY || entry->type == TURN_ENTRY_TYPE_DELETED) - return; - - if (!memory_is_zero(entry->transaction_id, STUN_TRANSACTION_ID_SIZE)) - remove_ordered_transaction_id(map, entry->transaction_id); - - if (entry->type == TURN_ENTRY_TYPE_CHANNEL && entry->channel) - remove_ordered_channel(map, entry->channel); - - memset(entry, 0, sizeof(*entry)); - entry->type = TURN_ENTRY_TYPE_DELETED; -} -*/ -static turn_entry_t *find_entry(turn_map_t *map, const addr_record_t *record, - turn_entry_type_t type, bool allow_deleted) { - unsigned long key = (addr_record_hash(record, false) + (int)type) % map->map_size; - unsigned long pos = key; - while (true) { - turn_entry_t *entry = map->map + pos; - if (entry->type == TURN_ENTRY_TYPE_EMPTY || - (entry->type == type && addr_record_is_equal(&entry->record, record, false))) - break; - - if (allow_deleted && entry->type == TURN_ENTRY_TYPE_DELETED) - break; - - pos = (pos + 1) % map->map_size; - if (pos == key) { - JLOG_VERBOSE("TURN map is full"); - return NULL; - } - } - return map->map + pos; -} - -static bool update_timestamp(turn_map_t *map, turn_entry_type_t type, const uint8_t *transaction_id, - const addr_record_t *record, timediff_t duration) { - turn_entry_t *entry; - if (record) { - entry = find_entry(map, record, type, true); - if (!entry) - return false; - - if (entry->type == type) { - if (memcmp(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE) == 0) - return true; - } else { - entry->type = type; - entry->record = *record; - } - - if (!memory_is_zero(entry->transaction_id, STUN_TRANSACTION_ID_SIZE)) - remove_ordered_transaction_id(map, entry->transaction_id); - - memcpy(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - - } else { - int pos = find_ordered_transaction_id(map, transaction_id); - if (pos == map->transaction_ids_count) - return false; - - entry = map->ordered_transaction_ids[pos]; - if (entry->type != type || - memcmp(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE) != 0) - return false; - } - - entry->timestamp = current_timestamp() + duration; - entry->fresh_transaction_id = false; - return true; -} - -int turn_init_map(turn_map_t *map, int size) { - memset(map, 0, sizeof(*map)); - - map->map_size = size * 2; - map->channels_count = 0; - map->transaction_ids_count = 0; - - map->map = calloc(map->map_size, sizeof(turn_entry_t)); - map->ordered_channels = calloc(map->map_size, sizeof(turn_entry_t *)); - map->ordered_transaction_ids = calloc(map->map_size, sizeof(turn_entry_t *)); - - if (!map->map || !map->ordered_channels || !map->ordered_transaction_ids) { - JLOG_ERROR("Failed to allocate TURN map of size %d", size); - turn_destroy_map(map); - return -1; - } - - return 0; -} - -void turn_destroy_map(turn_map_t *map) { - free(map->map); - free(map->ordered_channels); - free(map->ordered_transaction_ids); -} - -bool turn_set_permission(turn_map_t *map, const uint8_t *transaction_id, - const addr_record_t *record, timediff_t duration) { - return update_timestamp(map, TURN_ENTRY_TYPE_PERMISSION, transaction_id, record, duration); -} - -bool turn_has_permission(turn_map_t *map, const addr_record_t *record) { - turn_entry_t *entry = find_entry(map, record, TURN_ENTRY_TYPE_PERMISSION, false); - if (!entry || entry->type != TURN_ENTRY_TYPE_PERMISSION) - return false; - - return current_timestamp() < entry->timestamp; -} - -bool turn_bind_channel(turn_map_t *map, const addr_record_t *record, const uint8_t *transaction_id, - uint16_t channel, timediff_t duration) { - if (!is_valid_channel(channel)) { - JLOG_ERROR("Invalid channel number: 0x%hX", channel); - return false; - } - - turn_entry_t *entry = find_entry(map, record, TURN_ENTRY_TYPE_CHANNEL, true); - if (!entry) - return false; - - if (entry->type == TURN_ENTRY_TYPE_CHANNEL && entry->channel) { - if (entry->channel != channel) { - JLOG_WARN("The record is already bound to a channel"); - return false; - } - - entry->timestamp = current_timestamp() + duration; - return true; - } - - int pos = find_ordered_channel(map, channel); - if (pos < map->channels_count) { - const turn_entry_t *other_entry = map->ordered_channels[pos]; - if (other_entry->channel == channel) { - JLOG_WARN("The channel is already bound to a record"); - return false; - } - } - - if (entry->type != TURN_ENTRY_TYPE_CHANNEL) { - entry->type = TURN_ENTRY_TYPE_CHANNEL; - entry->record = *record; - } - - memmove(map->ordered_channels + pos + 1, map->ordered_channels + pos, - (map->channels_count - pos) * sizeof(turn_entry_t *)); - map->ordered_channels[pos] = entry; - map->channels_count++; - - entry->channel = channel; - entry->timestamp = current_timestamp() + duration; - - if (transaction_id) { - memcpy(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - entry->fresh_transaction_id = true; - } - - return true; -} - -bool turn_bind_random_channel(turn_map_t *map, const addr_record_t *record, uint16_t *channel, - timediff_t duration) { - uint16_t c; - do { - c = random_channel_number(); - } while (turn_find_channel(map, c, NULL)); - - if (!turn_bind_channel(map, record, NULL, c, duration)) - return false; - - if (channel) - *channel = c; - - return true; -} - -bool turn_bind_current_channel(turn_map_t *map, const uint8_t *transaction_id, - const addr_record_t *record, timediff_t duration) { - return update_timestamp(map, TURN_ENTRY_TYPE_CHANNEL, transaction_id, record, duration); -} - -bool turn_get_channel(turn_map_t *map, const addr_record_t *record, uint16_t *channel) { - turn_entry_t *entry = find_entry(map, record, TURN_ENTRY_TYPE_CHANNEL, false); - if (!entry || entry->type != TURN_ENTRY_TYPE_CHANNEL) - return false; - - if (channel) - *channel = entry->channel; - - return true; -} - -bool turn_get_bound_channel(turn_map_t *map, const addr_record_t *record, uint16_t *channel) { - turn_entry_t *entry = find_entry(map, record, TURN_ENTRY_TYPE_CHANNEL, false); - if (!entry || entry->type != TURN_ENTRY_TYPE_CHANNEL) - return false; - - if (!entry->channel || current_timestamp() >= entry->timestamp) - return false; - - if (channel) - *channel = entry->channel; - - return true; -} - -bool turn_find_channel(turn_map_t *map, uint16_t channel, addr_record_t *record) { - if (!is_valid_channel(channel)) { - JLOG_WARN("Invalid channel number: 0x%hX", channel); - return false; - } - - int pos = find_ordered_channel(map, channel); - if (pos == map->channels_count) - return false; - - const turn_entry_t *entry = map->ordered_channels[pos]; - if (entry->channel != channel) - return false; - - if (record) - *record = entry->record; - - return true; -} - -bool turn_find_bound_channel(turn_map_t *map, uint16_t channel, addr_record_t *record) { - if (!is_valid_channel(channel)) { - JLOG_WARN("Invalid channel number: 0x%hX", channel); - return false; - } - - int pos = find_ordered_channel(map, channel); - if (pos == map->channels_count) - return false; - - const turn_entry_t *entry = map->ordered_channels[pos]; - if (entry->channel != channel || current_timestamp() >= entry->timestamp) - return false; - - if (record) - *record = entry->record; - - return true; -} - -static bool set_transaction_id(turn_map_t *map, turn_entry_type_t type, const addr_record_t *record, - const uint8_t *transaction_id) { - if (type != TURN_ENTRY_TYPE_PERMISSION && type != TURN_ENTRY_TYPE_CHANNEL) - return false; - - turn_entry_t *entry = find_entry(map, record, type, true); - if (!entry) - return false; - - if (entry->type == type && !memory_is_zero(entry->transaction_id, STUN_TRANSACTION_ID_SIZE)) - remove_ordered_transaction_id(map, entry->transaction_id); - - int pos = find_ordered_transaction_id(map, transaction_id); - memmove(map->ordered_transaction_ids + pos + 1, map->ordered_transaction_ids + pos, - (map->transaction_ids_count - pos) * sizeof(turn_entry_t *)); - map->ordered_transaction_ids[pos] = entry; - map->transaction_ids_count++; - - if (entry->type != type) { - entry->type = type; - entry->record = *record; - } - - memcpy(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE); - entry->fresh_transaction_id = true; - return true; -} - -static bool find_transaction_id(turn_map_t *map, const uint8_t *transaction_id, - addr_record_t *record) { - int pos = find_ordered_transaction_id(map, transaction_id); - if (pos == map->transaction_ids_count) - return false; - - const turn_entry_t *entry = map->ordered_transaction_ids[pos]; - if (memcmp(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE) != 0) - return false; - - if (record) - *record = entry->record; - - return true; -} - -static bool set_random_transaction_id(turn_map_t *map, turn_entry_type_t type, - const addr_record_t *record, uint8_t *transaction_id) { - turn_entry_t *entry = find_entry(map, record, type, false); - if (entry && entry->fresh_transaction_id) { - if (transaction_id) - memcpy(transaction_id, entry->transaction_id, STUN_TRANSACTION_ID_SIZE); - - return true; - } - - uint8_t tid[STUN_TRANSACTION_ID_SIZE]; - do { - juice_random(tid, STUN_TRANSACTION_ID_SIZE); - } while (find_transaction_id(map, tid, NULL)); - - if (!set_transaction_id(map, type, record, tid)) - return false; - - if (transaction_id) - memcpy(transaction_id, tid, STUN_TRANSACTION_ID_SIZE); - - return true; -} - -bool turn_set_permission_transaction_id(turn_map_t *map, const addr_record_t *record, - const uint8_t *transaction_id) { - return set_transaction_id(map, TURN_ENTRY_TYPE_PERMISSION, record, transaction_id); -} - -bool turn_set_channel_transaction_id(turn_map_t *map, const addr_record_t *record, - const uint8_t *transaction_id) { - return set_transaction_id(map, TURN_ENTRY_TYPE_CHANNEL, record, transaction_id); -} - -bool turn_set_random_permission_transaction_id(turn_map_t *map, const addr_record_t *record, - uint8_t *transaction_id) { - return set_random_transaction_id(map, TURN_ENTRY_TYPE_PERMISSION, record, transaction_id); -} - -bool turn_set_random_channel_transaction_id(turn_map_t *map, const addr_record_t *record, - uint8_t *transaction_id) { - return set_random_transaction_id(map, TURN_ENTRY_TYPE_CHANNEL, record, transaction_id); -} - -bool turn_retrieve_transaction_id(turn_map_t *map, const uint8_t *transaction_id, - addr_record_t *record) { - int pos = find_ordered_transaction_id(map, transaction_id); - if (pos == map->transaction_ids_count) - return false; - - turn_entry_t *entry = map->ordered_transaction_ids[pos]; - if (memcmp(entry->transaction_id, transaction_id, STUN_TRANSACTION_ID_SIZE) != 0) - return false; - - if (record) - *record = entry->record; - - entry->fresh_transaction_id = false; - return true; -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/turn.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/turn.h deleted file mode 100644 index c4e9fc60..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/turn.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_TURN_H -#define JUICE_TURN_H - -#include "addr.h" -#include "ice.h" -#include "juice.h" -#include "log.h" -#include "stun.h" -#include "timestamp.h" - -#include - -#pragma pack(push, 1) -/* - * TURN ChannelData Message - * See https://www.rfc-editor.org/rfc/rfc8656.html#section-12.4 - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Channel Number | Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * / Application Data / - * / / - * | | - * | +-------------------------------+ - * | | - * +-------------------------------+ - */ - -struct channel_data_header { - uint16_t channel_number; - uint16_t length; -}; - -#pragma pack(pop) - -bool is_channel_data(const void *data, size_t size); -bool is_valid_channel(uint16_t channel); - -int turn_wrap_channel_data(char *buffer, size_t size, const char *data, size_t data_size, - uint16_t channel); - -// TURN state map - -typedef enum turn_entry_type { - TURN_ENTRY_TYPE_EMPTY = 0, - TURN_ENTRY_TYPE_DELETED, - TURN_ENTRY_TYPE_PERMISSION, - TURN_ENTRY_TYPE_CHANNEL -} turn_entry_type_t; - -typedef struct turn_entry { - turn_entry_type_t type; - timestamp_t timestamp; - addr_record_t record; - uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE]; - uint16_t channel; - bool fresh_transaction_id; -} turn_entry_t; - -typedef struct turn_map { - turn_entry_t *map; - turn_entry_t **ordered_channels; - turn_entry_t **ordered_transaction_ids; - int map_size; - int channels_count; - int transaction_ids_count; -} turn_map_t; - -int turn_init_map(turn_map_t *map, int size); -void turn_destroy_map(turn_map_t *map); - -bool turn_set_permission(turn_map_t *map, const uint8_t *transaction_id, - const addr_record_t *record, // record may be NULL - timediff_t duration); -bool turn_has_permission(turn_map_t *map, const addr_record_t *record); - -bool turn_bind_channel(turn_map_t *map, const addr_record_t *record, - const uint8_t *transaction_id, // transaction_id may be NULL - uint16_t channel, timediff_t duration); -bool turn_bind_random_channel(turn_map_t *map, const addr_record_t *record, uint16_t *channel, - timediff_t duration); -bool turn_bind_current_channel(turn_map_t *map, const uint8_t *transaction_id, - const addr_record_t *record, // record may be NULL - timediff_t duration); -bool turn_get_channel(turn_map_t *map, const addr_record_t *record, uint16_t *channel); -bool turn_get_bound_channel(turn_map_t *map, const addr_record_t *record, uint16_t *channel); -bool turn_find_channel(turn_map_t *map, uint16_t channel, addr_record_t *record); -bool turn_find_bound_channel(turn_map_t *map, uint16_t channel, addr_record_t *record); - -bool turn_set_permission_transaction_id(turn_map_t *map, const addr_record_t *record, - const uint8_t *transaction_id); -bool turn_set_channel_transaction_id(turn_map_t *map, const addr_record_t *record, - const uint8_t *transaction_id); -bool turn_set_random_permission_transaction_id(turn_map_t *map, const addr_record_t *record, - uint8_t *transaction_id); -bool turn_set_random_channel_transaction_id(turn_map_t *map, const addr_record_t *record, - uint8_t *transaction_id); -bool turn_retrieve_transaction_id(turn_map_t *map, const uint8_t *transaction_id, - addr_record_t *record); -#endif diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/udp.c b/godot/thirdparty/libdatachannel/deps/libjuice/src/udp.c deleted file mode 100644 index 7c7582ed..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/udp.c +++ /dev/null @@ -1,604 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "udp.h" -#include "addr.h" -#include "log.h" -#include "random.h" -#include "thread.h" // for mutexes - -#include -#include -#include -#include - -static struct addrinfo *find_family(struct addrinfo *ai_list, int family) { - struct addrinfo *ai = ai_list; - while (ai && ai->ai_family != family) - ai = ai->ai_next; - return ai; -} - -static uint16_t get_next_port_in_range(uint16_t begin, uint16_t end) { - if (begin == 0) - begin = 1024; - if (end == 0) - end = 0xFFFF; - if (begin == end) - return begin; - - static volatile uint32_t count = 0; - if (count == 0) - count = juice_rand32(); - - static mutex_t mutex = MUTEX_INITIALIZER; - mutex_lock(&mutex); - uint32_t diff = end > begin ? end - begin : 0; - uint16_t next = begin + count++ % (diff + 1); - mutex_unlock(&mutex); - return next; -} - -socket_t udp_create_socket(const udp_socket_config_t *config) { - socket_t sock = INVALID_SOCKET; - - // Obtain local Address - struct addrinfo *ai_list = NULL; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; - if (getaddrinfo(config->bind_address, "0", &hints, &ai_list) != 0) { - JLOG_ERROR("getaddrinfo for binding address failed, errno=%d", sockerrno); - return INVALID_SOCKET; - } - - // Create socket - struct addrinfo *ai = NULL; - const int families[2] = {AF_INET6, AF_INET}; // Prefer IPv6 - const char *names[2] = {"IPv6", "IPv4"}; - for (int i = 0; i < 2; ++i) { - ai = find_family(ai_list, families[i]); - if (!ai) - continue; - - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock == INVALID_SOCKET) { - JLOG_WARN("UDP socket creation for %s family failed, errno=%d", names[i], sockerrno); - continue; - } - - break; - } - - if (sock == INVALID_SOCKET) { - JLOG_ERROR("UDP socket creation failed: no suitable address family"); - goto error; - } - - assert(ai != NULL); - - // Listen on both IPv6 and IPv4 - const sockopt_t disabled = 0; - if (ai->ai_family == AF_INET6) - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&disabled, sizeof(disabled)); - - // Set DF flag -#ifndef NO_PMTUDISC - const sockopt_t val = IP_PMTUDISC_DO; - setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, (const char *)&val, sizeof(val)); -#ifdef IPV6_MTU_DISCOVER - if (ai->ai_family == AF_INET6) - setsockopt(sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (const char *)&val, sizeof(val)); -#endif -#else - // It seems Mac OS lacks a way to set the DF flag... - const sockopt_t enabled = 1; -#ifdef IP_DONTFRAG - setsockopt(sock, IPPROTO_IP, IP_DONTFRAG, (const char *)&enabled, sizeof(enabled)); -#endif -#ifdef IPV6_DONTFRAG - if (ai->ai_family == AF_INET6) - setsockopt(sock, IPPROTO_IPV6, IPV6_DONTFRAG, (const char *)&enabled, sizeof(enabled)); -#endif -#endif - - // Set buffer size up to 1 MiB for performance - const sockopt_t buffer_size = 1 * 1024 * 1024; - setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char *)&buffer_size, sizeof(buffer_size)); - setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char *)&buffer_size, sizeof(buffer_size)); - - ctl_t nbio = 1; - if (ioctlsocket(sock, FIONBIO, &nbio)) { - JLOG_ERROR("Setting non-blocking mode on UDP socket failed, errno=%d", sockerrno); - goto error; - } - - // Bind it - if (config->port_begin == 0 && config->port_end == 0) { - if (bind(sock, ai->ai_addr, (socklen_t)ai->ai_addrlen) == 0) { - JLOG_DEBUG("UDP socket bound to %s:%hu", - config->bind_address ? config->bind_address : "any", udp_get_port(sock)); - freeaddrinfo(ai_list); - return sock; - } - - JLOG_ERROR("UDP socket binding failed, errno=%d", sockerrno); - - } else if (config->port_begin == config->port_end) { - uint16_t port = config->port_begin; - struct sockaddr_storage addr; - socklen_t addrlen = (socklen_t)ai->ai_addrlen; - memcpy(&addr, ai->ai_addr, addrlen); - addr_set_port((struct sockaddr *)&addr, port); - - if (bind(sock, (struct sockaddr *)&addr, addrlen) == 0) { - JLOG_DEBUG("UDP socket bound to %s:%hu", - config->bind_address ? config->bind_address : "any", port); - freeaddrinfo(ai_list); - return sock; - } - - JLOG_ERROR("UDP socket binding failed on port %hu, errno=%d", port, sockerrno); - - } else { - struct sockaddr_storage addr; - socklen_t addrlen = (socklen_t)ai->ai_addrlen; - memcpy(&addr, ai->ai_addr, addrlen); - - int retries = config->port_end - config->port_begin; - do { - uint16_t port = get_next_port_in_range(config->port_begin, config->port_end); - addr_set_port((struct sockaddr *)&addr, port); - if (bind(sock, (struct sockaddr *)&addr, addrlen) == 0) { - JLOG_DEBUG("UDP socket bound to %s:%hu", - config->bind_address ? config->bind_address : "any", port); - freeaddrinfo(ai_list); - return sock; - } - } while ((sockerrno == SEADDRINUSE || sockerrno == SEACCES) && retries-- > 0); - - JLOG_ERROR("UDP socket binding failed on port range %s:[%hu,%hu], errno=%d", - config->bind_address ? config->bind_address : "any", config->port_begin, - config->port_end, sockerrno); - } - -error: - freeaddrinfo(ai_list); - if (sock != INVALID_SOCKET) - closesocket(sock); - - return INVALID_SOCKET; -} - -int udp_recvfrom(socket_t sock, char *buffer, size_t size, addr_record_t *src) { - while (true) { - src->len = sizeof(src->addr); - int len = - recvfrom(sock, buffer, (socklen_t)size, 0, (struct sockaddr *)&src->addr, &src->len); - if (len >= 0) { - addr_unmap_inet6_v4mapped((struct sockaddr *)&src->addr, &src->len); - - } else if (sockerrno == SECONNRESET || sockerrno == SENETRESET || - sockerrno == SECONNREFUSED) { - // On Windows, if a UDP socket receives an ICMP port unreachable response after - // sending a datagram, this error is stored, and the next call to recvfrom() returns - // WSAECONNRESET (port unreachable) or WSAENETRESET (TTL expired). - // Therefore, it may be ignored. - JLOG_DEBUG("Ignoring %s returned by recvfrom", - sockerrno == SECONNRESET - ? "ECONNRESET" - : (sockerrno == SENETRESET ? "ENETRESET" : "ECONNREFUSED")); - continue; - } - return len; - } -} - -int udp_sendto(socket_t sock, const char *data, size_t size, const addr_record_t *dst) { -#ifndef __linux__ - addr_record_t tmp = *dst; - addr_record_t name; - name.len = sizeof(name.addr); - if (getsockname(sock, (struct sockaddr *)&name.addr, &name.len) == 0) { - if (name.addr.ss_family == AF_INET6) - addr_map_inet6_v4mapped(&tmp.addr, &tmp.len); - } else { - JLOG_WARN("getsockname failed, errno=%d", sockerrno); - } - return sendto(sock, data, (socklen_t)size, 0, (const struct sockaddr *)&tmp.addr, tmp.len); -#else - return sendto(sock, data, size, 0, (const struct sockaddr *)&dst->addr, dst->len); -#endif -} - -int udp_sendto_self(socket_t sock, const char *data, size_t size) { - addr_record_t local; - if (udp_get_local_addr(sock, AF_UNSPEC, &local) < 0) - return -1; - - int ret; -#ifndef __linux__ - // We know local has the same address family as sock here - ret = sendto(sock, data, (socklen_t)size, 0, (const struct sockaddr *)&local.addr, local.len); -#else - ret = sendto(sock, data, size, 0, (const struct sockaddr *)&local.addr, local.len); -#endif - if (ret >= 0 || local.addr.ss_family != AF_INET6) - return ret; - - // Fallback as IPv6 may be disabled on the loopback interface - if (udp_get_local_addr(sock, AF_INET, &local) < 0) - return -1; - -#ifndef __linux__ - addr_map_inet6_v4mapped(&local.addr, &local.len); - return sendto(sock, data, (socklen_t)size, 0, (const struct sockaddr *)&local.addr, local.len); -#else - return sendto(sock, data, size, 0, (const struct sockaddr *)&local.addr, local.len); -#endif -} - -int udp_set_diffserv(socket_t sock, int ds) { -#ifdef _WIN32 - // IP_TOS has been intentionally broken on Windows in favor of a convoluted proprietary - // mechanism called qWave. Thank you Microsoft! - // TODO: Investigate if DSCP can be still set directly without administrator flow configuration. - (void)sock; - (void)ds; - JLOG_INFO("IP Differentiated Services are not supported on Windows"); - return -1; -#else - addr_record_t name; - name.len = sizeof(name.addr); - if (getsockname(sock, (struct sockaddr *)&name.addr, &name.len) < 0) { - JLOG_WARN("getsockname failed, errno=%d", sockerrno); - return -1; - } - - switch (name.addr.ss_family) { - case AF_INET: -#ifdef IP_TOS - if (setsockopt(sock, IPPROTO_IP, IP_TOS, &ds, sizeof(ds)) < 0) { - JLOG_WARN("Setting IP ToS failed, errno=%d", sockerrno); - return -1; - } - return 0; -#else - JLOG_INFO("Setting IP ToS is not supported"); - return -1; -#endif - - case AF_INET6: -#ifdef IPV6_TCLASS - if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)) < 0) { - JLOG_WARN("Setting IPv6 traffic class failed, errno=%d", sockerrno); - return -1; - } -#ifdef IP_TOS - // Attempt to also set IP_TOS for IPv4, in case the system requires it - setsockopt(sock, IPPROTO_IP, IP_TOS, &ds, sizeof(ds)); -#endif - return 0; -#else - JLOG_INFO("Setting IPv6 traffic class is not supported"); - return -1; -#endif - default: - return -1; - } -#endif -} - -uint16_t udp_get_port(socket_t sock) { - addr_record_t record; - if (udp_get_bound_addr(sock, &record) < 0) - return 0; - return addr_get_port((struct sockaddr *)&record.addr); -} - -int udp_get_bound_addr(socket_t sock, addr_record_t *record) { - record->len = sizeof(record->addr); - if (getsockname(sock, (struct sockaddr *)&record->addr, &record->len)) { - JLOG_WARN("getsockname failed, errno=%d", sockerrno); - return -1; - } - return 0; -} - -int udp_get_local_addr(socket_t sock, int family_hint, addr_record_t *record) { - if (udp_get_bound_addr(sock, record) < 0) - return -1; - - // If the socket is bound to a particular address, return it - if (!addr_is_any((struct sockaddr *)&record->addr)) { - if (record->addr.ss_family == AF_INET && family_hint == AF_INET6) - addr_map_inet6_v4mapped(&record->addr, &record->len); - - return 0; - } - - if (record->addr.ss_family == AF_INET6 && family_hint == AF_INET) { - // Generate an IPv4 instead (socket is listening to any IPv4 or IPv6) - - uint16_t port = addr_get_port((struct sockaddr *)&record->addr); - if (port == 0) - return -1; - - struct sockaddr_in *sin = (struct sockaddr_in *)&record->addr; - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_port = htons(port); - record->len = sizeof(*sin); - } - - switch (record->addr.ss_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)&record->addr; - const uint8_t localhost[4] = {127, 0, 0, 1}; - memcpy(&sin->sin_addr, localhost, 4); - break; - } - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&record->addr; - uint8_t *b = (uint8_t *)&sin6->sin6_addr; - memset(b, 0, 15); - b[15] = 0x01; // localhost - break; - } - default: - // Ignore - break; - } - - if (record->addr.ss_family == AF_INET && family_hint == AF_INET6) - addr_map_inet6_v4mapped(&record->addr, &record->len); - - return 0; -} - -// Helper function to check if a similar address already exists in records -// This function ignores the port -static int has_duplicate_addr(struct sockaddr *addr, const addr_record_t *records, size_t count) { - for (size_t i = 0; i < count; ++i) { - const addr_record_t *record = records + i; - if (record->addr.ss_family == addr->sa_family) { - switch (addr->sa_family) { - case AF_INET: { - // For IPv4, compare the whole address - const struct sockaddr_in *rsin = (const struct sockaddr_in *)&record->addr; - const struct sockaddr_in *asin = (const struct sockaddr_in *)addr; - if (memcmp(&rsin->sin_addr, &asin->sin_addr, 4) == 0) - return true; - break; - } - case AF_INET6: { - // For IPv6, compare the network part only - const struct sockaddr_in6 *rsin6 = (const struct sockaddr_in6 *)&record->addr; - const struct sockaddr_in6 *asin6 = (const struct sockaddr_in6 *)addr; - if (memcmp(&rsin6->sin6_addr, &asin6->sin6_addr, 8) == 0) // compare first 64 bits - return true; - break; - } - } - } - } - return false; -} - -#if !defined(_WIN32) && defined(NO_IFADDRS) -// Helper function to get the IPv6 address of the default interface -static int get_local_default_inet6(uint16_t port, struct sockaddr_in6 *result) { - const char *dummy_host = "2001:db8::1"; // dummy public unreachable address - const uint16_t dummy_port = 9; // discard port - - struct sockaddr_in6 sin6; - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(dummy_port); - if (inet_pton(AF_INET6, dummy_host, &sin6.sin6_addr) != 1) - return -1; - - socket_t sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if (sock == INVALID_SOCKET) - return -1; - - if (connect(sock, (const struct sockaddr *)&sin6, sizeof(sin6))) - goto error; - - socklen_t result_len = sizeof(*result); - if (getsockname(sock, (struct sockaddr *)result, &result_len)) - goto error; - - if (result_len != sizeof(*result)) - goto error; - - addr_set_port((struct sockaddr *)result, port); - closesocket(sock); - return 0; - -error: - closesocket(sock); - return -1; -} -#endif - -int udp_get_addrs(socket_t sock, addr_record_t *records, size_t count) { - addr_record_t bound; - if (udp_get_bound_addr(sock, &bound) < 0) { - JLOG_ERROR("Getting UDP bound address failed"); - return -1; - } - - if (!addr_is_any((struct sockaddr *)&bound.addr)) { - if (count > 0) - records[0] = bound; - - return 1; - } - - uint16_t port = addr_get_port((struct sockaddr *)&bound.addr); - - // RFC 8445 5.1.1.1. Host Candidates: - // Addresses from a loopback interface MUST NOT be included in the candidate addresses. - // [...] - // If gathering one or more host candidates that correspond to an IPv6 address that was - // generated using a mechanism that prevents location tracking [RFC7721], host candidates - // that correspond to IPv6 addresses that do allow location tracking, are configured on the - // same interface, and are part of the same network prefix MUST NOT be gathered. Similarly, - // when host candidates corresponding to an IPv6 address generated using a mechanism that - // prevents location tracking are gathered, then host candidates corresponding to IPv6 - // link-local addresses [RFC4291] MUST NOT be gathered. The IPv6 default address selection - // specification [RFC6724] specifies that temporary addresses [RFC4941] are to be preferred - // over permanent addresses. - - // IPv6 IIDs generated by modern systems are opaque so there is no way to reliably differentiate - // privacy-enabled IPv6 addresses here. Therefore, we hope the preferred addresses are listed - // first, and we never list link-local addresses. - - addr_record_t *current = records; - addr_record_t *end = records + count; - int ret = 0; - -#if JUICE_ENABLE_LOCALHOST_ADDRESS - // Add localhost for test purposes - addr_record_t local; - if (bound.addr.ss_family == AF_INET6 && udp_get_local_addr(sock, AF_INET6, &local) == 0) { - ++ret; - if (current != end) { - *current = local; - ++current; - } - } - if (udp_get_local_addr(sock, AF_INET, &local) == 0) { - ++ret; - if (current != end) { - *current = local; - ++current; - } - } -#endif - -#ifdef _WIN32 - char buf[4096]; - DWORD len = 0; - if (WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf, sizeof(buf), &len, NULL, NULL)) { - JLOG_ERROR("WSAIoctl with SIO_ADDRESS_LIST_QUERY failed, errno=%d", WSAGetLastError()); - return -1; - } - - SOCKET_ADDRESS_LIST *list = (SOCKET_ADDRESS_LIST *)buf; - for (int i = 0; i < list->iAddressCount; ++i) { - struct sockaddr *sa = list->Address[i].lpSockaddr; - socklen_t len = list->Address[i].iSockaddrLength; - if ((sa->sa_family == AF_INET || - (sa->sa_family == AF_INET6 && bound.addr.ss_family == AF_INET6)) && - !addr_is_local(sa)) { - if (!has_duplicate_addr(sa, records, current - records)) { - ++ret; - if (current != end) { - memcpy(¤t->addr, sa, len); - current->len = len; - addr_unmap_inet6_v4mapped((struct sockaddr *)¤t->addr, ¤t->len); - addr_set_port((struct sockaddr *)¤t->addr, port); - ++current; - } - } - } - } -#else // POSIX -#ifndef NO_IFADDRS - struct ifaddrs *ifas; - if (getifaddrs(&ifas)) { - JLOG_ERROR("getifaddrs failed, errno=%d", sockerrno); - return -1; - } - - for (struct ifaddrs *ifa = ifas; ifa; ifa = ifa->ifa_next) { - unsigned int flags = ifa->ifa_flags; - if (!(flags & IFF_UP) || (flags & IFF_LOOPBACK)) - continue; - if (strcmp(ifa->ifa_name, "docker0") == 0) - continue; - - struct sockaddr *sa = ifa->ifa_addr; - socklen_t len; - if (sa && - (sa->sa_family == AF_INET || - (sa->sa_family == AF_INET6 && bound.addr.ss_family == AF_INET6)) && - !addr_is_local(sa) && (len = addr_get_len(sa)) > 0) { - if (!has_duplicate_addr(sa, records, current - records)) { - ++ret; - if (current != end) { - memcpy(¤t->addr, sa, len); - current->len = len; - addr_set_port((struct sockaddr *)¤t->addr, port); - ++current; - } - } - } - } - - freeifaddrs(ifas); - -#else // NO_IFADDRS defined - char buf[4096]; - struct ifconf ifc; - memset(&ifc, 0, sizeof(ifc)); - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; - - if (ioctlsocket(sock, SIOCGIFCONF, &ifc)) { - JLOG_ERROR("ioctl for SIOCGIFCONF failed, errno=%d", sockerrno); - return -1; - } - - bool ifconf_has_inet6 = false; - int n = ifc.ifc_len / sizeof(struct ifreq); - for (int i = 0; i < n; ++i) { - struct ifreq *ifr = ifc.ifc_req + i; - struct sockaddr *sa = &ifr->ifr_addr; - if (sa->sa_family == AF_INET6) - ifconf_has_inet6 = true; - - socklen_t len; - if ((sa->sa_family == AF_INET || - (sa->sa_family == AF_INET6 && bound.addr.ss_family == AF_INET6)) && - !addr_is_local(sa) && (len = addr_get_len(sa)) > 0) { - if (!has_duplicate_addr(sa, records, current - records)) { - ++ret; - if (current != end) { - memcpy(¤t->addr, sa, len); - current->len = len; - addr_set_port((struct sockaddr *)¤t->addr, port); - ++current; - } - } - } - } - - if (!ifconf_has_inet6 && bound.addr.ss_family == AF_INET6) { - struct sockaddr_in6 sin6; - if (get_local_default_inet6(port, &sin6) == 0) { - if (!addr_is_local((const struct sockaddr *)&sin6)) { - ++ret; - if (current != end) { - memcpy(¤t->addr, &sin6, sizeof(sin6)); - current->len = sizeof(sin6); - ++current; - } - } - } - } -#endif -#endif - - return ret; -} diff --git a/godot/thirdparty/libdatachannel/deps/libjuice/src/udp.h b/godot/thirdparty/libdatachannel/deps/libjuice/src/udp.h deleted file mode 100644 index c318eec0..00000000 --- a/godot/thirdparty/libdatachannel/deps/libjuice/src/udp.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef JUICE_UDP_H -#define JUICE_UDP_H - -#include "addr.h" -#include "socket.h" - -#include - -typedef struct udp_socket_config { - const char *bind_address; - uint16_t port_begin; - uint16_t port_end; -} udp_socket_config_t; - -socket_t udp_create_socket(const udp_socket_config_t *config); -int udp_recvfrom(socket_t sock, char *buffer, size_t size, addr_record_t *src); -int udp_sendto(socket_t sock, const char *data, size_t size, const addr_record_t *dst); -int udp_sendto_self(socket_t sock, const char *data, size_t size); -int udp_set_diffserv(socket_t sock, int ds); -uint16_t udp_get_port(socket_t sock); -int udp_get_bound_addr(socket_t sock, addr_record_t *record); -int udp_get_local_addr(socket_t sock, int family, addr_record_t *record); // family may be AF_UNSPEC -int udp_get_addrs(socket_t sock, addr_record_t *records, size_t count); - -#endif // JUICE_UDP_H diff --git a/godot/thirdparty/libdatachannel/deps/plog/LICENSE b/godot/thirdparty/libdatachannel/deps/plog/LICENSE deleted file mode 100644 index 8a91a0ae..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 Sergey Podobry - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/AndroidAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/AndroidAppender.h deleted file mode 100644 index 722488ab..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/AndroidAppender.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - template - class PLOG_LINKAGE_HIDDEN AndroidAppender : public IAppender - { - public: - AndroidAppender(const char* tag) : m_tag(tag) - { - } - - virtual void write(const Record& record) PLOG_OVERRIDE - { - std::string str = Formatter::format(record); - - __android_log_print(toPriority(record.getSeverity()), m_tag, "%s", str.c_str()); - } - - private: - static android_LogPriority toPriority(Severity severity) - { - switch (severity) - { - case fatal: - return ANDROID_LOG_FATAL; - case error: - return ANDROID_LOG_ERROR; - case warning: - return ANDROID_LOG_WARN; - case info: - return ANDROID_LOG_INFO; - case debug: - return ANDROID_LOG_DEBUG; - case verbose: - return ANDROID_LOG_VERBOSE; - default: - return ANDROID_LOG_UNKNOWN; - } - } - - private: - const char* const m_tag; - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ArduinoAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ArduinoAppender.h deleted file mode 100644 index 276af323..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ArduinoAppender.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - template - class PLOG_LINKAGE_HIDDEN ArduinoAppender : public IAppender - { - public: - ArduinoAppender(Stream &stream) : m_stream(stream) - { - } - - virtual void write(const Record &record) PLOG_OVERRIDE - { - m_stream.print(Formatter::format(record).c_str()); - } - - private: - Stream &m_stream; - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ColorConsoleAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ColorConsoleAppender.h deleted file mode 100644 index 24bbc7d9..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ColorConsoleAppender.h +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - template - class PLOG_LINKAGE_HIDDEN ColorConsoleAppender : public ConsoleAppender - { - public: -#ifdef _WIN32 -# ifdef _MSC_VER -# pragma warning(suppress: 26812) // Prefer 'enum class' over 'enum' -# endif - ColorConsoleAppender(OutputStream outStream = streamStdOut) - : ConsoleAppender(outStream) - , m_originalAttr() - { - if (this->m_isatty) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo(this->m_outputHandle, &csbiInfo); - - m_originalAttr = csbiInfo.wAttributes; - } - } -#else - ColorConsoleAppender(OutputStream outStream = streamStdOut) - : ConsoleAppender(outStream) - {} -#endif - - virtual void write(const Record& record) PLOG_OVERRIDE - { - util::nstring str = Formatter::format(record); - util::MutexLock lock(this->m_mutex); - - setColor(record.getSeverity()); - this->writestr(str); - resetColor(); - } - - protected: - void setColor(Severity severity) - { - if (this->m_isatty) - { - switch (severity) - { -#ifdef _WIN32 - case fatal: - SetConsoleTextAttribute(this->m_outputHandle, foreground::kRed | foreground::kGreen | foreground::kBlue | foreground::kIntensity | background::kRed); // white on red background - break; - - case error: - SetConsoleTextAttribute(this->m_outputHandle, static_cast(foreground::kRed | foreground::kIntensity | (m_originalAttr & 0xf0))); // red - break; - - case warning: - SetConsoleTextAttribute(this->m_outputHandle, static_cast(foreground::kRed | foreground::kGreen | foreground::kIntensity | (m_originalAttr & 0xf0))); // yellow - break; - - case debug: - case verbose: - SetConsoleTextAttribute(this->m_outputHandle, static_cast(foreground::kGreen | foreground::kBlue | foreground::kIntensity | (m_originalAttr & 0xf0))); // cyan - break; -#else - case fatal: - this->m_outputStream << "\x1B[97m\x1B[41m"; // white on red background - break; - - case error: - this->m_outputStream << "\x1B[91m"; // red - break; - - case warning: - this->m_outputStream << "\x1B[93m"; // yellow - break; - - case debug: - case verbose: - this->m_outputStream << "\x1B[96m"; // cyan - break; -#endif - default: - break; - } - } - } - - void resetColor() - { - if (this->m_isatty) - { -#ifdef _WIN32 - SetConsoleTextAttribute(this->m_outputHandle, m_originalAttr); -#else - this->m_outputStream << "\x1B[0m\x1B[0K"; -#endif - } - } - - private: -#ifdef _WIN32 - WORD m_originalAttr; -#endif - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ConsoleAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ConsoleAppender.h deleted file mode 100644 index a8925a04..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/ConsoleAppender.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace plog -{ - enum OutputStream - { - streamStdOut, - streamStdErr - }; - - template - class PLOG_LINKAGE_HIDDEN ConsoleAppender : public IAppender - { - public: -#ifdef _WIN32 -# ifdef _MSC_VER -# pragma warning(suppress: 26812) // Prefer 'enum class' over 'enum' -# endif - ConsoleAppender(OutputStream outStream = streamStdOut) - : m_isatty(!!_isatty(_fileno(outStream == streamStdOut ? stdout : stderr))) - , m_outputStream(outStream == streamStdOut ? std::cout : std::cerr) - , m_outputHandle() - { - if (m_isatty) - { - m_outputHandle = GetStdHandle(outStream == streamStdOut ? stdHandle::kOutput : stdHandle::kErrorOutput); - } - } -#else - ConsoleAppender(OutputStream outStream = streamStdOut) - : m_isatty(!!isatty(fileno(outStream == streamStdOut ? stdout : stderr))) - , m_outputStream(outStream == streamStdOut ? std::cout : std::cerr) - {} -#endif - - virtual void write(const Record& record) PLOG_OVERRIDE - { - util::nstring str = Formatter::format(record); - util::MutexLock lock(m_mutex); - - writestr(str); - } - - protected: - void writestr(const util::nstring& str) - { -#ifdef _WIN32 - if (m_isatty) - { - const std::wstring& wstr = util::toWide(str); - WriteConsoleW(m_outputHandle, wstr.c_str(), static_cast(wstr.size()), NULL, NULL); - } - else - { -# if PLOG_CHAR_IS_UTF8 - m_outputStream << str << std::flush; -# else - m_outputStream << util::toNarrow(str, codePage::kActive) << std::flush; -# endif - } -#else - m_outputStream << str << std::flush; -#endif - } - - private: -#ifdef __BORLANDC__ - static int _isatty(int fd) { return ::isatty(fd); } -#endif - - protected: - util::Mutex m_mutex; - const bool m_isatty; - std::ostream& m_outputStream; -#ifdef _WIN32 - HANDLE m_outputHandle; -#endif - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DebugOutputAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DebugOutputAppender.h deleted file mode 100644 index 5d7c95ef..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DebugOutputAppender.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - template - class PLOG_LINKAGE_HIDDEN DebugOutputAppender : public IAppender - { - public: - virtual void write(const Record& record) PLOG_OVERRIDE - { - OutputDebugStringW(util::toWide(Formatter::format(record)).c_str()); - } - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DynamicAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DynamicAppender.h deleted file mode 100644 index f078c08c..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/DynamicAppender.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - class PLOG_LINKAGE_HIDDEN DynamicAppender : public IAppender - { - public: - DynamicAppender& addAppender(IAppender* appender) - { - assert(appender != this); - - util::MutexLock lock(m_mutex); - m_appenders.insert(appender); - - return *this; - } - - DynamicAppender& removeAppender(IAppender* appender) - { - util::MutexLock lock(m_mutex); - m_appenders.erase(appender); - - return *this; - } - - virtual void write(const Record& record) PLOG_OVERRIDE - { - util::MutexLock lock(m_mutex); - - for (std::set::iterator it = m_appenders.begin(); it != m_appenders.end(); ++it) - { - (*it)->write(record); - } - } - - private: - mutable util::Mutex m_mutex; - std::set m_appenders; - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/EventLogAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/EventLogAppender.h deleted file mode 100644 index 3b7065be..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/EventLogAppender.h +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - template - class PLOG_LINKAGE_HIDDEN EventLogAppender : public IAppender - { - public: - EventLogAppender(const util::nchar* sourceName) : m_eventSource(RegisterEventSourceW(NULL, util::toWide(sourceName).c_str())) - { - } - - ~EventLogAppender() - { - DeregisterEventSource(m_eventSource); - } - - virtual void write(const Record& record) PLOG_OVERRIDE - { - util::nstring str = Formatter::format(record); - - write(record.getSeverity(), util::toWide(str).c_str()); - } - - private: - void write(Severity severity, const wchar_t* str) - { - const wchar_t* logMessagePtr[] = { str }; - - ReportEventW(m_eventSource, logSeverityToType(severity), static_cast(severity), 0, NULL, 1, 0, logMessagePtr, NULL); - } - - static WORD logSeverityToType(plog::Severity severity) - { - switch (severity) - { - case plog::fatal: - case plog::error: - return eventLog::kErrorType; - - case plog::warning: - return eventLog::kWarningType; - - case plog::info: - case plog::debug: - case plog::verbose: - default: - return eventLog::kInformationType; - } - } - - private: - HANDLE m_eventSource; - }; - - class EventLogAppenderRegistry - { - public: - static bool add(const util::nchar* sourceName, const util::nchar* logName = PLOG_NSTR("Application")) - { - std::wstring logKeyName; - std::wstring sourceKeyName; - getKeyNames(sourceName, logName, sourceKeyName, logKeyName); - - HKEY sourceKey; - if (0 != RegCreateKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, NULL, 0, regSam::kSetValue, NULL, &sourceKey, NULL)) - { - return false; - } - - const DWORD kTypesSupported = eventLog::kErrorType | eventLog::kWarningType | eventLog::kInformationType; - RegSetValueExW(sourceKey, L"TypesSupported", 0, regType::kDword, reinterpret_cast(&kTypesSupported), sizeof(kTypesSupported)); - - const wchar_t kEventMessageFile[] = L"%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\EventLogMessages.dll;%windir%\\Microsoft.NET\\Framework\\v2.0.50727\\EventLogMessages.dll"; - RegSetValueExW(sourceKey, L"EventMessageFile", 0, regType::kExpandSz, reinterpret_cast(kEventMessageFile), sizeof(kEventMessageFile) - sizeof(*kEventMessageFile)); - - RegCloseKey(sourceKey); - return true; - } - - static bool exists(const util::nchar* sourceName, const util::nchar* logName = PLOG_NSTR("Application")) - { - std::wstring logKeyName; - std::wstring sourceKeyName; - getKeyNames(sourceName, logName, sourceKeyName, logKeyName); - - HKEY sourceKey; - if (0 != RegOpenKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, regSam::kQueryValue, &sourceKey)) - { - return false; - } - - RegCloseKey(sourceKey); - return true; - } - - static void remove(const util::nchar* sourceName, const util::nchar* logName = PLOG_NSTR("Application")) - { - std::wstring logKeyName; - std::wstring sourceKeyName; - getKeyNames(sourceName, logName, sourceKeyName, logKeyName); - - RegDeleteKeyW(hkey::kLocalMachine, sourceKeyName.c_str()); - RegDeleteKeyW(hkey::kLocalMachine, logKeyName.c_str()); - } - - private: - static void getKeyNames(const util::nchar* sourceName, const util::nchar* logName, std::wstring& sourceKeyName, std::wstring& logKeyName) - { - const std::wstring kPrefix = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\"; - logKeyName = kPrefix + util::toWide(logName); - sourceKeyName = logKeyName + L"\\" + util::toWide(sourceName); - } - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/IAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/IAppender.h deleted file mode 100644 index 56b7827a..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/IAppender.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - class PLOG_LINKAGE IAppender - { - public: - virtual ~IAppender() - { - } - - virtual void write(const Record& record) = 0; - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/RollingFileAppender.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/RollingFileAppender.h deleted file mode 100644 index 3b667287..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Appenders/RollingFileAppender.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace plog -{ - template > - class PLOG_LINKAGE_HIDDEN RollingFileAppender : public IAppender - { - public: - RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) - : m_fileSize() - , m_maxFileSize() - , m_maxFiles(maxFiles) - , m_firstWrite(true) - { - setFileName(fileName); - setMaxFileSize(maxFileSize); - } - -#if defined(_WIN32) && !PLOG_CHAR_IS_UTF8 - RollingFileAppender(const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) - : m_fileSize() - , m_maxFileSize() - , m_maxFiles(maxFiles) - , m_firstWrite(true) - { - setFileName(fileName); - setMaxFileSize(maxFileSize); - } -#endif - - virtual void write(const Record& record) PLOG_OVERRIDE - { - util::MutexLock lock(m_mutex); - - if (m_firstWrite) - { - openLogFile(); - m_firstWrite = false; - } - else if (m_maxFiles > 0 && m_fileSize > m_maxFileSize && static_cast(-1) != m_fileSize) - { - rollLogFiles(); - } - - size_t bytesWritten = m_file.write(Converter::convert(Formatter::format(record))); - - if (static_cast(-1) != bytesWritten) - { - m_fileSize += bytesWritten; - } - } - - void setFileName(const util::nchar* fileName) - { - util::MutexLock lock(m_mutex); - - util::splitFileName(fileName, m_fileNameNoExt, m_fileExt); - - m_file.close(); - m_firstWrite = true; - } - -#if defined(_WIN32) && !PLOG_CHAR_IS_UTF8 - void setFileName(const char* fileName) - { - setFileName(util::toWide(fileName).c_str()); - } -#endif - - void setMaxFiles(int maxFiles) - { - m_maxFiles = maxFiles; - } - - void setMaxFileSize(size_t maxFileSize) - { - m_maxFileSize = (std::max)(maxFileSize, static_cast(1000)); // set a lower limit for the maxFileSize - } - - void rollLogFiles() - { - m_file.close(); - - util::nstring lastFileName = buildFileName(m_maxFiles - 1); - util::File::unlink(lastFileName); - - for (int fileNumber = m_maxFiles - 2; fileNumber >= 0; --fileNumber) - { - util::nstring currentFileName = buildFileName(fileNumber); - util::nstring nextFileName = buildFileName(fileNumber + 1); - - util::File::rename(currentFileName, nextFileName); - } - - openLogFile(); - m_firstWrite = false; - } - - private: - void openLogFile() - { - m_fileSize = m_file.open(buildFileName()); - - if (0 == m_fileSize) - { - size_t bytesWritten = m_file.write(Converter::header(Formatter::header())); - - if (static_cast(-1) != bytesWritten) - { - m_fileSize += bytesWritten; - } - } - } - - util::nstring buildFileName(int fileNumber = 0) - { - util::nostringstream ss; - ss << m_fileNameNoExt; - - if (fileNumber > 0) - { - ss << '.' << fileNumber; - } - - if (!m_fileExt.empty()) - { - ss << '.' << m_fileExt; - } - - return ss.str(); - } - - private: - util::Mutex m_mutex; - util::File m_file; - size_t m_fileSize; - size_t m_maxFileSize; - int m_maxFiles; - util::nstring m_fileExt; - util::nstring m_fileNameNoExt; - bool m_firstWrite; - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/NativeEOLConverter.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/NativeEOLConverter.h deleted file mode 100644 index a395e4e8..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/NativeEOLConverter.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - template - class NativeEOLConverter : public NextConverter - { -#ifdef _WIN32 - public: - static std::string header(const util::nstring& str) - { - return NextConverter::header(fixLineEndings(str)); - } - - static std::string convert(const util::nstring& str) - { - return NextConverter::convert(fixLineEndings(str)); - } - - private: - static util::nstring fixLineEndings(const util::nstring& str) - { - util::nstring output; - output.reserve(str.length() * 2); // the worst case requires 2x chars - - for (size_t i = 0; i < str.size(); ++i) - { - util::nchar ch = str[i]; - - if (ch == PLOG_NSTR('\n')) - { - output.push_back(PLOG_NSTR('\r')); - } - - output.push_back(ch); - } - - return output; - } -#endif - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/UTF8Converter.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/UTF8Converter.h deleted file mode 100644 index 9de5a630..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Converters/UTF8Converter.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - -namespace plog -{ - class UTF8Converter - { - public: - static std::string header(const util::nstring& str) - { - const char kBOM[] = "\xEF\xBB\xBF"; - - return std::string(kBOM) + convert(str); - } - -#if PLOG_CHAR_IS_UTF8 - static const std::string& convert(const util::nstring& str) - { - return str; - } -#else - static std::string convert(const util::nstring& str) - { - return util::toNarrow(str, codePage::kUTF8); - } -#endif - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/CsvFormatter.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/CsvFormatter.h deleted file mode 100644 index 282c57f1..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/CsvFormatter.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include -#include -#include - -namespace plog -{ - template - class CsvFormatterImpl - { - public: - static util::nstring header() - { - return PLOG_NSTR("Date;Time;Severity;TID;This;Function;Message\n"); - } - - static util::nstring format(const Record& record) - { - tm t; - useUtcTime ? util::gmtime_s(&t, &record.getTime().time) : util::localtime_s(&t, &record.getTime().time); - - util::nostringstream ss; - ss << t.tm_year + 1900 << PLOG_NSTR("/") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("/") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(";"); - ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << static_cast (record.getTime().millitm) << PLOG_NSTR(";"); - ss << severityToString(record.getSeverity()) << PLOG_NSTR(";"); - ss << record.getTid() << PLOG_NSTR(";"); - ss << record.getObject() << PLOG_NSTR(";"); - ss << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR(";"); - - util::nstring message = record.getMessage(); - - if (message.size() > kMaxMessageSize) - { - message.resize(kMaxMessageSize); - message.append(PLOG_NSTR("...")); - } - - util::nistringstream split(message); - util::nstring token; - - while (!split.eof()) - { - std::getline(split, token, PLOG_NSTR('"')); - ss << PLOG_NSTR("\"") << token << PLOG_NSTR("\""); - } - - ss << PLOG_NSTR("\n"); - - return ss.str(); - } - - static const size_t kMaxMessageSize = 32000; - }; - - class CsvFormatter : public CsvFormatterImpl {}; - class CsvFormatterUtcTime : public CsvFormatterImpl {}; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/FuncMessageFormatter.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/FuncMessageFormatter.h deleted file mode 100644 index aa57806b..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/FuncMessageFormatter.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - class FuncMessageFormatter - { - public: - static util::nstring header() - { - return util::nstring(); - } - - static util::nstring format(const Record& record) - { - util::nostringstream ss; - ss << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR(": ") << record.getMessage() << PLOG_NSTR("\n"); - - return ss.str(); - } - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/MessageOnlyFormatter.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/MessageOnlyFormatter.h deleted file mode 100644 index b2db5a5a..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/MessageOnlyFormatter.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - class MessageOnlyFormatter - { - public: - static util::nstring header() - { - return util::nstring(); - } - - static util::nstring format(const Record& record) - { - util::nostringstream ss; - ss << record.getMessage() << PLOG_NSTR("\n"); - - return ss.str(); - } - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/TxtFormatter.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/TxtFormatter.h deleted file mode 100644 index 48e2d50b..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Formatters/TxtFormatter.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include -#include - -namespace plog -{ - template - class TxtFormatterImpl - { - public: - static util::nstring header() - { - return util::nstring(); - } - - static util::nstring format(const Record& record) - { - tm t; - useUtcTime ? util::gmtime_s(&t, &record.getTime().time) : util::localtime_s(&t, &record.getTime().time); - - util::nostringstream ss; - ss << t.tm_year + 1900 << "-" << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("-") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(" "); - ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << static_cast (record.getTime().millitm) << PLOG_NSTR(" "); - ss << std::setfill(PLOG_NSTR(' ')) << std::setw(5) << std::left << severityToString(record.getSeverity()) << PLOG_NSTR(" "); - ss << PLOG_NSTR("[") << record.getTid() << PLOG_NSTR("] "); - ss << PLOG_NSTR("[") << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR("] "); - ss << record.getMessage() << PLOG_NSTR("\n"); - - return ss.str(); - } - }; - - class TxtFormatter : public TxtFormatterImpl {}; - class TxtFormatterUtcTime : public TxtFormatterImpl {}; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/AscDump.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/AscDump.h deleted file mode 100644 index 18b9a6f4..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/AscDump.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - class AscDump - { - public: - AscDump(const void* ptr, size_t size) - : m_ptr(static_cast(ptr)) - , m_size(size) - { - } - - friend util::nostringstream& operator<<(util::nostringstream& stream, const AscDump& ascDump); - - private: - const char* m_ptr; - size_t m_size; - }; - - inline util::nostringstream& operator<<(util::nostringstream& stream, const AscDump& ascDump) - { - for (size_t i = 0; i < ascDump.m_size; ++i) - { - stream << (std::isprint(ascDump.m_ptr[i]) ? ascDump.m_ptr[i] : '.'); - } - - return stream; - } - - inline AscDump ascdump(const void* ptr, size_t size) { return AscDump(ptr, size); } - - template - inline AscDump ascdump(const Container& container) { return AscDump(container.data(), container.size() * sizeof(*container.data())); } - - template - inline AscDump ascdump(const T (&arr)[N]) { return AscDump(arr, N * sizeof(*arr)); } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/HexDump.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/HexDump.h deleted file mode 100644 index b0493d70..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/HexDump.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - class HexDump - { - public: - HexDump(const void* ptr, size_t size) - : m_ptr(static_cast(ptr)) - , m_size(size) - , m_group(8) - , m_digitSeparator(" ") - , m_groupSeparator(" ") - { - } - - HexDump& group(size_t group) - { - m_group = group; - return *this; - } - - HexDump& separator(const char* digitSeparator) - { - m_digitSeparator = digitSeparator; - return *this; - } - - HexDump& separator(const char* digitSeparator, const char* groupSeparator) - { - m_digitSeparator = digitSeparator; - m_groupSeparator = groupSeparator; - return *this; - } - - friend util::nostringstream& operator<<(util::nostringstream& stream, const HexDump&); - - private: - const unsigned char* m_ptr; - size_t m_size; - size_t m_group; - const char* m_digitSeparator; - const char* m_groupSeparator; - }; - - inline util::nostringstream& operator<<(util::nostringstream& stream, const HexDump& hexDump) - { - stream << std::hex << std::setfill(PLOG_NSTR('0')); - - for (size_t i = 0; i < hexDump.m_size;) - { - stream << std::setw(2) << static_cast(hexDump.m_ptr[i]); - - if (++i < hexDump.m_size) - { - if (hexDump.m_group > 0 && i % hexDump.m_group == 0) - { - stream << hexDump.m_groupSeparator; - } - else - { - stream << hexDump.m_digitSeparator; - } - } - } - - return stream; - } - - inline HexDump hexdump(const void* ptr, size_t size) { return HexDump(ptr, size); } - - template - inline HexDump hexdump(const Container& container) { return HexDump(container.data(), container.size() * sizeof(*container.data())); } - - template - inline HexDump hexdump(const T (&arr)[N]) { return HexDump(arr, N * sizeof(*arr)); } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/PrintVar.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/PrintVar.h deleted file mode 100644 index 465e1938..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Helpers/PrintVar.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#define PLOG_IMPL_PRINT_VAR_1(a1) #a1 ": " << a1 -#define PLOG_IMPL_PRINT_VAR_2(a1, a2) PLOG_IMPL_PRINT_VAR_1(a1) PLOG_IMPL_PRINT_VAR_TAIL(a2) -#define PLOG_IMPL_PRINT_VAR_3(a1, a2, a3) PLOG_IMPL_PRINT_VAR_2(a1, a2) PLOG_IMPL_PRINT_VAR_TAIL(a3) -#define PLOG_IMPL_PRINT_VAR_4(a1, a2, a3, a4) PLOG_IMPL_PRINT_VAR_3(a1, a2, a3) PLOG_IMPL_PRINT_VAR_TAIL(a4) -#define PLOG_IMPL_PRINT_VAR_5(a1, a2, a3, a4, a5) PLOG_IMPL_PRINT_VAR_4(a1, a2, a3, a4) PLOG_IMPL_PRINT_VAR_TAIL(a5) -#define PLOG_IMPL_PRINT_VAR_6(a1, a2, a3, a4, a5, a6) PLOG_IMPL_PRINT_VAR_5(a1, a2, a3, a4, a5) PLOG_IMPL_PRINT_VAR_TAIL(a6) -#define PLOG_IMPL_PRINT_VAR_7(a1, a2, a3, a4, a5, a6, a7) PLOG_IMPL_PRINT_VAR_6(a1, a2, a3, a4, a5, a6) PLOG_IMPL_PRINT_VAR_TAIL(a7) -#define PLOG_IMPL_PRINT_VAR_8(a1, a2, a3, a4, a5, a6, a7, a8) PLOG_IMPL_PRINT_VAR_7(a1, a2, a3, a4, a5, a6, a7) PLOG_IMPL_PRINT_VAR_TAIL(a8) -#define PLOG_IMPL_PRINT_VAR_9(a1, a2, a3, a4, a5, a6, a7, a8, a9) PLOG_IMPL_PRINT_VAR_8(a1, a2, a3, a4, a5, a6, a7, a8) PLOG_IMPL_PRINT_VAR_TAIL(a9) -#define PLOG_IMPL_PRINT_VAR_TAIL(a) << ", " PLOG_IMPL_PRINT_VAR_1(a) - -#define PLOG_IMPL_PRINT_VAR_EXPAND(x) x - -#ifdef __GNUC__ -#pragma GCC system_header // disable warning: variadic macros are a C99 feature -#endif - -#define PLOG_IMPL_PRINT_VAR_GET_MACRO(x1, x2, x3, x4, x5, x6, x7, x8, x9, NAME, ...) NAME - -#define PLOG_PRINT_VAR(...) PLOG_IMPL_PRINT_VAR_EXPAND(PLOG_IMPL_PRINT_VAR_GET_MACRO(__VA_ARGS__,\ - PLOG_IMPL_PRINT_VAR_9, PLOG_IMPL_PRINT_VAR_8, PLOG_IMPL_PRINT_VAR_7, PLOG_IMPL_PRINT_VAR_6, PLOG_IMPL_PRINT_VAR_5,\ - PLOG_IMPL_PRINT_VAR_4, PLOG_IMPL_PRINT_VAR_3, PLOG_IMPL_PRINT_VAR_2, PLOG_IMPL_PRINT_VAR_1, UNUSED)(__VA_ARGS__)) diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Init.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Init.h deleted file mode 100644 index 615c41d6..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Init.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -namespace plog -{ - template - PLOG_LINKAGE_HIDDEN inline Logger& init(Severity maxSeverity = none, IAppender* appender = NULL) - { - static Logger logger(maxSeverity); - return appender ? logger.addAppender(appender) : logger; - } - - inline Logger& init(Severity maxSeverity = none, IAppender* appender = NULL) - { - return init(maxSeverity, appender); - } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/ConsoleInitializer.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/ConsoleInitializer.h deleted file mode 100644 index 5b504abd..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/ConsoleInitializer.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include -#include - -namespace plog -{ - ////////////////////////////////////////////////////////////////////////// - // ColorConsoleAppender with any Formatter - - template - PLOG_LINKAGE_HIDDEN inline Logger& init(Severity maxSeverity, OutputStream outputStream) - { - static ColorConsoleAppender appender(outputStream); - return init(maxSeverity, &appender); - } - - template - inline Logger& init(Severity maxSeverity, OutputStream outputStream) - { - return init(maxSeverity, outputStream); - } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/RollingFileInitializer.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/RollingFileInitializer.h deleted file mode 100644 index dc0adda1..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Initializers/RollingFileInitializer.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace plog -{ - ////////////////////////////////////////////////////////////////////////// - // RollingFileAppender with any Formatter - - template - PLOG_LINKAGE_HIDDEN inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - static RollingFileAppender rollingFileAppender(fileName, maxFileSize, maxFiles); - return init(maxSeverity, &rollingFileAppender); - } - - template - inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return init(maxSeverity, fileName, maxFileSize, maxFiles); - } - - ////////////////////////////////////////////////////////////////////////// - // RollingFileAppender with TXT/CSV chosen by file extension - - namespace - { - inline bool isCsv(const util::nchar* fileName) - { - const util::nchar* dot = util::findExtensionDot(fileName); -#if PLOG_CHAR_IS_UTF8 - return dot && 0 == std::strcmp(dot, ".csv"); -#else - return dot && 0 == std::wcscmp(dot, L".csv"); -#endif - } - } - - template - inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return isCsv(fileName) ? init(maxSeverity, fileName, maxFileSize, maxFiles) : init(maxSeverity, fileName, maxFileSize, maxFiles); - } - - inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return init(maxSeverity, fileName, maxFileSize, maxFiles); - } - - ////////////////////////////////////////////////////////////////////////// - // CHAR variants for Windows - -#if defined(_WIN32) && !PLOG_CHAR_IS_UTF8 - template - inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return init(maxSeverity, util::toWide(fileName).c_str(), maxFileSize, maxFiles); - } - - template - inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return init(maxSeverity, fileName, maxFileSize, maxFiles); - } - - template - inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return init(maxSeverity, util::toWide(fileName).c_str(), maxFileSize, maxFiles); - } - - inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) - { - return init(maxSeverity, fileName, maxFileSize, maxFiles); - } -#endif -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Log.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Log.h deleted file mode 100644 index bbfb0e49..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Log.h +++ /dev/null @@ -1,242 +0,0 @@ -////////////////////////////////////////////////////////////////////////// -// Plog - portable and simple log for C++ -// Documentation and sources: https://github.com/SergiusTheBest/plog -// License: MIT, https://choosealicense.com/licenses/mit - -#pragma once - -#if defined(GODOT_PLOG_DISABLE_LOG) - -#include -#include -#include - -#define PLOG_GET_FUNC() "" -#define PLOG_GET_THIS() reinterpret_cast(0) -#define PLOG_GET_FILE() "" - -class NullLog { -public: - template NullLog &operator<<(const T&) { return *this; } -}; - -namespace plog { - class Logger_ { - public: - Severity getMaxSeverity() const { return none; } - }; - inline Logger_ *get() { return nullptr; } -} - -#define PLOG_DEFAULT_INSTANCE_ID 0 - -#define PLOG_(inst, sev) NullLog() -#define PLOG(sev) NullLog() - -#ifdef _MSC_VER -# define IF_PLOG_(instanceId, severity) __pragma(warning(push)) __pragma(warning(disable:4127)) if (true) {;} else __pragma(warning(pop)) // conditional expression is constant -#else -# define IF_PLOG_(instanceId, severity) if (true) {;} else -#endif -#define IF_PLOG(severity) IF_PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity) - -#else // defined(GODOT_PLOG_DISABLE_LOG) - -#include - -////////////////////////////////////////////////////////////////////////// -// Helper macros that get context info - -#if defined(PLOG_ENABLE_GET_THIS) && defined(_MSC_VER) && _MSC_VER >= 1600 && !defined(__INTELLISENSE__) && !defined(__INTEL_COMPILER) && !defined(__llvm__) && !defined(__RESHARPER__) // >= Visual Studio 2010, skip IntelliSense, Intel Compiler, Clang Code Model and ReSharper -# define PLOG_GET_THIS() __if_exists(this) { this } __if_not_exists(this) { 0 } -#else -# define PLOG_GET_THIS() reinterpret_cast(0) -#endif - -#ifdef _MSC_VER -# define PLOG_GET_FUNC() __FUNCTION__ -#elif defined(__BORLANDC__) -# define PLOG_GET_FUNC() __FUNC__ -#else -# define PLOG_GET_FUNC() __PRETTY_FUNCTION__ -#endif - -#ifdef PLOG_CAPTURE_FILE -# define PLOG_GET_FILE() __FILE__ -#else -# define PLOG_GET_FILE() "" -#endif - -////////////////////////////////////////////////////////////////////////// -// Log severity level checker - -#ifdef PLOG_DISABLE_LOGGING -# ifdef _MSC_VER -# define IF_PLOG_(instanceId, severity) __pragma(warning(push)) __pragma(warning(disable:4127)) if (true) {;} else __pragma(warning(pop)) // conditional expression is constant -# else -# define IF_PLOG_(instanceId, severity) if (true) {;} else -# endif -#else -# define IF_PLOG_(instanceId, severity) if (!plog::get() || !plog::get()->checkSeverity(severity)) {;} else -#endif - -#define IF_PLOG(severity) IF_PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity) - -////////////////////////////////////////////////////////////////////////// -// Main logging macros - -#define PLOG_(instanceId, severity) IF_PLOG_(instanceId, severity) (*plog::get()) += plog::Record(severity, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS(), instanceId).ref() -#define PLOG(severity) PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity) - -#endif // !defined(GODOT_PLOG_DISABLE_LOG) - -#define PLOG_VERBOSE PLOG(plog::verbose) -#define PLOG_DEBUG PLOG(plog::debug) -#define PLOG_INFO PLOG(plog::info) -#define PLOG_WARNING PLOG(plog::warning) -#define PLOG_ERROR PLOG(plog::error) -#define PLOG_FATAL PLOG(plog::fatal) -#define PLOG_NONE PLOG(plog::none) - -#define PLOG_VERBOSE_(instanceId) PLOG_(instanceId, plog::verbose) -#define PLOG_DEBUG_(instanceId) PLOG_(instanceId, plog::debug) -#define PLOG_INFO_(instanceId) PLOG_(instanceId, plog::info) -#define PLOG_WARNING_(instanceId) PLOG_(instanceId, plog::warning) -#define PLOG_ERROR_(instanceId) PLOG_(instanceId, plog::error) -#define PLOG_FATAL_(instanceId) PLOG_(instanceId, plog::fatal) -#define PLOG_NONE_(instanceId) PLOG_(instanceId, plog::none) - -#define PLOGV PLOG_VERBOSE -#define PLOGD PLOG_DEBUG -#define PLOGI PLOG_INFO -#define PLOGW PLOG_WARNING -#define PLOGE PLOG_ERROR -#define PLOGF PLOG_FATAL -#define PLOGN PLOG_NONE - -#define PLOGV_(instanceId) PLOG_VERBOSE_(instanceId) -#define PLOGD_(instanceId) PLOG_DEBUG_(instanceId) -#define PLOGI_(instanceId) PLOG_INFO_(instanceId) -#define PLOGW_(instanceId) PLOG_WARNING_(instanceId) -#define PLOGE_(instanceId) PLOG_ERROR_(instanceId) -#define PLOGF_(instanceId) PLOG_FATAL_(instanceId) -#define PLOGN_(instanceId) PLOG_NONE_(instanceId) - -////////////////////////////////////////////////////////////////////////// -// Conditional logging macros - -#define PLOG_IF_(instanceId, severity, condition) if (!(condition)) {;} else PLOG_(instanceId, severity) -#define PLOG_IF(severity, condition) PLOG_IF_(PLOG_DEFAULT_INSTANCE_ID, severity, condition) - -#define PLOG_VERBOSE_IF(condition) PLOG_IF(plog::verbose, condition) -#define PLOG_DEBUG_IF(condition) PLOG_IF(plog::debug, condition) -#define PLOG_INFO_IF(condition) PLOG_IF(plog::info, condition) -#define PLOG_WARNING_IF(condition) PLOG_IF(plog::warning, condition) -#define PLOG_ERROR_IF(condition) PLOG_IF(plog::error, condition) -#define PLOG_FATAL_IF(condition) PLOG_IF(plog::fatal, condition) -#define PLOG_NONE_IF(condition) PLOG_IF(plog::none, condition) - -#define PLOG_VERBOSE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::verbose, condition) -#define PLOG_DEBUG_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::debug, condition) -#define PLOG_INFO_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::info, condition) -#define PLOG_WARNING_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::warning, condition) -#define PLOG_ERROR_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::error, condition) -#define PLOG_FATAL_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::fatal, condition) -#define PLOG_NONE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::none, condition) - -#define PLOGV_IF(condition) PLOG_VERBOSE_IF(condition) -#define PLOGD_IF(condition) PLOG_DEBUG_IF(condition) -#define PLOGI_IF(condition) PLOG_INFO_IF(condition) -#define PLOGW_IF(condition) PLOG_WARNING_IF(condition) -#define PLOGE_IF(condition) PLOG_ERROR_IF(condition) -#define PLOGF_IF(condition) PLOG_FATAL_IF(condition) -#define PLOGN_IF(condition) PLOG_NONE_IF(condition) - -#define PLOGV_IF_(instanceId, condition) PLOG_VERBOSE_IF_(instanceId, condition) -#define PLOGD_IF_(instanceId, condition) PLOG_DEBUG_IF_(instanceId, condition) -#define PLOGI_IF_(instanceId, condition) PLOG_INFO_IF_(instanceId, condition) -#define PLOGW_IF_(instanceId, condition) PLOG_WARNING_IF_(instanceId, condition) -#define PLOGE_IF_(instanceId, condition) PLOG_ERROR_IF_(instanceId, condition) -#define PLOGF_IF_(instanceId, condition) PLOG_FATAL_IF_(instanceId, condition) -#define PLOGN_IF_(instanceId, condition) PLOG_NONE_IF_(instanceId, condition) - -// Old macro names for downward compatibility. To bypass including these macro names, add -// #define PLOG_OMIT_LOG_DEFINES before #include -#ifndef PLOG_OMIT_LOG_DEFINES - -////////////////////////////////////////////////////////////////////////// -// Main logging macros - can be changed later to point at macros for a different logging package - -#define LOG_(instanceId, severity) IF_PLOG_(instanceId, severity) (*plog::get()) += plog::Record(severity, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS(), instanceId).ref() -#define LOG(severity) PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity) - -#define LOG_VERBOSE PLOG(plog::verbose) -#define LOG_DEBUG PLOG(plog::debug) -#define LOG_INFO PLOG(plog::info) -#define LOG_WARNING PLOG(plog::warning) -#define LOG_ERROR PLOG(plog::error) -#define LOG_FATAL PLOG(plog::fatal) -#define LOG_NONE PLOG(plog::none) - -#define LOG_VERBOSE_(instanceId) PLOG_(instanceId, plog::verbose) -#define LOG_DEBUG_(instanceId) PLOG_(instanceId, plog::debug) -#define LOG_INFO_(instanceId) PLOG_(instanceId, plog::info) -#define LOG_WARNING_(instanceId) PLOG_(instanceId, plog::warning) -#define LOG_ERROR_(instanceId) PLOG_(instanceId, plog::error) -#define LOG_FATAL_(instanceId) PLOG_(instanceId, plog::fatal) -#define LOG_NONE_(instanceId) PLOG_(instanceId, plog::none) - -#define LOGV PLOG_VERBOSE -#define LOGD PLOG_DEBUG -#define LOGI PLOG_INFO -#define LOGW PLOG_WARNING -#define LOGE PLOG_ERROR -#define LOGF PLOG_FATAL -#define LOGN PLOG_NONE - -#define LOGV_(instanceId) PLOG_VERBOSE_(instanceId) -#define LOGD_(instanceId) PLOG_DEBUG_(instanceId) -#define LOGI_(instanceId) PLOG_INFO_(instanceId) -#define LOGW_(instanceId) PLOG_WARNING_(instanceId) -#define LOGE_(instanceId) PLOG_ERROR_(instanceId) -#define LOGF_(instanceId) PLOG_FATAL_(instanceId) -#define LOGN_(instanceId) PLOG_NONE_(instanceId) - -////////////////////////////////////////////////////////////////////////// -// Conditional logging macros - -#define LOG_IF_(instanceId, severity, condition) if (!(condition)) {;} else PLOG_(instanceId, severity) -#define LOG_IF(severity, condition) PLOG_IF_(PLOG_DEFAULT_INSTANCE_ID, severity, condition) - -#define LOG_VERBOSE_IF(condition) PLOG_IF(plog::verbose, condition) -#define LOG_DEBUG_IF(condition) PLOG_IF(plog::debug, condition) -#define LOG_INFO_IF(condition) PLOG_IF(plog::info, condition) -#define LOG_WARNING_IF(condition) PLOG_IF(plog::warning, condition) -#define LOG_ERROR_IF(condition) PLOG_IF(plog::error, condition) -#define LOG_FATAL_IF(condition) PLOG_IF(plog::fatal, condition) -#define LOG_NONE_IF(condition) PLOG_IF(plog::none, condition) - -#define LOG_VERBOSE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::verbose, condition) -#define LOG_DEBUG_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::debug, condition) -#define LOG_INFO_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::info, condition) -#define LOG_WARNING_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::warning, condition) -#define LOG_ERROR_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::error, condition) -#define LOG_FATAL_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::fatal, condition) -#define LOG_NONE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::none, condition) - -#define LOGV_IF(condition) PLOG_VERBOSE_IF(condition) -#define LOGD_IF(condition) PLOG_DEBUG_IF(condition) -#define LOGI_IF(condition) PLOG_INFO_IF(condition) -#define LOGW_IF(condition) PLOG_WARNING_IF(condition) -#define LOGE_IF(condition) PLOG_ERROR_IF(condition) -#define LOGF_IF(condition) PLOG_FATAL_IF(condition) -#define LOGN_IF(condition) PLOG_NONE_IF(condition) - -#define LOGV_IF_(instanceId, condition) PLOG_VERBOSE_IF_(instanceId, condition) -#define LOGD_IF_(instanceId, condition) PLOG_DEBUG_IF_(instanceId, condition) -#define LOGI_IF_(instanceId, condition) PLOG_INFO_IF_(instanceId, condition) -#define LOGW_IF_(instanceId, condition) PLOG_WARNING_IF_(instanceId, condition) -#define LOGE_IF_(instanceId, condition) PLOG_ERROR_IF_(instanceId, condition) -#define LOGF_IF_(instanceId, condition) PLOG_FATAL_IF_(instanceId, condition) -#define LOGN_IF_(instanceId, condition) PLOG_NONE_IF_(instanceId, condition) -#endif diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Logger.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Logger.h deleted file mode 100644 index 0e116e4c..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Logger.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include -#include -#include - -#ifdef PLOG_DEFAULT_INSTANCE // for backward compatibility -# define PLOG_DEFAULT_INSTANCE_ID PLOG_DEFAULT_INSTANCE -#endif - -#ifndef PLOG_DEFAULT_INSTANCE_ID -# define PLOG_DEFAULT_INSTANCE_ID 0 -#endif - -namespace plog -{ - template - class PLOG_LINKAGE Logger : public util::Singleton >, public IAppender - { - public: - Logger(Severity maxSeverity = none) : m_maxSeverity(maxSeverity) - { - } - - Logger& addAppender(IAppender* appender) - { - assert(appender != this); - m_appenders.push_back(appender); - return *this; - } - - Severity getMaxSeverity() const - { - return m_maxSeverity; - } - - void setMaxSeverity(Severity severity) - { - m_maxSeverity = severity; - } - - bool checkSeverity(Severity severity) const - { - return severity <= m_maxSeverity; - } - - virtual void write(const Record& record) PLOG_OVERRIDE - { - if (checkSeverity(record.getSeverity())) - { - *this += record; - } - } - - void operator+=(const Record& record) - { - for (std::vector::iterator it = m_appenders.begin(); it != m_appenders.end(); ++it) - { - (*it)->write(record); - } - } - - private: - Severity m_maxSeverity; -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class -#endif - std::vector m_appenders; -#ifdef _MSC_VER -# pragma warning(pop) -#endif - }; - - template - inline Logger* get() - { - return Logger::getInstance(); - } - - inline Logger* get() - { - return Logger::getInstance(); - } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Record.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Record.h deleted file mode 100644 index c0c4e872..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Record.h +++ /dev/null @@ -1,435 +0,0 @@ -#pragma once -#include -#include -#include - -#ifdef __cplusplus_cli -#include // For PtrToStringChars -#endif - -namespace plog -{ - namespace detail - { -#if !defined(_MSC_VER) || _MSC_VER > 1400 // MSVC 2005 doesn't understand `enableIf`, so drop all `meta` - namespace meta - { - template - inline T& declval() - { -#ifdef __INTEL_COMPILER -# pragma warning(suppress: 327) // NULL reference is not allowed -#endif - return *reinterpret_cast(0); - } - - template - struct enableIf {}; - - template - struct enableIf { typedef T type; }; - - struct No { char a[1]; }; - struct Yes { char a[2]; }; - - template - struct isConvertible - { - // `+ sizeof(U*)` is required for GCC 4.5-4.7 - template - static typename enableIf(meta::declval())) + sizeof(U*)), Yes>::type test(int); - - template - static No test(...); - - enum { value = sizeof(test(0)) == sizeof(Yes) }; - }; - - template - struct isConvertibleToNString : isConvertible {}; - - template - struct isConvertibleToString : isConvertible {}; - - template - struct isContainer - { - template - static typename meta::enableIf().begin()) + sizeof(meta::declval().end() -#else - typename U::const_iterator -#endif - )), Yes>::type test(int); - - template - static No test(...); - - enum { value = sizeof(test(0)) == sizeof(Yes) }; - }; - - // Detects `std::filesystem::path` and `boost::filesystem::path`. They look like containers - // but we don't want to treat them as containers, so we use this detector to filter them out. - template - struct isFilesystemPath - { - template - static typename meta::enableIf().preferred_separator)), Yes>::type test(int); - - template - static No test(...); - - enum { value = sizeof(test(0)) == sizeof(Yes) }; - }; - } -#endif - - ////////////////////////////////////////////////////////////////////////// - // Stream output operators as free functions - -#if PLOG_ENABLE_WCHAR_INPUT - inline void operator<<(util::nostringstream& stream, const wchar_t* data) - { - data = data ? data : L"(null)"; - -# ifdef _WIN32 -# if PLOG_CHAR_IS_UTF8 - std::operator<<(stream, util::toNarrow(data, codePage::kUTF8)); -# else - std::operator<<(stream, data); -# endif -# else - std::operator<<(stream, util::toNarrow(data)); -# endif - } - - inline void operator<<(util::nostringstream& stream, wchar_t* data) - { - plog::detail::operator<<(stream, const_cast(data)); - } - - inline void operator<<(util::nostringstream& stream, const std::wstring& data) - { - plog::detail::operator<<(stream, data.c_str()); - } -#endif - - inline void operator<<(util::nostringstream& stream, const char* data) - { - data = data ? data : "(null)"; - -#if defined(_WIN32) && defined(__BORLANDC__) -# if PLOG_CHAR_IS_UTF8 - stream << data; -# else - stream << util::toWide(data); -# endif -#elif defined(_WIN32) -# if PLOG_CHAR_IS_UTF8 - std::operator<<(stream, data); -# else - std::operator<<(stream, util::toWide(data)); -# endif -#else - std::operator<<(stream, data); -#endif - } - - inline void operator<<(util::nostringstream& stream, char* data) - { - plog::detail::operator<<(stream, const_cast(data)); - } - - inline void operator<<(util::nostringstream& stream, const std::string& data) - { - plog::detail::operator<<(stream, data.c_str()); - } - -#ifdef __cpp_char8_t - inline void operator<<(util::nostringstream& stream, const char8_t* data) - { -# if PLOG_CHAR_IS_UTF8 - plog::detail::operator<<(stream, reinterpret_cast(data)); -# else - plog::detail::operator<<(stream, util::toWide(reinterpret_cast(data), codePage::kUTF8)); -# endif - } -#endif //__cpp_char8_t - - // Print `std::pair` - template - inline void operator<<(util::nostringstream& stream, const std::pair& data) - { - stream << data.first; - stream << ":"; - stream << data.second; - } - -#if defined(__clang__) || !defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 // skip for GCC < 4.5 due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38600 -#if !defined(_MSC_VER) || _MSC_VER > 1400 // MSVC 2005 doesn't understand `enableIf`, so drop all `meta` - // Print data that can be casted to `std::basic_string`. - template - inline typename meta::enableIf::value, void>::type operator<<(util::nostringstream& stream, const T& data) - { - plog::detail::operator<<(stream, static_cast(data)); - } - - // Print std containers - template - inline typename meta::enableIf::value && - !meta::isConvertibleToNString::value && - !meta::isConvertibleToString::value && - !meta::isFilesystemPath::value, void>::type operator<<(util::nostringstream& stream, const T& data) - { - stream << "["; - - for (typename T::const_iterator it = data.begin(); it != data.end();) - { - stream << *it; - - if (++it == data.end()) - { - break; - } - - stream << ", "; - } - - stream << "]"; - } -#endif -#endif - -#ifdef __cplusplus_cli - inline void operator<<(util::nostringstream& stream, System::String^ data) - { - cli::pin_ptr ptr = PtrToStringChars(data); - plog::detail::operator<<(stream, static_cast(ptr)); - } -#endif - -#if defined(_WIN32) && (!defined(_MSC_VER) || _MSC_VER > 1400) // MSVC 2005 doesn't understand `enableIf`, so drop all `meta` - namespace meta - { - template - struct valueType { enum { value = Value }; }; - - template - inline No operator<<(Stream&, const T&); - - template - struct isStreamable : valueType(), meta::declval())) != sizeof(No)> {}; - - template - struct isStreamable : valueType {}; - - template - struct isStreamable : valueType {}; - - template - struct isStreamable : valueType {}; - - // meta doesn't work well for deleted functions and C++20 has `operator<<(std::ostream&, const wchar_t*) = delete` so exlicitly define it - template<> - struct isStreamable : valueType {}; - -# ifdef __cpp_char8_t - // meta doesn't work well for deleted functions and C++20 has `operator<<(std::ostream&, const char8_t*) = delete` so exlicitly define it - template - struct isStreamable : valueType {}; - - template - struct isStreamable : valueType {}; -# endif //__cpp_char8_t - } - - template - inline typename meta::enableIf::value && !meta::isStreamable::value, void>::type operator<<(std::wostringstream& stream, const T& data) - { - std::ostringstream ss; - ss << data; - stream << ss.str(); - } -#endif - } - - class Record - { - public: - Record(Severity severity, const char* func, size_t line, const char* file, const void* object, int instanceId) - : m_severity(severity), m_tid(util::gettid()), m_object(object), m_line(line), m_func(func), m_file(file), m_instanceId(instanceId) - { - util::ftime(&m_time); - } - - Record& ref() - { - return *this; - } - - ////////////////////////////////////////////////////////////////////////// - // Stream output operators - - Record& operator<<(char data) - { - char str[] = { data, 0 }; - return *this << str; - } - -#if PLOG_ENABLE_WCHAR_INPUT - Record& operator<<(wchar_t data) - { - wchar_t str[] = { data, 0 }; - return *this << str; - } -#endif - - Record& operator<<(util::nostream& (PLOG_CDECL *data)(util::nostream&)) - { - m_message << data; - return *this; - } - -#ifdef QT_VERSION - Record& operator<<(const QString& data) - { -# if PLOG_CHAR_IS_UTF8 - return *this << data.toStdString(); -# else - return *this << data.toStdWString(); -# endif - } - -# if QT_VERSION < 0x060000 - Record& operator<<(const QStringRef& data) - { - return *this << data.toString(); - } -# endif - -# ifdef QSTRINGVIEW_H - Record& operator<<(QStringView data) - { - return *this << data.toString(); - } -# endif -#endif - - template - Record& operator<<(const T& data) - { - using namespace plog::detail; - - m_message << data; - return *this; - } - -#ifndef __cplusplus_cli - Record& printf(const char* format, ...) - { - using namespace util; - - char* str = NULL; - va_list ap; - - va_start(ap, format); - int len = vasprintf(&str, format, ap); - static_cast(len); - va_end(ap); - - *this << str; - free(str); - - return *this; - } - -#ifdef _WIN32 - Record& printf(const wchar_t* format, ...) - { - using namespace util; - - wchar_t* str = NULL; - va_list ap; - - va_start(ap, format); - int len = vaswprintf(&str, format, ap); - static_cast(len); - va_end(ap); - - *this << str; - free(str); - - return *this; - } -#endif -#endif //__cplusplus_cli - - ////////////////////////////////////////////////////////////////////////// - // Getters - - virtual const util::Time& getTime() const - { - return m_time; - } - - virtual Severity getSeverity() const - { - return m_severity; - } - - virtual unsigned int getTid() const - { - return m_tid; - } - - virtual const void* getObject() const - { - return m_object; - } - - virtual size_t getLine() const - { - return m_line; - } - - virtual const util::nchar* getMessage() const - { - m_messageStr = m_message.str(); - return m_messageStr.c_str(); - } - - virtual const char* getFunc() const - { - m_funcStr = util::processFuncName(m_func); - return m_funcStr.c_str(); - } - - virtual const char* getFile() const - { - return m_file; - } - - virtual ~Record() // virtual destructor to satisfy -Wnon-virtual-dtor warning - { - } - - virtual int getInstanceId() const - { - return m_instanceId; - } - - private: - util::Time m_time; - const Severity m_severity; - const unsigned int m_tid; - const void* const m_object; - const size_t m_line; - util::nostringstream m_message; - const char* const m_func; - const char* const m_file; - const int m_instanceId; - mutable std::string m_funcStr; - mutable util::nstring m_messageStr; - }; -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Severity.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Severity.h deleted file mode 100644 index 446768e8..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Severity.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include - -namespace plog -{ - enum Severity - { - none = 0, - fatal = 1, - error = 2, - warning = 3, - info = 4, - debug = 5, - verbose = 6 - }; - -#ifdef _MSC_VER -# pragma warning(suppress: 26812) // Prefer 'enum class' over 'enum' -#endif - inline const char* severityToString(Severity severity) - { - switch (severity) - { - case fatal: - return "FATAL"; - case error: - return "ERROR"; - case warning: - return "WARN"; - case info: - return "INFO"; - case debug: - return "DEBUG"; - case verbose: - return "VERB"; - default: - return "NONE"; - } - } - - inline Severity severityFromString(const char* str) - { - switch (std::toupper(str[0])) - { - case 'F': - return fatal; - case 'E': - return error; - case 'W': - return warning; - case 'I': - return info; - case 'D': - return debug; - case 'V': - return verbose; - default: - return none; - } - } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Util.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/Util.h deleted file mode 100644 index ac01a526..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/Util.h +++ /dev/null @@ -1,616 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -#ifndef PLOG_ENABLE_WCHAR_INPUT -# ifdef _WIN32 -# define PLOG_ENABLE_WCHAR_INPUT 1 -# else -# define PLOG_ENABLE_WCHAR_INPUT 0 -# endif -#endif - -////////////////////////////////////////////////////////////////////////// -// PLOG_CHAR_IS_UTF8 specifies character encoding of `char` type. On *nix -// systems it's set to UTF-8 while on Windows in can be ANSI or UTF-8. It -// automatically detects `/utf-8` command line option in MSVC. Also it can -// be set manually if required. -// This option allows to support http://utf8everywhere.org approach. - -#ifndef PLOG_CHAR_IS_UTF8 -# if defined(_WIN32) && !defined(_UTF8) -# define PLOG_CHAR_IS_UTF8 0 -# else -# define PLOG_CHAR_IS_UTF8 1 -# endif -#endif - -#ifdef _WIN32 -# if defined(PLOG_EXPORT) -# define PLOG_LINKAGE __declspec(dllexport) -# elif defined(PLOG_IMPORT) -# define PLOG_LINKAGE __declspec(dllimport) -# endif -# if defined(PLOG_GLOBAL) -# error "PLOG_GLOBAL isn't supported on Windows" -# endif -#else -# if defined(PLOG_GLOBAL) -# define PLOG_LINKAGE __attribute__ ((visibility ("default"))) -# elif defined(PLOG_LOCAL) -# define PLOG_LINKAGE __attribute__ ((visibility ("hidden"))) -# define PLOG_LINKAGE_HIDDEN PLOG_LINKAGE -# endif -# if defined(PLOG_EXPORT) || defined(PLOG_IMPORT) -# error "PLOG_EXPORT/PLOG_IMPORT is supported only on Windows" -# endif -#endif - -#ifndef PLOG_LINKAGE -# define PLOG_LINKAGE -#endif - -#ifndef PLOG_LINKAGE_HIDDEN -# define PLOG_LINKAGE_HIDDEN -#endif - -#ifdef _WIN32 -# include -# include -# include -# include -# include -#else -# include -# include -# if defined(__linux__) || defined(__FreeBSD__) -# include -# elif defined(__rtems__) -# include -# endif -# if defined(_POSIX_THREADS) -# include -# endif -# if PLOG_ENABLE_WCHAR_INPUT -# include -# endif -#endif - -#if PLOG_CHAR_IS_UTF8 -# define PLOG_NSTR(x) x -#else -# define _PLOG_NSTR(x) L##x -# define PLOG_NSTR(x) _PLOG_NSTR(x) -#endif - -#ifdef _WIN32 -# define PLOG_CDECL __cdecl -#else -# define PLOG_CDECL -#endif - -#if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER >= 1700 -# define PLOG_OVERRIDE override -#else -# define PLOG_OVERRIDE -#endif - -namespace plog -{ - namespace util - { -#if PLOG_CHAR_IS_UTF8 - typedef std::string nstring; - typedef std::ostringstream nostringstream; - typedef std::istringstream nistringstream; - typedef std::ostream nostream; - typedef char nchar; -#else - typedef std::wstring nstring; - typedef std::wostringstream nostringstream; - typedef std::wistringstream nistringstream; - typedef std::wostream nostream; - typedef wchar_t nchar; -#endif - - inline void localtime_s(struct tm* t, const time_t* time) - { -#if defined(_WIN32) && defined(__BORLANDC__) - ::localtime_s(time, t); -#elif defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) - *t = *::localtime(time); -#elif defined(_WIN32) - ::localtime_s(t, time); -#else - ::localtime_r(time, t); -#endif - } - - inline void gmtime_s(struct tm* t, const time_t* time) - { -#if defined(_WIN32) && defined(__BORLANDC__) - ::gmtime_s(time, t); -#elif defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) - *t = *::gmtime(time); -#elif defined(_WIN32) - ::gmtime_s(t, time); -#else - ::gmtime_r(time, t); -#endif - } - -#ifdef _WIN32 - typedef timeb Time; - - inline void ftime(Time* t) - { - ::ftime(t); - } -#else - struct Time - { - time_t time; - unsigned short millitm; - }; - - inline void ftime(Time* t) - { - timeval tv; - ::gettimeofday(&tv, NULL); - - t->time = tv.tv_sec; - t->millitm = static_cast(tv.tv_usec / 1000); - } -#endif - - inline unsigned int gettid() - { -#ifdef _WIN32 - return GetCurrentThreadId(); -#elif defined(__linux__) - return static_cast(::syscall(__NR_gettid)); -#elif defined(__FreeBSD__) - long tid; - syscall(SYS_thr_self, &tid); - return static_cast(tid); -#elif defined(__rtems__) - return rtems_task_self(); -#elif defined(__APPLE__) - uint64_t tid64; - pthread_threadid_np(NULL, &tid64); - return static_cast(tid64); -#else - return 0; -#endif - } - -#ifndef _GNU_SOURCE - inline int vasprintf(char** strp, const char* format, va_list ap) - { - va_list ap_copy; -#if defined(_MSC_VER) && _MSC_VER <= 1600 - ap_copy = ap; // there is no va_copy on Visual Studio 2010 -#else - va_copy(ap_copy, ap); -#endif -#ifndef __STDC_SECURE_LIB__ - int charCount = vsnprintf(NULL, 0, format, ap_copy); -#else - int charCount = _vscprintf(format, ap_copy); -#endif - va_end(ap_copy); - if (charCount < 0) - { - return -1; - } - - size_t bufferCharCount = static_cast(charCount) + 1; - - char* str = static_cast(malloc(bufferCharCount)); - if (!str) - { - return -1; - } - -#ifndef __STDC_SECURE_LIB__ - int retval = vsnprintf(str, bufferCharCount, format, ap); -#else - int retval = vsnprintf_s(str, bufferCharCount, static_cast(-1), format, ap); -#endif - if (retval < 0) - { - free(str); - return -1; - } - - *strp = str; - return retval; - } -#endif - -#ifdef _WIN32 - inline int vaswprintf(wchar_t** strp, const wchar_t* format, va_list ap) - { -#if defined(__BORLANDC__) - int charCount = 0x1000; // there is no _vscwprintf on Borland/Embarcadero -#else - int charCount = _vscwprintf(format, ap); - if (charCount < 0) - { - return -1; - } -#endif - - size_t bufferCharCount = static_cast(charCount) + 1; - - wchar_t* str = static_cast(malloc(bufferCharCount * sizeof(wchar_t))); - if (!str) - { - return -1; - } - -#if defined(__BORLANDC__) - int retval = vsnwprintf_s(str, bufferCharCount, format, ap); -#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) - int retval = _vsnwprintf(str, bufferCharCount, format, ap); -#else - int retval = _vsnwprintf_s(str, bufferCharCount, charCount, format, ap); -#endif - if (retval < 0) - { - free(str); - return -1; - } - - *strp = str; - return retval; - } -#endif - -#ifdef _WIN32 - inline std::wstring toWide(const char* str, UINT cp = codePage::kChar) - { - size_t len = ::strlen(str); - std::wstring wstr(len, 0); - - if (!wstr.empty()) - { - int wlen = MultiByteToWideChar(cp, 0, str, static_cast(len), &wstr[0], static_cast(wstr.size())); - wstr.resize(wlen); - } - - return wstr; - } - - inline std::wstring toWide(const std::string& str, UINT cp = codePage::kChar) - { - return toWide(str.c_str(), cp); - } - - inline const std::wstring& toWide(const std::wstring& str) // do nothing for already wide string - { - return str; - } - - inline std::string toNarrow(const std::wstring& wstr, long page) - { - int len = WideCharToMultiByte(page, 0, wstr.c_str(), static_cast(wstr.size()), 0, 0, 0, 0); - std::string str(len, 0); - - if (!str.empty()) - { - WideCharToMultiByte(page, 0, wstr.c_str(), static_cast(wstr.size()), &str[0], len, 0, 0); - } - - return str; - } -#elif PLOG_ENABLE_WCHAR_INPUT - inline std::string toNarrow(const wchar_t* wstr) - { - size_t wlen = ::wcslen(wstr); - std::string str(wlen * sizeof(wchar_t), 0); - - if (!str.empty()) - { - const char* in = reinterpret_cast(&wstr[0]); - char* out = &str[0]; - size_t inBytes = wlen * sizeof(wchar_t); - size_t outBytes = str.size(); - - iconv_t cd = ::iconv_open("UTF-8", "WCHAR_T"); - ::iconv(cd, const_cast(&in), &inBytes, &out, &outBytes); - ::iconv_close(cd); - - str.resize(str.size() - outBytes); - } - - return str; - } -#endif - - inline std::string processFuncName(const char* func) - { -#if (defined(_WIN32) && !defined(__MINGW32__)) || defined(__OBJC__) - return std::string(func); -#else - const char* funcBegin = func; - const char* funcEnd = ::strchr(funcBegin, '('); - int foundTemplate = 0; - - if (!funcEnd) - { - return std::string(func); - } - - for (const char* i = funcEnd - 1; i >= funcBegin; --i) // search backwards for the first space char - { - if (*i == '>') - { - foundTemplate++; - } - else if (*i == '<') - { - foundTemplate--; - } - else if (*i == ' ' && foundTemplate == 0) - { - funcBegin = i + 1; - break; - } - } - - return std::string(funcBegin, funcEnd); -#endif - } - - inline const nchar* findExtensionDot(const nchar* fileName) - { -#if PLOG_CHAR_IS_UTF8 - return std::strrchr(fileName, '.'); -#else - return std::wcsrchr(fileName, L'.'); -#endif - } - - inline void splitFileName(const nchar* fileName, nstring& fileNameNoExt, nstring& fileExt) - { - const nchar* dot = findExtensionDot(fileName); - - if (dot) - { - fileNameNoExt.assign(fileName, dot); - fileExt.assign(dot + 1); - } - else - { - fileNameNoExt.assign(fileName); - fileExt.clear(); - } - } - - class PLOG_LINKAGE NonCopyable - { - protected: - NonCopyable() - { - } - - private: - NonCopyable(const NonCopyable&); - NonCopyable& operator=(const NonCopyable&); - }; - - class PLOG_LINKAGE_HIDDEN File : NonCopyable - { - public: - File() : m_file(-1) - { - } - - ~File() - { - close(); - } - - size_t open(const nstring& fileName) - { -#if defined(_WIN32) && (defined(__BORLANDC__) || defined(__MINGW32__)) - m_file = ::_wsopen(toWide(fileName).c_str(), _O_CREAT | _O_WRONLY | _O_BINARY | _O_NOINHERIT, SH_DENYWR, _S_IREAD | _S_IWRITE); -#elif defined(_WIN32) - ::_wsopen_s(&m_file, toWide(fileName).c_str(), _O_CREAT | _O_WRONLY | _O_BINARY | _O_NOINHERIT, _SH_DENYWR, _S_IREAD | _S_IWRITE); -#elif defined(O_CLOEXEC) - m_file = ::open(fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -#else - m_file = ::open(fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -#endif - return seek(0, SEEK_END); - } - - size_t write(const void* buf, size_t count) - { - return m_file != -1 ? static_cast( -#ifdef _WIN32 - ::_write(m_file, buf, static_cast(count)) -#else - ::write(m_file, buf, count) -#endif - ) : static_cast(-1); - } - - template - size_t write(const std::basic_string& str) - { - return write(str.data(), str.size() * sizeof(CharType)); - } - - size_t seek(size_t offset, int whence) - { - return m_file != -1 ? static_cast( -#if defined(_WIN32) && (defined(__BORLANDC__) || defined(__MINGW32__)) - ::_lseek(m_file, static_cast(offset), whence) -#elif defined(_WIN32) - ::_lseeki64(m_file, static_cast(offset), whence) -#else - ::lseek(m_file, static_cast(offset), whence) -#endif - ) : static_cast(-1); - } - - void close() - { - if (m_file != -1) - { -#ifdef _WIN32 - ::_close(m_file); -#else - ::close(m_file); -#endif - m_file = -1; - } - } - - static int unlink(const nstring& fileName) - { -#ifdef _WIN32 - return ::_wunlink(toWide(fileName).c_str()); -#else - return ::unlink(fileName.c_str()); -#endif - } - - static int rename(const nstring& oldFilename, const nstring& newFilename) - { -#ifdef _WIN32 - return MoveFileW(toWide(oldFilename).c_str(), toWide(newFilename).c_str()); -#else - return ::rename(oldFilename.c_str(), newFilename.c_str()); -#endif - } - - private: - int m_file; - }; - - class PLOG_LINKAGE_HIDDEN Mutex : NonCopyable - { - public: - Mutex() - { -#ifdef _WIN32 - InitializeCriticalSection(&m_sync); -#elif defined(__rtems__) - rtems_semaphore_create(0, 1, - RTEMS_PRIORITY | - RTEMS_BINARY_SEMAPHORE | - RTEMS_INHERIT_PRIORITY, 1, &m_sync); -#elif defined(_POSIX_THREADS) - ::pthread_mutex_init(&m_sync, 0); -#endif - } - - ~Mutex() - { -#ifdef _WIN32 - DeleteCriticalSection(&m_sync); -#elif defined(__rtems__) - rtems_semaphore_delete(m_sync); -#elif defined(_POSIX_THREADS) - ::pthread_mutex_destroy(&m_sync); -#endif - } - - friend class MutexLock; - - private: - void lock() - { -#ifdef _WIN32 - EnterCriticalSection(&m_sync); -#elif defined(__rtems__) - rtems_semaphore_obtain(m_sync, RTEMS_WAIT, RTEMS_NO_TIMEOUT); -#elif defined(_POSIX_THREADS) - ::pthread_mutex_lock(&m_sync); -#endif - } - - void unlock() - { -#ifdef _WIN32 - LeaveCriticalSection(&m_sync); -#elif defined(__rtems__) - rtems_semaphore_release(m_sync); -#elif defined(_POSIX_THREADS) - ::pthread_mutex_unlock(&m_sync); -#endif - } - - private: -#ifdef _WIN32 - CRITICAL_SECTION m_sync; -#elif defined(__rtems__) - rtems_id m_sync; -#elif defined(_POSIX_THREADS) - pthread_mutex_t m_sync; -#endif - }; - - class PLOG_LINKAGE_HIDDEN MutexLock : NonCopyable - { - public: - MutexLock(Mutex& mutex) : m_mutex(mutex) - { - m_mutex.lock(); - } - - ~MutexLock() - { - m_mutex.unlock(); - } - - private: - Mutex& m_mutex; - }; - - template -#ifdef _WIN32 - class Singleton : NonCopyable -#else - class PLOG_LINKAGE Singleton : NonCopyable -#endif - { - public: -#if (defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 8) && !defined(__BORLANDC__) - // This constructor is called before the `T` object is fully constructed, and - // pointers are not dereferenced anyway, so UBSan shouldn't check vptrs. - __attribute__((no_sanitize("vptr"))) -#endif - Singleton() - { - assert(!m_instance); - m_instance = static_cast(this); - } - - ~Singleton() - { - assert(m_instance); - m_instance = 0; - } - - static T* getInstance() - { - return m_instance; - } - - private: - static T* m_instance; - }; - - template - T* Singleton::m_instance = NULL; - } -} diff --git a/godot/thirdparty/libdatachannel/deps/plog/include/plog/WinApi.h b/godot/thirdparty/libdatachannel/deps/plog/include/plog/WinApi.h deleted file mode 100644 index ccf44af0..00000000 --- a/godot/thirdparty/libdatachannel/deps/plog/include/plog/WinApi.h +++ /dev/null @@ -1,175 +0,0 @@ -#pragma once - -#ifdef _WIN32 - -// These windows structs must be in a global namespace -struct HKEY__; -struct _SECURITY_ATTRIBUTES; -struct _CONSOLE_SCREEN_BUFFER_INFO; -struct _RTL_CRITICAL_SECTION; - -namespace plog -{ - typedef unsigned long DWORD; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned int UINT; - typedef int BOOL; - typedef long LSTATUS; - typedef char* LPSTR; - typedef wchar_t* LPWSTR; - typedef const char* LPCSTR; - typedef const wchar_t* LPCWSTR; - typedef void* HANDLE; - typedef HKEY__* HKEY; - typedef size_t ULONG_PTR; - - struct CRITICAL_SECTION - { - void* DebugInfo; - long LockCount; - long RecursionCount; - HANDLE OwningThread; - HANDLE LockSemaphore; - ULONG_PTR SpinCount; - }; - - struct COORD - { - short X; - short Y; - }; - - struct SMALL_RECT - { - short Left; - short Top; - short Right; - short Bottom; - }; - - struct CONSOLE_SCREEN_BUFFER_INFO - { - COORD dwSize; - COORD dwCursorPosition; - WORD wAttributes; - SMALL_RECT srWindow; - COORD dwMaximumWindowSize; - }; - - namespace codePage - { - const UINT kActive = 0; - const UINT kUTF8 = 65001; -#if PLOG_CHAR_IS_UTF8 - const UINT kChar = kUTF8; -#else - const UINT kChar = kActive; -#endif - } - - namespace eventLog - { - const WORD kErrorType = 0x0001; - const WORD kWarningType = 0x0002; - const WORD kInformationType = 0x0004; - } - - namespace hkey - { - const HKEY kLocalMachine = reinterpret_cast(static_cast(0x80000002)); - } - - namespace regSam - { - const DWORD kQueryValue = 0x0001; - const DWORD kSetValue = 0x0002; - } - - namespace regType - { - const DWORD kExpandSz = 2; - const DWORD kDword = 4; - } - - namespace stdHandle - { - const DWORD kOutput = static_cast(-11); - const DWORD kErrorOutput = static_cast(-12); - } - - namespace foreground - { - const WORD kBlue = 0x0001; - const WORD kGreen = 0x0002; - const WORD kRed = 0x0004; - const WORD kIntensity = 0x0008; - } - - namespace background - { - const WORD kBlue = 0x0010; - const WORD kGreen = 0x0020; - const WORD kRed = 0x0040; - const WORD kIntensity = 0x0080; - } - - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, BOOL* lpUsedDefaultChar); - - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(); - - __declspec(dllimport) BOOL __stdcall MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName); - - __declspec(dllimport) void __stdcall InitializeCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection); - __declspec(dllimport) void __stdcall EnterCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection); - __declspec(dllimport) void __stdcall LeaveCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection); - __declspec(dllimport) void __stdcall DeleteCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection); - - __declspec(dllimport) HANDLE __stdcall RegisterEventSourceW(LPCWSTR lpUNCServerName, LPCWSTR lpSourceName); - __declspec(dllimport) BOOL __stdcall DeregisterEventSource(HANDLE hEventLog); - __declspec(dllimport) BOOL __stdcall ReportEventW(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, void* lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR* lpStrings, void* lpRawData); - - __declspec(dllimport) LSTATUS __stdcall RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, DWORD samDesired, _SECURITY_ATTRIBUTES* lpSecurityAttributes, HKEY* phkResult, DWORD* lpdwDisposition); - __declspec(dllimport) LSTATUS __stdcall RegSetValueExW(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData); - __declspec(dllimport) LSTATUS __stdcall RegCloseKey(HKEY hKey); - __declspec(dllimport) LSTATUS __stdcall RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, DWORD samDesired, HKEY* phkResult); - __declspec(dllimport) LSTATUS __stdcall RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey); - - __declspec(dllimport) HANDLE __stdcall GetStdHandle(DWORD nStdHandle); - - __declspec(dllimport) BOOL __stdcall WriteConsoleW(HANDLE hConsoleOutput, const void* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD* lpNumberOfCharsWritten, void* lpReserved); - __declspec(dllimport) BOOL __stdcall GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, _CONSOLE_SCREEN_BUFFER_INFO* lpConsoleScreenBufferInfo); - __declspec(dllimport) BOOL __stdcall SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes); - - __declspec(dllimport) void __stdcall OutputDebugStringW(LPCWSTR lpOutputString); - } - - inline void InitializeCriticalSection(CRITICAL_SECTION* criticalSection) - { - plog::InitializeCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection)); - } - - inline void EnterCriticalSection(CRITICAL_SECTION* criticalSection) - { - plog::EnterCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection)); - } - - inline void LeaveCriticalSection(CRITICAL_SECTION* criticalSection) - { - plog::LeaveCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection)); - } - - inline void DeleteCriticalSection(CRITICAL_SECTION* criticalSection) - { - plog::DeleteCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection)); - } - - inline BOOL GetConsoleScreenBufferInfo(HANDLE consoleOutput, CONSOLE_SCREEN_BUFFER_INFO* consoleScreenBufferInfo) - { - return plog::GetConsoleScreenBufferInfo(consoleOutput, reinterpret_cast<_CONSOLE_SCREEN_BUFFER_INFO*>(consoleScreenBufferInfo)); - } -} -#endif // _WIN32 diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/LICENSE.md b/godot/thirdparty/libdatachannel/deps/usrsctp/LICENSE.md deleted file mode 100644 index a2d1f989..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/LICENSE.md +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015, Randall Stewart and Michael Tuexen -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of usrsctp nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp.h deleted file mode 100644 index 6a800ea2..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp.h +++ /dev/null @@ -1,676 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_H_ -#define _NETINET_SCTP_H_ - -#if defined(__APPLE__) || defined(__linux__) -#include -#endif -#include - -#if !defined(_WIN32) -#define SCTP_PACKED __attribute__((packed)) -#else -#pragma pack (push, 1) -#define SCTP_PACKED -#endif - -/* - * SCTP protocol - RFC4960. - */ -struct sctphdr { - uint16_t src_port; /* source port */ - uint16_t dest_port; /* destination port */ - uint32_t v_tag; /* verification tag of packet */ - uint32_t checksum; /* CRC32C checksum */ - /* chunks follow... */ -} SCTP_PACKED; - -/* - * SCTP Chunks - */ -struct sctp_chunkhdr { - uint8_t chunk_type; /* chunk type */ - uint8_t chunk_flags; /* chunk flags */ - uint16_t chunk_length; /* chunk length */ - /* optional params follow */ -} SCTP_PACKED; - -/* - * SCTP chunk parameters - */ -struct sctp_paramhdr { - uint16_t param_type; /* parameter type */ - uint16_t param_length; /* parameter length */ -} SCTP_PACKED; - -/* - * user socket options: socket API defined - */ -/* - * read-write options - */ -#define SCTP_RTOINFO 0x00000001 -#define SCTP_ASSOCINFO 0x00000002 -#define SCTP_INITMSG 0x00000003 -#define SCTP_NODELAY 0x00000004 -#define SCTP_AUTOCLOSE 0x00000005 -#define SCTP_SET_PEER_PRIMARY_ADDR 0x00000006 -#define SCTP_PRIMARY_ADDR 0x00000007 -#define SCTP_ADAPTATION_LAYER 0x00000008 -/* same as above */ -#define SCTP_ADAPTION_LAYER 0x00000008 -#define SCTP_DISABLE_FRAGMENTS 0x00000009 -#define SCTP_PEER_ADDR_PARAMS 0x0000000a -#define SCTP_DEFAULT_SEND_PARAM 0x0000000b -/* ancillary data/notification interest options */ -#define SCTP_EVENTS 0x0000000c /* deprecated */ -/* Without this applied we will give V4 and V6 addresses on a V6 socket */ -#define SCTP_I_WANT_MAPPED_V4_ADDR 0x0000000d -#define SCTP_MAXSEG 0x0000000e -#define SCTP_DELAYED_SACK 0x0000000f -#define SCTP_FRAGMENT_INTERLEAVE 0x00000010 -#define SCTP_PARTIAL_DELIVERY_POINT 0x00000011 -/* authentication support */ -#define SCTP_AUTH_CHUNK 0x00000012 -#define SCTP_AUTH_KEY 0x00000013 -#define SCTP_HMAC_IDENT 0x00000014 -#define SCTP_AUTH_ACTIVE_KEY 0x00000015 -#define SCTP_AUTH_DELETE_KEY 0x00000016 -#define SCTP_USE_EXT_RCVINFO 0x00000017 -#define SCTP_AUTO_ASCONF 0x00000018 /* rw */ -#define SCTP_MAXBURST 0x00000019 /* rw */ -#define SCTP_MAX_BURST 0x00000019 /* rw */ -/* assoc level context */ -#define SCTP_CONTEXT 0x0000001a /* rw */ -/* explicit EOR signalling */ -#define SCTP_EXPLICIT_EOR 0x0000001b -#define SCTP_REUSE_PORT 0x0000001c /* rw */ -#define SCTP_AUTH_DEACTIVATE_KEY 0x0000001d -#define SCTP_EVENT 0x0000001e -#define SCTP_RECVRCVINFO 0x0000001f -#define SCTP_RECVNXTINFO 0x00000020 -#define SCTP_DEFAULT_SNDINFO 0x00000021 -#define SCTP_DEFAULT_PRINFO 0x00000022 -#define SCTP_PEER_ADDR_THLDS 0x00000023 -#define SCTP_REMOTE_UDP_ENCAPS_PORT 0x00000024 -#define SCTP_ECN_SUPPORTED 0x00000025 -#define SCTP_PR_SUPPORTED 0x00000026 -#define SCTP_AUTH_SUPPORTED 0x00000027 -#define SCTP_ASCONF_SUPPORTED 0x00000028 -#define SCTP_RECONFIG_SUPPORTED 0x00000029 -#define SCTP_NRSACK_SUPPORTED 0x00000030 -#define SCTP_PKTDROP_SUPPORTED 0x00000031 -#define SCTP_MAX_CWND 0x00000032 -#define SCTP_ACCEPT_ZERO_CHECKSUM 0x00000033 - -/* - * read-only options - */ -#define SCTP_STATUS 0x00000100 -#define SCTP_GET_PEER_ADDR_INFO 0x00000101 -/* authentication support */ -#define SCTP_PEER_AUTH_CHUNKS 0x00000102 -#define SCTP_LOCAL_AUTH_CHUNKS 0x00000103 -#define SCTP_GET_ASSOC_NUMBER 0x00000104 /* ro */ -#define SCTP_GET_ASSOC_ID_LIST 0x00000105 /* ro */ -#define SCTP_TIMEOUTS 0x00000106 -#define SCTP_PR_STREAM_STATUS 0x00000107 -#define SCTP_PR_ASSOC_STATUS 0x00000108 - -/* - * user socket options: BSD implementation specific - */ -/* - * Blocking I/O is enabled on any TCP type socket by default. For the UDP - * model if this is turned on then the socket buffer is shared for send - * resources amongst all associations. The default for the UDP model is that - * is SS_NBIO is set. Which means all associations have a separate send - * limit BUT they will NOT ever BLOCK instead you will get an error back - * EAGAIN if you try to send too much. If you want the blocking semantics you - * set this option at the cost of sharing one socket send buffer size amongst - * all associations. Peeled off sockets turn this option off and block. But - * since both TCP and peeled off sockets have only one assoc per socket this - * is fine. It probably does NOT make sense to set this on SS_NBIO on a TCP - * model OR peeled off UDP model, but we do allow you to do so. You just use - * the normal syscall to toggle SS_NBIO the way you want. - * - * Blocking I/O is controlled by the SS_NBIO flag on the socket state so_state - * field. - */ - -#define SCTP_ENABLE_STREAM_RESET 0x00000900 /* struct sctp_assoc_value */ -#define SCTP_RESET_STREAMS 0x00000901 /* struct sctp_reset_streams */ -#define SCTP_RESET_ASSOC 0x00000902 /* sctp_assoc_t */ -#define SCTP_ADD_STREAMS 0x00000903 /* struct sctp_add_streams */ - -/* For enable stream reset */ -#define SCTP_ENABLE_RESET_STREAM_REQ 0x00000001 -#define SCTP_ENABLE_RESET_ASSOC_REQ 0x00000002 -#define SCTP_ENABLE_CHANGE_ASSOC_REQ 0x00000004 -#define SCTP_ENABLE_VALUE_MASK 0x00000007 -/* For reset streams */ -#define SCTP_STREAM_RESET_INCOMING 0x00000001 -#define SCTP_STREAM_RESET_OUTGOING 0x00000002 - -/* here on down are more implementation specific */ -#define SCTP_SET_DEBUG_LEVEL 0x00001005 -#define SCTP_CLR_STAT_LOG 0x00001007 -/* CMT ON/OFF socket option */ -#define SCTP_CMT_ON_OFF 0x00001200 -#define SCTP_CMT_USE_DAC 0x00001201 -/* JRS - Pluggable Congestion Control Socket option */ -#define SCTP_PLUGGABLE_CC 0x00001202 -/* RS - Pluggable Stream Scheduling Socket option */ -#define SCTP_STREAM_SCHEDULER 0x00001203 -#define SCTP_STREAM_SCHEDULER_VALUE 0x00001204 -/* The next two are for backwards compatibility. */ -#define SCTP_PLUGGABLE_SS SCTP_STREAM_SCHEDULER -#define SCTP_SS_VALUE SCTP_STREAM_SCHEDULER_VALUE -#define SCTP_CC_OPTION 0x00001205 /* Options for CC modules */ -/* For I-DATA */ -#define SCTP_INTERLEAVING_SUPPORTED 0x00001206 - -/* read only */ -#define SCTP_GET_SNDBUF_USE 0x00001101 -#define SCTP_GET_STAT_LOG 0x00001103 -#define SCTP_PCB_STATUS 0x00001104 -#define SCTP_GET_NONCE_VALUES 0x00001105 - -/* Special hook for dynamically setting primary for all assoc's, - * this is a write only option that requires root privilege. - */ -#define SCTP_SET_DYNAMIC_PRIMARY 0x00002001 - -/* VRF (virtual router feature) and multi-VRF support - * options. VRF's provide splits within a router - * that give the views of multiple routers. A - * standard host, without VRF support, is just - * a single VRF. If VRF's are supported then - * the transport must be VRF aware. This means - * that every socket call coming in must be directed - * within the endpoint to one of the VRF's it belongs - * to. The endpoint, before binding, may select - * the "default" VRF it is in by using a set socket - * option with SCTP_VRF_ID. This will also - * get propagated to the default VRF. Once the - * endpoint binds an address then it CANNOT add - * additional VRF's to become a Multi-VRF endpoint. - * - * Before BINDING additional VRF's can be added with - * the SCTP_ADD_VRF_ID call or deleted with - * SCTP_DEL_VRF_ID. - * - * Associations are ALWAYS contained inside a single - * VRF. They cannot reside in two (or more) VRF's. Incoming - * packets, assuming the router is VRF aware, can always - * tell us what VRF they arrived on. A host not supporting - * any VRF's will find that the packets always arrived on the - * single VRF that the host has. - * - */ - -#define SCTP_VRF_ID 0x00003001 -#define SCTP_ADD_VRF_ID 0x00003002 -#define SCTP_GET_VRF_IDS 0x00003003 -#define SCTP_GET_ASOC_VRF 0x00003004 -#define SCTP_DEL_VRF_ID 0x00003005 - -/* - * If you enable packet logging you can get - * a poor mans ethereal output in binary - * form. Note this is a compile option to - * the kernel, SCTP_PACKET_LOGGING, and - * without it in your kernel you - * will get a EOPNOTSUPP - */ -#define SCTP_GET_PACKET_LOG 0x00004001 - -/* - * hidden implementation specific options these are NOT user visible (should - * move out of sctp.h) - */ -/* sctp_bindx() flags as hidden socket options */ -#define SCTP_BINDX_ADD_ADDR 0x00008001 -#define SCTP_BINDX_REM_ADDR 0x00008002 -/* Hidden socket option that gets the addresses */ -#define SCTP_GET_PEER_ADDRESSES 0x00008003 -#define SCTP_GET_LOCAL_ADDRESSES 0x00008004 -/* return the total count in bytes needed to hold all local addresses bound */ -#define SCTP_GET_LOCAL_ADDR_SIZE 0x00008005 -/* Return the total count in bytes needed to hold the remote address */ -#define SCTP_GET_REMOTE_ADDR_SIZE 0x00008006 -/* hidden option for connectx */ -#define SCTP_CONNECT_X 0x00008007 -/* hidden option for connectx_delayed, part of sendx */ -#define SCTP_CONNECT_X_DELAYED 0x00008008 -#define SCTP_CONNECT_X_COMPLETE 0x00008009 -/* hidden socket option based sctp_peeloff */ -#define SCTP_PEELOFF 0x0000800a -/* the real worker for sctp_getaddrlen() */ -#define SCTP_GET_ADDR_LEN 0x0000800b -#if defined(__APPLE__) && !defined(__Userspace__) -/* temporary workaround for Apple listen() issue, no args used */ -#define SCTP_LISTEN_FIX 0x0000800c -#endif -#if defined(_WIN32) && !defined(__Userspace__) -/* workaround for Cygwin on Windows: returns the SOCKET handle */ -#define SCTP_GET_HANDLE 0x0000800d -#endif -/* Debug things that need to be purged */ -#define SCTP_SET_INITIAL_DBG_SEQ 0x00009f00 - -/* JRS - Supported congestion control modules for pluggable - * congestion control - */ -/* Standard TCP Congestion Control */ -#define SCTP_CC_RFC2581 0x00000000 -/* High Speed TCP Congestion Control (Floyd) */ -#define SCTP_CC_HSTCP 0x00000001 -/* HTCP Congestion Control */ -#define SCTP_CC_HTCP 0x00000002 -/* RTCC Congestion Control - RFC2581 plus */ -#define SCTP_CC_RTCC 0x00000003 - -#define SCTP_CC_OPT_RTCC_SETMODE 0x00002000 -#define SCTP_CC_OPT_USE_DCCC_ECN 0x00002001 -#define SCTP_CC_OPT_STEADY_STEP 0x00002002 - -#define SCTP_CMT_OFF 0 -#define SCTP_CMT_BASE 1 -#define SCTP_CMT_RPV1 2 -#define SCTP_CMT_RPV2 3 -#define SCTP_CMT_MPTCP 4 -#define SCTP_CMT_MAX SCTP_CMT_MPTCP - -/* RS - Supported stream scheduling modules for pluggable - * stream scheduling - */ -/* Default simple round-robin */ -#define SCTP_SS_DEFAULT 0x00000000 -/* Real round-robin */ -#define SCTP_SS_RR 0x00000001 -/* Real round-robin per packet */ -#define SCTP_SS_RR_PKT 0x00000002 -/* Priority */ -#define SCTP_SS_PRIO 0x00000003 -/* Fair Bandwidth */ -#define SCTP_SS_FB 0x00000004 -/* First-come, first-serve */ -#define SCTP_SS_FCFS 0x00000005 -/* The next five are for backwards compatibility. */ -#define SCTP_SS_ROUND_ROBIN SCTP_SS_RR -#define SCTP_SS_ROUND_ROBIN_PACKET SCTP_SS_RR_PKT -#define SCTP_SS_PRIORITY SCTP_SS_PRIO -#define SCTP_SS_FAIR_BANDWITH SCTP_SS_FB -#define SCTP_SS_FIRST_COME SCTP_SS_FCFS - -/* fragment interleave constants - * setting must be one of these or - * EINVAL returned. - */ -#define SCTP_FRAG_LEVEL_0 0x00000000 -#define SCTP_FRAG_LEVEL_1 0x00000001 -#define SCTP_FRAG_LEVEL_2 0x00000002 - -/* - * user state values - */ -#define SCTP_CLOSED 0x0000 -#define SCTP_BOUND 0x1000 -#define SCTP_LISTEN 0x2000 -#define SCTP_COOKIE_WAIT 0x0002 -#define SCTP_COOKIE_ECHOED 0x0004 -#define SCTP_ESTABLISHED 0x0008 -#define SCTP_SHUTDOWN_SENT 0x0010 -#define SCTP_SHUTDOWN_RECEIVED 0x0020 -#define SCTP_SHUTDOWN_ACK_SENT 0x0040 -#define SCTP_SHUTDOWN_PENDING 0x0080 - -/* - * SCTP operational error codes (user visible) - */ -#define SCTP_CAUSE_NO_ERROR 0x0000 -#define SCTP_CAUSE_INVALID_STREAM 0x0001 -#define SCTP_CAUSE_MISSING_PARAM 0x0002 -#define SCTP_CAUSE_STALE_COOKIE 0x0003 -#define SCTP_CAUSE_OUT_OF_RESC 0x0004 -#define SCTP_CAUSE_UNRESOLVABLE_ADDR 0x0005 -#define SCTP_CAUSE_UNRECOG_CHUNK 0x0006 -#define SCTP_CAUSE_INVALID_PARAM 0x0007 -#define SCTP_CAUSE_UNRECOG_PARAM 0x0008 -#define SCTP_CAUSE_NO_USER_DATA 0x0009 -#define SCTP_CAUSE_COOKIE_IN_SHUTDOWN 0x000a -#define SCTP_CAUSE_RESTART_W_NEWADDR 0x000b -#define SCTP_CAUSE_USER_INITIATED_ABT 0x000c -#define SCTP_CAUSE_PROTOCOL_VIOLATION 0x000d - -/* Error causes from RFC5061 */ -#define SCTP_CAUSE_DELETING_LAST_ADDR 0x00a0 -#define SCTP_CAUSE_RESOURCE_SHORTAGE 0x00a1 -#define SCTP_CAUSE_DELETING_SRC_ADDR 0x00a2 -#define SCTP_CAUSE_ILLEGAL_ASCONF_ACK 0x00a3 -#define SCTP_CAUSE_REQUEST_REFUSED 0x00a4 - -/* Error causes from nat-draft */ -#define SCTP_CAUSE_NAT_COLLIDING_STATE 0x00b0 -#define SCTP_CAUSE_NAT_MISSING_STATE 0x00b1 - -/* Error causes from RFC4895 */ -#define SCTP_CAUSE_UNSUPPORTED_HMACID 0x0105 - -/* - * error cause parameters (user visible) - */ -struct sctp_gen_error_cause { - uint16_t code; - uint16_t length; - uint8_t info[]; -} SCTP_PACKED; - -struct sctp_error_cause { - uint16_t code; - uint16_t length; - /* optional cause-specific info may follow */ -} SCTP_PACKED; - -struct sctp_error_invalid_stream { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_INVALID_STREAM */ - uint16_t stream_id; /* stream id of the DATA in error */ - uint16_t reserved; -} SCTP_PACKED; - -struct sctp_error_missing_param { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_MISSING_PARAM */ - uint32_t num_missing_params; /* number of missing parameters */ - uint16_t type[]; -} SCTP_PACKED; - -struct sctp_error_stale_cookie { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_STALE_COOKIE */ - uint32_t stale_time; /* time in usec of staleness */ -} SCTP_PACKED; - -struct sctp_error_out_of_resource { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_OUT_OF_RESOURCES */ -} SCTP_PACKED; - -struct sctp_error_unresolv_addr { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRESOLVABLE_ADDR */ -} SCTP_PACKED; - -struct sctp_error_unrecognized_chunk { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRECOG_CHUNK */ - struct sctp_chunkhdr ch;/* header from chunk in error */ -} SCTP_PACKED; - -struct sctp_error_no_user_data { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_NO_USER_DATA */ - uint32_t tsn; /* TSN of the empty data chunk */ -} SCTP_PACKED; - -struct sctp_error_auth_invalid_hmac { - struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNSUPPORTED_HMACID */ - uint16_t hmac_id; -} SCTP_PACKED; - -/* - * Main SCTP chunk types we place these here so natd and f/w's in user land - * can find them. - */ -/************0x00 series ***********/ -#define SCTP_DATA 0x00 -#define SCTP_INITIATION 0x01 -#define SCTP_INITIATION_ACK 0x02 -#define SCTP_SELECTIVE_ACK 0x03 -#define SCTP_HEARTBEAT_REQUEST 0x04 -#define SCTP_HEARTBEAT_ACK 0x05 -#define SCTP_ABORT_ASSOCIATION 0x06 -#define SCTP_SHUTDOWN 0x07 -#define SCTP_SHUTDOWN_ACK 0x08 -#define SCTP_OPERATION_ERROR 0x09 -#define SCTP_COOKIE_ECHO 0x0a -#define SCTP_COOKIE_ACK 0x0b -#define SCTP_ECN_ECHO 0x0c -#define SCTP_ECN_CWR 0x0d -#define SCTP_SHUTDOWN_COMPLETE 0x0e -/* RFC4895 */ -#define SCTP_AUTHENTICATION 0x0f -/* EY nr_sack chunk id*/ -#define SCTP_NR_SELECTIVE_ACK 0x10 -/************0x40 series ***********/ -#define SCTP_IDATA 0x40 -/************0x80 series ***********/ -/* RFC5061 */ -#define SCTP_ASCONF_ACK 0x80 -/* draft-ietf-stewart-pktdrpsctp */ -#define SCTP_PACKET_DROPPED 0x81 -/* draft-ietf-stewart-strreset-xxx */ -#define SCTP_STREAM_RESET 0x82 - -/* RFC4820 */ -#define SCTP_PAD_CHUNK 0x84 -/************0xc0 series ***********/ -/* RFC3758 */ -#define SCTP_FORWARD_CUM_TSN 0xc0 -/* RFC5061 */ -#define SCTP_ASCONF 0xc1 -#define SCTP_IFORWARD_CUM_TSN 0xc2 - -/* ABORT and SHUTDOWN COMPLETE FLAG */ -#define SCTP_HAD_NO_TCB 0x01 - -/* Packet dropped flags */ -#define SCTP_FROM_MIDDLE_BOX SCTP_HAD_NO_TCB -#define SCTP_BADCRC 0x02 -#define SCTP_PACKET_TRUNCATED 0x04 - -/* Flag for ECN -CWR */ -#define SCTP_CWR_REDUCE_OVERRIDE 0x01 -#define SCTP_CWR_IN_SAME_WINDOW 0x02 - -#define SCTP_SAT_NETWORK_MIN 400 /* min ms for RTT to set satellite - * time */ -#define SCTP_SAT_NETWORK_BURST_INCR 2 /* how many times to multiply maxburst - * in sat */ - -/* Data Chuck Specific Flags */ -#define SCTP_DATA_FRAG_MASK 0x03 -#define SCTP_DATA_MIDDLE_FRAG 0x00 -#define SCTP_DATA_LAST_FRAG 0x01 -#define SCTP_DATA_FIRST_FRAG 0x02 -#define SCTP_DATA_NOT_FRAG 0x03 -#define SCTP_DATA_UNORDERED 0x04 -#define SCTP_DATA_SACK_IMMEDIATELY 0x08 -/* ECN Nonce: SACK Chunk Specific Flags */ -#define SCTP_SACK_NONCE_SUM 0x01 - -/* CMT DAC algorithm SACK flag */ -#define SCTP_SACK_CMT_DAC 0x80 - -/* - * PCB flags (in sctp_flags bitmask). - * Note the features and flags are meant - * for use by netstat. - */ -#define SCTP_PCB_FLAGS_UDPTYPE 0x00000001 -#define SCTP_PCB_FLAGS_TCPTYPE 0x00000002 -#define SCTP_PCB_FLAGS_BOUNDALL 0x00000004 -#define SCTP_PCB_FLAGS_ACCEPTING 0x00000008 -#define SCTP_PCB_FLAGS_UNBOUND 0x00000010 -#define SCTP_PCB_FLAGS_SND_ITERATOR_UP 0x00000020 -#define SCTP_PCB_FLAGS_CLOSE_IP 0x00040000 -#define SCTP_PCB_FLAGS_WAS_CONNECTED 0x00080000 -#define SCTP_PCB_FLAGS_WAS_ABORTED 0x00100000 -/* TCP model support */ - -#define SCTP_PCB_FLAGS_CONNECTED 0x00200000 -#define SCTP_PCB_FLAGS_IN_TCPPOOL 0x00400000 -#define SCTP_PCB_FLAGS_DONT_WAKE 0x00800000 -#define SCTP_PCB_FLAGS_WAKEOUTPUT 0x01000000 -#define SCTP_PCB_FLAGS_WAKEINPUT 0x02000000 -#define SCTP_PCB_FLAGS_BOUND_V6 0x04000000 -#define SCTP_PCB_FLAGS_BLOCKING_IO 0x08000000 -#define SCTP_PCB_FLAGS_SOCKET_GONE 0x10000000 -#define SCTP_PCB_FLAGS_SOCKET_ALLGONE 0x20000000 -#define SCTP_PCB_FLAGS_SOCKET_CANT_READ 0x40000000 -#if defined(__Userspace__) -#define SCTP_PCB_FLAGS_BOUND_CONN 0x80000000 - -/* flags to copy to new PCB */ -#define SCTP_PCB_COPY_FLAGS (SCTP_PCB_FLAGS_BOUNDALL|\ - SCTP_PCB_FLAGS_WAKEINPUT|\ - SCTP_PCB_FLAGS_BOUND_V6|\ - SCTP_PCB_FLAGS_BOUND_CONN) -#else - -/* flags to copy to new PCB */ -#define SCTP_PCB_COPY_FLAGS (SCTP_PCB_FLAGS_BOUNDALL|\ - SCTP_PCB_FLAGS_WAKEINPUT|\ - SCTP_PCB_FLAGS_BOUND_V6) -#endif - -/* - * PCB Features (in sctp_features bitmask) - */ -#define SCTP_PCB_FLAGS_DO_NOT_PMTUD 0x0000000000000001 -#define SCTP_PCB_FLAGS_EXT_RCVINFO 0x0000000000000002 /* deprecated */ -#define SCTP_PCB_FLAGS_DONOT_HEARTBEAT 0x0000000000000004 -#define SCTP_PCB_FLAGS_FRAG_INTERLEAVE 0x0000000000000008 -#define SCTP_PCB_FLAGS_INTERLEAVE_STRMS 0x0000000000000010 -#define SCTP_PCB_FLAGS_DO_ASCONF 0x0000000000000020 -#define SCTP_PCB_FLAGS_AUTO_ASCONF 0x0000000000000040 -/* socket options */ -#define SCTP_PCB_FLAGS_NODELAY 0x0000000000000100 -#define SCTP_PCB_FLAGS_AUTOCLOSE 0x0000000000000200 -#define SCTP_PCB_FLAGS_RECVDATAIOEVNT 0x0000000000000400 /* deprecated */ -#define SCTP_PCB_FLAGS_RECVASSOCEVNT 0x0000000000000800 -#define SCTP_PCB_FLAGS_RECVPADDREVNT 0x0000000000001000 -#define SCTP_PCB_FLAGS_RECVPEERERR 0x0000000000002000 -#define SCTP_PCB_FLAGS_RECVSENDFAILEVNT 0x0000000000004000 /* deprecated */ -#define SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT 0x0000000000008000 -#define SCTP_PCB_FLAGS_ADAPTATIONEVNT 0x0000000000010000 -#define SCTP_PCB_FLAGS_PDAPIEVNT 0x0000000000020000 -#define SCTP_PCB_FLAGS_AUTHEVNT 0x0000000000040000 -#define SCTP_PCB_FLAGS_STREAM_RESETEVNT 0x0000000000080000 -#define SCTP_PCB_FLAGS_NO_FRAGMENT 0x0000000000100000 -#define SCTP_PCB_FLAGS_EXPLICIT_EOR 0x0000000000400000 -#define SCTP_PCB_FLAGS_NEEDS_MAPPED_V4 0x0000000000800000 -#define SCTP_PCB_FLAGS_MULTIPLE_ASCONFS 0x0000000001000000 -#define SCTP_PCB_FLAGS_PORTREUSE 0x0000000002000000 -#define SCTP_PCB_FLAGS_DRYEVNT 0x0000000004000000 -#define SCTP_PCB_FLAGS_RECVRCVINFO 0x0000000008000000 -#define SCTP_PCB_FLAGS_RECVNXTINFO 0x0000000010000000 -#define SCTP_PCB_FLAGS_ASSOC_RESETEVNT 0x0000000020000000 -#define SCTP_PCB_FLAGS_STREAM_CHANGEEVNT 0x0000000040000000 -#define SCTP_PCB_FLAGS_RECVNSENDFAILEVNT 0x0000000080000000 - -/*- - * mobility_features parameters (by micchie).Note - * these features are applied against the - * sctp_mobility_features flags.. not the sctp_features - * flags. - */ -#define SCTP_MOBILITY_BASE 0x00000001 -#define SCTP_MOBILITY_FASTHANDOFF 0x00000002 -#define SCTP_MOBILITY_PRIM_DELETED 0x00000004 - -/* Smallest PMTU allowed when disabling PMTU discovery */ -#define SCTP_SMALLEST_PMTU 512 -/* Largest PMTU allowed when disabling PMTU discovery */ -#define SCTP_LARGEST_PMTU 65536 - -#if defined(_WIN32) -#pragma pack(pop) -#endif -#undef SCTP_PACKED - -#include - -/* This dictates the size of the packet - * collection buffer. This only applies - * if SCTP_PACKET_LOGGING is enabled in - * your config. - */ -#define SCTP_PACKET_LOG_SIZE 65536 - -/* Maximum delays and such a user can set for options that - * take ms. - */ -#define SCTP_MAX_SACK_DELAY 500 /* per RFC4960 */ -#define SCTP_MAX_HB_INTERVAL 14400000 /* 4 hours in ms */ -#define SCTP_MIN_COOKIE_LIFE 1000 /* 1 second in ms */ -#define SCTP_MAX_COOKIE_LIFE 3600000 /* 1 hour in ms */ - -/* Types of logging/KTR tracing that can be enabled via the - * sysctl net.inet.sctp.sctp_logging. You must also enable - * SUBSYS tracing. - * Note that you must have the SCTP option in the kernel - * to enable these as well. - */ -#define SCTP_BLK_LOGGING_ENABLE 0x00000001 -#define SCTP_CWND_MONITOR_ENABLE 0x00000002 -#define SCTP_CWND_LOGGING_ENABLE 0x00000004 -#define SCTP_FLIGHT_LOGGING_ENABLE 0x00000020 -#define SCTP_FR_LOGGING_ENABLE 0x00000040 -#define SCTP_LOCK_LOGGING_ENABLE 0x00000080 -#define SCTP_MAP_LOGGING_ENABLE 0x00000100 -#define SCTP_MBCNT_LOGGING_ENABLE 0x00000200 -#define SCTP_MBUF_LOGGING_ENABLE 0x00000400 -#define SCTP_NAGLE_LOGGING_ENABLE 0x00000800 -#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000 -#define SCTP_RTTVAR_LOGGING_ENABLE 0x00002000 -#define SCTP_SACK_LOGGING_ENABLE 0x00004000 -#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000 -#define SCTP_SB_LOGGING_ENABLE 0x00010000 -#define SCTP_STR_LOGGING_ENABLE 0x00020000 -#define SCTP_WAKE_LOGGING_ENABLE 0x00040000 -#define SCTP_LOG_MAXBURST_ENABLE 0x00080000 -#define SCTP_LOG_RWND_ENABLE 0x00100000 -#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000 -#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000 -#define SCTP_LTRACE_ERROR_ENABLE 0x00800000 -#define SCTP_LAST_PACKET_TRACING 0x01000000 -#define SCTP_THRESHOLD_LOGGING 0x02000000 -#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000 -#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000 -#define SCTP_LOG_TRY_ADVANCE 0x10000000 - -#endif /* !_NETINET_SCTP_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.c deleted file mode 100644 index 333f4ac4..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.c +++ /dev/null @@ -1,3531 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * debug flags: - * SCTP_DEBUG_ASCONF1: protocol info, general info and errors - * SCTP_DEBUG_ASCONF2: detailed info - */ - -/* - * RFC 5061 - * - * An ASCONF parameter queue exists per asoc which holds the pending address - * operations. Lists are updated upon receipt of ASCONF-ACK. - * - * A restricted_addrs list exists per assoc to hold local addresses that are - * not (yet) usable by the assoc as a source address. These addresses are - * either pending an ASCONF operation (and exist on the ASCONF parameter - * queue), or they are permanently restricted (the peer has returned an - * ERROR indication to an ASCONF(ADD), or the peer does not support ASCONF). - * - * Deleted addresses are always immediately removed from the lists as they will - * (shortly) no longer exist in the kernel. We send ASCONFs as a courtesy, - * only if allowed. - */ - -/* - * ASCONF parameter processing. - * response_required: set if a reply is required (eg. SUCCESS_REPORT). - * returns a mbuf to an "error" response parameter or NULL/"success" if ok. - * FIX: allocating this many mbufs on the fly is pretty inefficient... - */ -static struct mbuf * -sctp_asconf_success_response(uint32_t id) -{ - struct mbuf *m_reply = NULL; - struct sctp_asconf_paramhdr *aph; - - m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr), - 0, M_NOWAIT, 1, MT_DATA); - if (m_reply == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_success_response: couldn't get mbuf!\n"); - return (NULL); - } - aph = mtod(m_reply, struct sctp_asconf_paramhdr *); - aph->correlation_id = id; - aph->ph.param_type = htons(SCTP_SUCCESS_REPORT); - aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr); - SCTP_BUF_LEN(m_reply) = aph->ph.param_length; - aph->ph.param_length = htons(aph->ph.param_length); - - return (m_reply); -} - -static struct mbuf * -sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv, - uint16_t tlv_length) -{ - struct mbuf *m_reply = NULL; - struct sctp_asconf_paramhdr *aph; - struct sctp_error_cause *error; - uint32_t buf_len; - uint16_t i, param_length, cause_length, padding_length; - uint8_t *tlv; - - if (error_tlv == NULL) { - tlv_length = 0; - } - cause_length = sizeof(struct sctp_error_cause) + tlv_length; - param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length; - padding_length = tlv_length % 4; - if (padding_length != 0) { - padding_length = 4 - padding_length; - } - buf_len = param_length + padding_length; - if (buf_len > MLEN) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_error_response: tlv_length (%xh) too big\n", - tlv_length); - return (NULL); - } - m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_reply == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_error_response: couldn't get mbuf!\n"); - return (NULL); - } - aph = mtod(m_reply, struct sctp_asconf_paramhdr *); - aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND); - aph->ph.param_length = htons(param_length); - aph->correlation_id = id; - error = (struct sctp_error_cause *)(aph + 1); - error->code = htons(cause); - error->length = htons(cause_length); - if (error_tlv != NULL) { - tlv = (uint8_t *) (error + 1); - memcpy(tlv, error_tlv, tlv_length); - for (i = 0; i < padding_length; i++) { - tlv[tlv_length + i] = 0; - } - } - SCTP_BUF_LEN(m_reply) = buf_len; - return (m_reply); -} - -static struct mbuf * -sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph, - struct sctp_tcb *stcb, int send_hb, int response_required) -{ - struct sctp_nets *net; - struct mbuf *m_reply = NULL; - union sctp_sockstore store; - struct sctp_paramhdr *ph; - uint16_t param_type, aparam_length; -#if defined(INET) || defined(INET6) - uint16_t param_length; -#endif - struct sockaddr *sa; - int zero_address = 0; - int bad_address = 0; -#ifdef INET - struct sockaddr_in *sin; - struct sctp_ipv4addr_param *v4addr; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; - struct sctp_ipv6addr_param *v6addr; -#endif - - aparam_length = ntohs(aph->ph.param_length); - if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) { - return (NULL); - } - ph = (struct sctp_paramhdr *)(aph + 1); - param_type = ntohs(ph->param_type); -#if defined(INET) || defined(INET6) - param_length = ntohs(ph->param_length); - if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) { - return (NULL); - } -#endif - sa = &store.sa; - switch (param_type) { -#ifdef INET - case SCTP_IPV4_ADDRESS: - if (param_length != sizeof(struct sctp_ipv4addr_param)) { - /* invalid param size */ - return (NULL); - } - v4addr = (struct sctp_ipv4addr_param *)ph; - sin = &store.sin; - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_port = stcb->rport; - sin->sin_addr.s_addr = v4addr->addr; - if ((sin->sin_addr.s_addr == INADDR_BROADCAST) || - IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { - bad_address = 1; - } - if (sin->sin_addr.s_addr == INADDR_ANY) - zero_address = 1; - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - break; -#endif -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - if (param_length != sizeof(struct sctp_ipv6addr_param)) { - /* invalid param size */ - return (NULL); - } - v6addr = (struct sctp_ipv6addr_param *)ph; - sin6 = &store.sin6; - memset(sin6, 0, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6->sin6_port = stcb->rport; - memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr, - sizeof(struct in6_addr)); - if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { - bad_address = 1; - } - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) - zero_address = 1; - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - break; -#endif - default: - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, - aparam_length); - return (m_reply); - } /* end switch */ - - /* if 0.0.0.0/::0, add the source address instead */ - if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { - sa = src; - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_add_ip: using source addr "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); - } - net = NULL; - /* add the address */ - if (bad_address) { - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, - aparam_length); - } else if (sctp_add_remote_addr(stcb, sa, &net, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, - SCTP_ADDR_DYNAMIC_ADDED) != 0) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_add_ip: error adding address\n"); - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph, - aparam_length); - } else { - if (response_required) { - m_reply = - sctp_asconf_success_response(aph->correlation_id); - } - if (net != NULL) { - /* notify upper layer */ - sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED); - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, - stcb, net); - if (send_hb) { - sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - } - } - } - return (m_reply); -} - -static int -sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src) -{ - struct sctp_nets *src_net, *net, *nnet; - - /* make sure the source address exists as a destination net */ - src_net = sctp_findnet(stcb, src); - if (src_net == NULL) { - /* not found */ - return (-1); - } - - /* delete all destination addresses except the source */ - TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) { - if (net != src_net) { - /* delete this address */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_del_remote_addrs_except: deleting "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, - (struct sockaddr *)&net->ro._l_addr); - /* notify upper layer */ - sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, - (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED); - sctp_remove_net(stcb, net); - } - } - return (0); -} - -static struct mbuf * -sctp_process_asconf_delete_ip(struct sockaddr *src, - struct sctp_asconf_paramhdr *aph, - struct sctp_tcb *stcb, int response_required) -{ - struct mbuf *m_reply = NULL; - union sctp_sockstore store; - struct sctp_paramhdr *ph; - uint16_t param_type, aparam_length; -#if defined(INET) || defined(INET6) - uint16_t param_length; -#endif - struct sockaddr *sa; - int zero_address = 0; - int result; -#ifdef INET - struct sockaddr_in *sin; - struct sctp_ipv4addr_param *v4addr; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; - struct sctp_ipv6addr_param *v6addr; -#endif - - aparam_length = ntohs(aph->ph.param_length); - if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) { - return (NULL); - } - ph = (struct sctp_paramhdr *)(aph + 1); - param_type = ntohs(ph->param_type); -#if defined(INET) || defined(INET6) - param_length = ntohs(ph->param_length); - if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) { - return (NULL); - } -#endif - sa = &store.sa; - switch (param_type) { -#ifdef INET - case SCTP_IPV4_ADDRESS: - if (param_length != sizeof(struct sctp_ipv4addr_param)) { - /* invalid param size */ - return (NULL); - } - v4addr = (struct sctp_ipv4addr_param *)ph; - sin = &store.sin; - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_port = stcb->rport; - sin->sin_addr.s_addr = v4addr->addr; - if (sin->sin_addr.s_addr == INADDR_ANY) - zero_address = 1; - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_delete_ip: deleting "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - break; -#endif -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - if (param_length != sizeof(struct sctp_ipv6addr_param)) { - /* invalid param size */ - return (NULL); - } - v6addr = (struct sctp_ipv6addr_param *)ph; - sin6 = &store.sin6; - memset(sin6, 0, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6->sin6_port = stcb->rport; - memcpy(&sin6->sin6_addr, v6addr->addr, - sizeof(struct in6_addr)); - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) - zero_address = 1; - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_delete_ip: deleting "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - break; -#endif - default: - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, - aparam_length); - return (m_reply); - } - - /* make sure the source address is not being deleted */ - if (sctp_cmpaddr(sa, src)) { - /* trying to delete the source address! */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n"); - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph, - aparam_length); - return (m_reply); - } - - /* if deleting 0.0.0.0/::0, delete all addresses except src addr */ - if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { - result = sctp_asconf_del_remote_addrs_except(stcb, src); - - if (result) { - /* src address did not exist? */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: src addr does not exist?\n"); - /* what error to reply with?? */ - m_reply = - sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *) aph, - aparam_length); - } else if (response_required) { - m_reply = - sctp_asconf_success_response(aph->correlation_id); - } - return (m_reply); - } - - /* delete the address */ - result = sctp_del_remote_addr(stcb, sa); - /* - * note if result == -2, the address doesn't exist in the asoc but - * since it's being deleted anyways, we just ack the delete -- but - * this probably means something has already gone awry - */ - if (result == -1) { - /* only one address in the asoc */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete last IP addr!\n"); - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *) aph, - aparam_length); - } else { - if (response_required) { - m_reply = sctp_asconf_success_response(aph->correlation_id); - } - /* notify upper layer */ - sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED); - } - return (m_reply); -} - -static struct mbuf * -sctp_process_asconf_set_primary(struct sockaddr *src, - struct sctp_asconf_paramhdr *aph, - struct sctp_tcb *stcb, int response_required) -{ - struct mbuf *m_reply = NULL; - union sctp_sockstore store; - struct sctp_paramhdr *ph; - uint16_t param_type, aparam_length; -#if defined(INET) || defined(INET6) - uint16_t param_length; -#endif - struct sockaddr *sa; - int zero_address = 0; -#ifdef INET - struct sockaddr_in *sin; - struct sctp_ipv4addr_param *v4addr; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; - struct sctp_ipv6addr_param *v6addr; -#endif - - aparam_length = ntohs(aph->ph.param_length); - if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) { - return (NULL); - } - ph = (struct sctp_paramhdr *)(aph + 1); - param_type = ntohs(ph->param_type); -#if defined(INET) || defined(INET6) - param_length = ntohs(ph->param_length); - if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) { - return (NULL); - } -#endif - sa = &store.sa; - switch (param_type) { -#ifdef INET - case SCTP_IPV4_ADDRESS: - if (param_length != sizeof(struct sctp_ipv4addr_param)) { - /* invalid param size */ - return (NULL); - } - v4addr = (struct sctp_ipv4addr_param *)ph; - sin = &store.sin; - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_addr.s_addr = v4addr->addr; - if (sin->sin_addr.s_addr == INADDR_ANY) - zero_address = 1; - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - break; -#endif -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - if (param_length != sizeof(struct sctp_ipv6addr_param)) { - /* invalid param size */ - return (NULL); - } - v6addr = (struct sctp_ipv6addr_param *)ph; - sin6 = &store.sin6; - memset(sin6, 0, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(struct sockaddr_in6); -#endif - memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr, - sizeof(struct in6_addr)); - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) - zero_address = 1; - SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - break; -#endif - default: - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, - aparam_length); - return (m_reply); - } - - /* if 0.0.0.0/::0, use the source address instead */ - if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { - sa = src; - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_set_primary: using source addr "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); - } - /* set the primary address */ - if (sctp_set_primary_addr(stcb, sa, NULL) == 0) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_set_primary: primary address set\n"); - /* notify upper layer */ - sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED); - if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) && - ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF) == 0) && - (stcb->asoc.alternate != NULL)) { - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - if (response_required) { - m_reply = sctp_asconf_success_response(aph->correlation_id); - } - /* Mobility adaptation. - Ideally, when the reception of SET PRIMARY with DELETE IP - ADDRESS of the previous primary destination, unacknowledged - DATA are retransmitted immediately to the new primary - destination for seamless handover. - If the destination is UNCONFIRMED and marked to REQ_PRIM, - The retransmission occur when reception of the - HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in - sctp_input.c) - Also, when change of the primary destination, it is better - that all subsequent new DATA containing already queued DATA - are transmitted to the new primary destination. (by micchie) - */ - if ((sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_BASE) || - sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) && - sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_PRIM_DELETED) && - (stcb->asoc.primary_destination->dest_state & - SCTP_ADDR_UNCONFIRMED) == 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, - stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) { - sctp_assoc_immediate_retrans(stcb, - stcb->asoc.primary_destination); - } - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_BASE)) { - sctp_move_chunks_from_net(stcb, - stcb->asoc.deleted_primary); - } - sctp_delete_prim_timer(stcb->sctp_ep, stcb); - } - } else { - /* couldn't set the requested primary address! */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_set_primary: set primary failed!\n"); - /* must have been an invalid address, so report */ - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, - aparam_length); - } - - return (m_reply); -} - -/* - * handles an ASCONF chunk. - * if all parameters are processed ok, send a plain (empty) ASCONF-ACK - */ -void -sctp_handle_asconf(struct mbuf *m, unsigned int offset, - struct sockaddr *src, - struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb, - int first) -{ - struct sctp_association *asoc; - uint32_t serial_num; - struct mbuf *n, *m_ack, *m_result, *m_tail; - struct sctp_asconf_ack_chunk *ack_cp; - struct sctp_asconf_paramhdr *aph; - struct sctp_ipv6addr_param *p_addr; - unsigned int asconf_limit, cnt; - int error = 0; /* did an error occur? */ - - /* asconf param buffer */ - uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_asconf_ack *ack, *ack_next; - - /* verify minimum length */ - if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "handle_asconf: chunk too small = %xh\n", - ntohs(cp->ch.chunk_length)); - return; - } - asoc = &stcb->asoc; - serial_num = ntohl(cp->serial_number); - - if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) { - /* got a duplicate ASCONF */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "handle_asconf: got duplicate serial number = %xh\n", - serial_num); - return; - } else if (serial_num != (asoc->asconf_seq_in + 1)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n", - serial_num, asoc->asconf_seq_in + 1); - return; - } - - /* it's the expected "next" sequence number, so process it */ - asoc->asconf_seq_in = serial_num; /* update sequence */ - /* get length of all the param's in the ASCONF */ - asconf_limit = offset + ntohs(cp->ch.chunk_length); - SCTPDBG(SCTP_DEBUG_ASCONF1, - "handle_asconf: asconf_limit=%u, sequence=%xh\n", - asconf_limit, serial_num); - - if (first) { - /* delete old cache */ - SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: Now processing first ASCONF. Try to delete old cache\n"); - - TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) { - if (ack->serial_number == serial_num) - break; - SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: delete old(%u) < first(%u)\n", - ack->serial_number, serial_num); - TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next); - if (ack->data != NULL) { - sctp_m_freem(ack->data); - } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack); - } - } - - m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0, - M_NOWAIT, 1, MT_DATA); - if (m_ack == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "handle_asconf: couldn't get mbuf!\n"); - return; - } - m_tail = m_ack; /* current reply chain's tail */ - - /* fill in ASCONF-ACK header */ - ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *); - ack_cp->ch.chunk_type = SCTP_ASCONF_ACK; - ack_cp->ch.chunk_flags = 0; - ack_cp->serial_number = htonl(serial_num); - /* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */ - SCTP_BUF_LEN(m_ack) = sizeof(struct sctp_asconf_ack_chunk); - ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk); - - /* skip the lookup address parameter */ - offset += sizeof(struct sctp_asconf_chunk); - p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *)&aparam_buf); - if (p_addr == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "handle_asconf: couldn't get lookup addr!\n"); - /* respond with a missing/invalid mandatory parameter error */ - sctp_m_freem(m_ack); - return; - } - /* skip lookup addr */ - offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length)); - /* get pointer to first asconf param in ASCONF */ - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf); - if (aph == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "Empty ASCONF received?\n"); - goto send_reply; - } - /* process through all parameters */ - cnt = 0; - while (aph != NULL) { - unsigned int param_length, param_type; - - param_type = ntohs(aph->ph.param_type); - param_length = ntohs(aph->ph.param_length); - if (offset + param_length > asconf_limit) { - /* parameter goes beyond end of chunk! */ - sctp_m_freem(m_ack); - return; - } - m_result = NULL; - - if (param_length > sizeof(aparam_buf)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) larger than buffer size!\n", param_length); - sctp_m_freem(m_ack); - return; - } - if (param_length < sizeof(struct sctp_asconf_paramhdr)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length); - sctp_m_freem(m_ack); - return; - } - /* get the entire parameter */ - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf); - if (aph == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: couldn't get entire param\n"); - sctp_m_freem(m_ack); - return; - } - switch (param_type) { - case SCTP_ADD_IP_ADDRESS: - m_result = sctp_process_asconf_add_ip(src, aph, stcb, - (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error); - cnt++; - break; - case SCTP_DEL_IP_ADDRESS: - m_result = sctp_process_asconf_delete_ip(src, aph, stcb, - error); - break; - case SCTP_ERROR_CAUSE_IND: - /* not valid in an ASCONF chunk */ - break; - case SCTP_SET_PRIM_ADDR: - m_result = sctp_process_asconf_set_primary(src, aph, - stcb, error); - break; - case SCTP_NAT_VTAGS: - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n"); - break; - case SCTP_SUCCESS_REPORT: - /* not valid in an ASCONF chunk */ - break; - case SCTP_ULP_ADAPTATION: - /* FIX */ - break; - default: - if ((param_type & 0x8000) == 0) { - /* Been told to STOP at this param */ - asconf_limit = offset; - /* - * FIX FIX - We need to call - * sctp_arethere_unrecognized_parameters() - * to get a operr and send it for any - * param's with the 0x4000 bit set OR do it - * here ourselves... note we still must STOP - * if the 0x8000 bit is clear. - */ - } - /* unknown/invalid param type */ - break; - } /* switch */ - - /* add any (error) result to the reply mbuf chain */ - if (m_result != NULL) { - SCTP_BUF_NEXT(m_tail) = m_result; - m_tail = m_result; - ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result); - /* set flag to force success reports */ - error = 1; - } - offset += SCTP_SIZE32(param_length); - /* update remaining ASCONF message length to process */ - if (offset >= asconf_limit) { - /* no more data in the mbuf chain */ - break; - } - /* get pointer to next asconf param */ - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, - sizeof(struct sctp_asconf_paramhdr), - (uint8_t *)&aparam_buf); - if (aph == NULL) { - /* can't get an asconf paramhdr */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: can't get asconf param hdr!\n"); - /* FIX ME - add error here... */ - } - } - - send_reply: - ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length); - /* save the ASCONF-ACK reply */ - ack = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asconf_ack), - struct sctp_asconf_ack); - if (ack == NULL) { - sctp_m_freem(m_ack); - return; - } - ack->serial_number = serial_num; - ack->last_sent_to = NULL; - ack->data = m_ack; - ack->len = 0; - for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) { - ack->len += SCTP_BUF_LEN(n); - } - TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next); - - /* see if last_control_chunk_from is set properly (use IP src addr) */ - if (stcb->asoc.last_control_chunk_from == NULL) { - /* - * this could happen if the source address was just newly - * added - */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n"); - SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); - /* look up the from address */ - stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src); -#ifdef SCTP_DEBUG - if (stcb->asoc.last_control_chunk_from == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n"); - } -#endif - } -} - -/* - * does the address match? returns 0 if not, 1 if so - */ -static uint32_t -sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa) -{ - switch (sa->sa_family) { -#ifdef INET6 - case AF_INET6: - { - /* XXX scopeid */ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) && - (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr, - sizeof(struct in6_addr)) == 0)) { - return (1); - } - break; - } -#endif -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) && - (memcmp(&aa->ap.addrp.addr, &sin->sin_addr, - sizeof(struct in_addr)) == 0)) { - return (1); - } - break; - } -#endif - default: - break; - } - return (0); -} - -/* - * does the address match? returns 0 if not, 1 if so - */ -static uint32_t -sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa) -{ -#if defined(INET) || defined(INET6) - uint16_t param_type, param_length; - - param_type = ntohs(ph->param_type); - param_length = ntohs(ph->param_length); -#endif - switch (sa->sa_family) { -#ifdef INET6 - case AF_INET6: - { - /* XXX scopeid */ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - struct sctp_ipv6addr_param *v6addr; - - v6addr = (struct sctp_ipv6addr_param *)ph; - if ((param_type == SCTP_IPV6_ADDRESS) && - (param_length == sizeof(struct sctp_ipv6addr_param)) && - (memcmp(&v6addr->addr, &sin6->sin6_addr, - sizeof(struct in6_addr)) == 0)) { - return (1); - } - break; - } -#endif -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - struct sctp_ipv4addr_param *v4addr; - - v4addr = (struct sctp_ipv4addr_param *)ph; - if ((param_type == SCTP_IPV4_ADDRESS) && - (param_length == sizeof(struct sctp_ipv4addr_param)) && - (memcmp(&v4addr->addr, &sin->sin_addr, - sizeof(struct in_addr)) == 0)) { - return (1); - } - break; - } -#endif - default: - break; - } - return (0); -} -/* - * Cleanup for non-responded/OP ERR'd ASCONF - */ -void -sctp_asconf_cleanup(struct sctp_tcb *stcb) -{ - /* - * clear out any existing asconfs going out - */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2); - stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out; - /* remove the old ASCONF on our outbound queue */ - sctp_toss_old_asconf(stcb); -} - -/* - * cleanup any cached source addresses that may be topologically - * incorrect after a new address has been added to this interface. - */ -static void -sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn) -{ - struct sctp_nets *net; - - /* - * Ideally, we want to only clear cached routes and source addresses - * that are topologically incorrect. But since there is no easy way - * to know whether the newly added address on the ifn would cause a - * routing change (i.e. a new egress interface would be chosen) - * without doing a new routing lookup and source address selection, - * we will (for now) just flush any cached route using a different - * ifn (and cached source addrs) and let output re-choose them during - * the next send on that net. - */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* - * clear any cached route (and cached source address) if the - * route's interface is NOT the same as the address change. - * If it's the same interface, just clear the cached source - * address. - */ - if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) && - ((ifn == NULL) || - (SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) { - /* clear any cached route */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(&net->ro); -#else - RTFREE(net->ro.ro_rt); - net->ro.ro_rt = NULL; -#endif - } - /* clear any cached source address */ - if (net->src_addr_selected) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } - } -} - -void -sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet) -{ - int error; - - if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) { - return; - } - if (stcb->asoc.deleted_primary == NULL) { - return; - } - - if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Deleted primary is "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); - SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa); - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, - stcb->asoc.deleted_primary, - SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3); - stcb->asoc.num_send_timers_up--; - if (stcb->asoc.num_send_timers_up < 0) { - stcb->asoc.num_send_timers_up = 0; - } - SCTP_TCB_LOCK_ASSERT(stcb); - error = sctp_t3rxt_timer(stcb->sctp_ep, stcb, - stcb->asoc.deleted_primary); - if (error) { - SCTP_INP_DECR_REF(stcb->sctp_ep); - return; - } - SCTP_TCB_LOCK_ASSERT(stcb); -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary); -#endif - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); - if ((stcb->asoc.num_send_timers_up == 0) && - (stcb->asoc.sent_queue_cnt > 0)) { - struct sctp_tmit_chunk *chk; - - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->whoTo != NULL) { - break; - } - } - if (chk != NULL) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo); - } - } - } - return; -} - -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) -static int -sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t); - -void -sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - struct sctp_tmit_chunk *chk; - - SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO); - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_ASCONF + SCTP_LOC_4); - stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); - net->error_count = 0; - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->whoTo == net) { - if (chk->sent < SCTP_DATAGRAM_RESEND) { - chk->sent = SCTP_DATAGRAM_RESEND; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - sctp_flight_size_decrease(chk); - sctp_total_flight_decrease(stcb, chk); - net->marked_retrans++; - stcb->asoc.marked_retrans++; - } - } - } - if (net->marked_retrans) { - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); - } -} - -static void -sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa) -{ - struct sctp_nets *net; - int addrnum, changed; - - /* If number of local valid addresses is 1, the valid address is - probably newly added address. - Several valid addresses in this association. A source address - may not be changed. Additionally, they can be configured on a - same interface as "alias" addresses. (by micchie) - */ - addrnum = sctp_local_addr_count(stcb); - SCTPDBG(SCTP_DEBUG_ASCONF1, "p_check_react(): %d local addresses\n", - addrnum); - if (addrnum == 1) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* clear any cached route and source address */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(&net->ro); -#else - if (net->ro.ro_rt) { - RTFREE(net->ro.ro_rt); - net->ro.ro_rt = NULL; - } -#endif - if (net->src_addr_selected) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } - /* Retransmit unacknowledged DATA chunks immediately */ - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) { - sctp_net_immediate_retrans(stcb, net); - } - /* also, SET PRIMARY is maybe already sent */ - } - return; - } - - /* Multiple local addresses exist in the association. */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* clear any cached route and source address */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(&net->ro); -#else - if (net->ro.ro_rt) { - RTFREE(net->ro.ro_rt); - net->ro.ro_rt = NULL; - } -#endif - if (net->src_addr_selected) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } - /* Check if the nexthop is corresponding to the new address. - If the new address is corresponding to the current nexthop, - the path will be changed. - If the new address is NOT corresponding to the current - nexthop, the path will not be changed. - */ - SCTP_RTALLOC((sctp_route_t *)&net->ro, - stcb->sctp_ep->def_vrf_id, - stcb->sctp_ep->fibnum); -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net->ro.ro_nh == NULL) -#else - if (net->ro.ro_rt == NULL) -#endif - continue; - - changed = 0; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *)&net->ro)) { - changed = 1; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (sctp_v6src_match_nexthop( - &newifa->address.sin6, (sctp_route_t *)&net->ro)) { - changed = 1; - } - break; -#endif - default: - break; - } - /* if the newly added address does not relate routing - information, we skip. - */ - if (changed == 0) - continue; - /* Retransmit unacknowledged DATA chunks immediately */ - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) { - sctp_net_immediate_retrans(stcb, net); - } - /* Send SET PRIMARY for this new address */ - if (net == stcb->asoc.primary_destination) { - (void)sctp_asconf_queue_mgmt(stcb, newifa, - SCTP_SET_PRIM_ADDR); - } - } -} -#endif - -/* - * process an ADD/DELETE IP ack from peer. - * addr: corresponding sctp_ifa to the address being added/deleted. - * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS. - * flag: 1=success, 0=failure. - */ -static void -sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag) -{ - /* - * do the necessary asoc list work- if we get a failure indication, - * leave the address on the assoc's restricted list. If we get a - * success indication, remove the address from the restricted list. - */ - /* - * Note: this will only occur for ADD_IP_ADDRESS, since - * DEL_IP_ADDRESS is never actually added to the list... - */ - if (flag) { - /* success case, so remove from the restricted list */ - sctp_del_local_addr_restricted(stcb, addr); - -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_BASE) || - sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) { - sctp_path_check_and_react(stcb, addr); - return; - } -#endif - /* clear any cached/topologically incorrect source addresses */ - sctp_asconf_nets_cleanup(stcb, addr->ifn_p); - } - /* else, leave it on the list */ -} - -/* - * add an asconf add/delete/set primary IP address parameter to the queue. - * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR. - * returns 0 if queued, -1 if not queued/removed. - * NOTE: if adding, but a delete for the same address is already scheduled - * (and not yet sent out), simply remove it from queue. Same for deleting - * an address already scheduled for add. If a duplicate operation is found, - * ignore the new one. - */ -static int -sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, - uint16_t type) -{ - struct sctp_asconf_addr *aa, *aa_next; - - /* make sure the request isn't already in the queue */ - TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { - /* address match? */ - if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0) - continue; - /* is the request already in queue but not sent? - * pass the request already sent in order to resolve the following case: - * 1. arrival of ADD, then sent - * 2. arrival of DEL. we can't remove the ADD request already sent - * 3. arrival of ADD - */ - if (aa->ap.aph.ph.param_type == type && aa->sent == 0) { - return (-1); - } - /* is the negative request already in queue, and not sent */ - if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) && - (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) { - /* add requested, delete already queued */ - TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); - /* remove the ifa from the restricted list */ - sctp_del_local_addr_restricted(stcb, ifa); - /* free the asconf param */ - SCTP_FREE(aa, SCTP_M_ASC_ADDR); - SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n"); - return (-1); - } - if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) && - (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) { - /* delete requested, add already queued */ - TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); - /* remove the aa->ifa from the restricted list */ - sctp_del_local_addr_restricted(stcb, aa->ifa); - /* free the asconf param */ - SCTP_FREE(aa, SCTP_M_ASC_ADDR); - SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n"); - return (-1); - } - } /* for each aa */ - - /* adding new request to the queue */ - SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), - SCTP_M_ASC_ADDR); - if (aa == NULL) { - /* didn't get memory */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n"); - return (-1); - } - aa->special_del = 0; - /* fill in asconf address parameter fields */ - /* top level elements are "networked" during send */ - aa->ap.aph.ph.param_type = type; - aa->ifa = ifa; - atomic_add_int(&ifa->refcount, 1); - /* correlation_id filled in during send routine later... */ - switch (ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = &ifa->address.sin6; - aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + - sizeof(struct sctp_ipv6addr_param); - memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, - sizeof(struct in6_addr)); - break; - } -#endif -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = &ifa->address.sin; - aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + - sizeof(struct sctp_ipv4addr_param); - memcpy(&aa->ap.addrp.addr, &sin->sin_addr, - sizeof(struct in_addr)); - break; - } -#endif - default: - /* invalid family! */ - SCTP_FREE(aa, SCTP_M_ASC_ADDR); - sctp_free_ifa(ifa); - return (-1); - } - aa->sent = 0; /* clear sent flag */ - - TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); -#ifdef SCTP_DEBUG - if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) { - if (type == SCTP_ADD_IP_ADDRESS) { - SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); - } else if (type == SCTP_DEL_IP_ADDRESS) { - SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); - } else { - SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); - } - } -#endif - - return (0); -} - -/* - * add an asconf operation for the given ifa and type. - * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR. - * returns 0 if completed, -1 if not completed, 1 if immediate send is - * advisable. - */ -static int -sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa, - uint16_t type) -{ - uint32_t status; - int pending_delete_queued = 0; - int last; - - /* see if peer supports ASCONF */ - if (stcb->asoc.asconf_supported == 0) { - return (-1); - } - - /* - * if this is deleting the last address from the assoc, mark it as - * pending. - */ - if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending) { - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - last = (sctp_local_addr_count(stcb) == 0); - } else { - last = (sctp_local_addr_count(stcb) == 1); - } - if (last) { - /* set the pending delete info only */ - stcb->asoc.asconf_del_pending = 1; - stcb->asoc.asconf_addr_del_pending = ifa; - atomic_add_int(&ifa->refcount, 1); - SCTPDBG(SCTP_DEBUG_ASCONF2, - "asconf_queue_add: mark delete last address pending\n"); - return (-1); - } - } - - /* queue an asconf parameter */ - status = sctp_asconf_queue_mgmt(stcb, ifa, type); - - /* - * if this is an add, and there is a delete also pending (i.e. the - * last local address is being changed), queue the pending delete too. - */ - if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) { - /* queue in the pending delete */ - if (sctp_asconf_queue_mgmt(stcb, - stcb->asoc.asconf_addr_del_pending, - SCTP_DEL_IP_ADDRESS) == 0) { - SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queuing pending delete\n"); - pending_delete_queued = 1; - /* clear out the pending delete info */ - stcb->asoc.asconf_del_pending = 0; - sctp_free_ifa(stcb->asoc.asconf_addr_del_pending); - stcb->asoc.asconf_addr_del_pending = NULL; - } - } - - if (pending_delete_queued) { - struct sctp_nets *net; - /* - * since we know that the only/last address is now being - * changed in this case, reset the cwnd/rto on all nets to - * start as a new address and path. Also clear the error - * counts to give the assoc the best chance to complete the - * address change. - */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, - net); - net->RTO = 0; - net->error_count = 0; - } - stcb->asoc.overall_error_count = 0; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_ASCONF, - __LINE__); - } - - /* queue in an advisory set primary too */ - (void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR); - /* let caller know we should send this out immediately */ - status = 1; - } - return (status); -} - -/*- - * add an asconf delete IP address parameter to the queue by sockaddr and - * possibly with no sctp_ifa available. This is only called by the routine - * that checks the addresses in an INIT-ACK against the current address list. - * returns 0 if completed, non-zero if not completed. - * NOTE: if an add is already scheduled (and not yet sent out), simply - * remove it from queue. If a duplicate operation is found, ignore the - * new one. - */ -static int -sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa) -{ - struct sctp_ifa *ifa; - struct sctp_asconf_addr *aa, *aa_next; - - if (stcb == NULL) { - return (-1); - } - /* see if peer supports ASCONF */ - if (stcb->asoc.asconf_supported == 0) { - return (-1); - } - /* make sure the request isn't already in the queue */ - TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { - /* address match? */ - if (sctp_asconf_addr_match(aa, sa) == 0) - continue; - /* is the request already in queue (sent or not) */ - if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) { - return (-1); - } - /* is the negative request already in queue, and not sent */ - if (aa->sent == 1) - continue; - if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) { - /* add already queued, so remove existing entry */ - TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); - sctp_del_local_addr_restricted(stcb, aa->ifa); - /* free the entry */ - SCTP_FREE(aa, SCTP_M_ASC_ADDR); - return (-1); - } - } /* for each aa */ - - /* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */ - ifa = sctp_find_ifa_by_addr(sa, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); - - /* adding new request to the queue */ - SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), - SCTP_M_ASC_ADDR); - if (aa == NULL) { - /* didn't get memory */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "sctp_asconf_queue_sa_delete: failed to get memory!\n"); - return (-1); - } - aa->special_del = 0; - /* fill in asconf address parameter fields */ - /* top level elements are "networked" during send */ - aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS; - aa->ifa = ifa; - if (ifa) - atomic_add_int(&ifa->refcount, 1); - /* correlation_id filled in during send routine later... */ - switch (sa->sa_family) { -#ifdef INET6 - case AF_INET6: - { - /* IPv6 address */ - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)sa; - aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param); - memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, - sizeof(struct in6_addr)); - break; - } -#endif -#ifdef INET - case AF_INET: - { - /* IPv4 address */ - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param); - memcpy(&aa->ap.addrp.addr, &sin->sin_addr, - sizeof(struct in_addr)); - break; - } -#endif - default: - /* invalid family! */ - SCTP_FREE(aa, SCTP_M_ASC_ADDR); - if (ifa) - sctp_free_ifa(ifa); - return (-1); - } - aa->sent = 0; /* clear sent flag */ - - /* delete goes to the back of the queue */ - TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); - - /* sa_ignore MEMLEAK {memory is put on the tailq} */ - return (0); -} - -/* - * find a specific asconf param on our "sent" queue - */ -static struct sctp_asconf_addr * -sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id) -{ - struct sctp_asconf_addr *aa; - - TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) { - if (aa->ap.aph.correlation_id == correlation_id && - aa->sent == 1) { - /* found it */ - return (aa); - } - } - /* didn't find it */ - return (NULL); -} - -/* - * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do - * notifications based on the error response - */ -static void -sctp_asconf_process_error(struct sctp_tcb *stcb SCTP_UNUSED, - struct sctp_asconf_paramhdr *aph) -{ - struct sctp_error_cause *eh; - struct sctp_paramhdr *ph; - uint16_t param_type; - uint16_t error_code; - - eh = (struct sctp_error_cause *)(aph + 1); - ph = (struct sctp_paramhdr *)(eh + 1); - /* validate lengths */ - if (htons(eh->length) + sizeof(struct sctp_error_cause) > - htons(aph->ph.param_length)) { - /* invalid error cause length */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_process_error: cause element too long\n"); - return; - } - if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) > - htons(eh->length)) { - /* invalid included TLV length */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_process_error: included TLV too long\n"); - return; - } - /* which error code ? */ - error_code = ntohs(eh->code); - param_type = ntohs(aph->ph.param_type); - /* FIX: this should go back up the REMOTE_ERROR ULP notify */ - switch (error_code) { - case SCTP_CAUSE_RESOURCE_SHORTAGE: - /* we allow ourselves to "try again" for this error */ - break; - default: - /* peer can't handle it... */ - switch (param_type) { - case SCTP_ADD_IP_ADDRESS: - case SCTP_DEL_IP_ADDRESS: - case SCTP_SET_PRIM_ADDR: - break; - default: - break; - } - } -} - -/* - * process an asconf queue param. - * aparam: parameter to process, will be removed from the queue. - * flag: 1=success case, 0=failure case - */ -static void -sctp_asconf_process_param_ack(struct sctp_tcb *stcb, - struct sctp_asconf_addr *aparam, uint32_t flag) -{ - uint16_t param_type; - - /* process this param */ - param_type = aparam->ap.aph.ph.param_type; - switch (param_type) { - case SCTP_ADD_IP_ADDRESS: - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_param_ack: added IP address\n"); - sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag); - break; - case SCTP_DEL_IP_ADDRESS: - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_param_ack: deleted IP address\n"); - /* nothing really to do... lists already updated */ - break; - case SCTP_SET_PRIM_ADDR: - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_param_ack: set primary IP address\n"); - /* nothing to do... peer may start using this addr */ - break; - default: - /* should NEVER happen */ - break; - } - - /* remove the param and free it */ - TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next); - if (aparam->ifa) - sctp_free_ifa(aparam->ifa); - SCTP_FREE(aparam, SCTP_M_ASC_ADDR); -} - -/* - * cleanup from a bad asconf ack parameter - */ -static void -sctp_asconf_ack_clear(struct sctp_tcb *stcb SCTP_UNUSED) -{ - /* assume peer doesn't really know how to do asconfs */ - /* XXX we could free the pending queue here */ - -} - -void -sctp_handle_asconf_ack(struct mbuf *m, int offset, - struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb, - struct sctp_nets *net, int *abort_no_unlock) -{ - struct sctp_association *asoc; - uint32_t serial_num; - uint16_t ack_length; - struct sctp_asconf_paramhdr *aph; - struct sctp_asconf_addr *aa, *aa_next; - uint32_t last_error_id = 0; /* last error correlation id */ - uint32_t id; - struct sctp_asconf_addr *ap; - - /* asconf param buffer */ - uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; - - /* verify minimum length */ - if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "handle_asconf_ack: chunk too small = %xh\n", - ntohs(cp->ch.chunk_length)); - return; - } - asoc = &stcb->asoc; - serial_num = ntohl(cp->serial_number); - - /* - * NOTE: we may want to handle this differently- currently, we will - * abort when we get an ack for the expected serial number + 1 (eg. - * we didn't send it), process an ack normally if it is the expected - * serial number, and re-send the previous ack for *ALL* other - * serial numbers - */ - - /* - * if the serial number is the next expected, but I didn't send it, - * abort the asoc, since someone probably just hijacked us... - */ - if (serial_num == (asoc->asconf_seq_out + 1)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n"); - SCTP_SNPRINTF(msg, sizeof(msg), "Never sent serial number %8.8x", serial_num); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_no_unlock = 1; - return; - } - if (serial_num != asoc->asconf_seq_out_acked + 1) { - /* got a duplicate/unexpected ASCONF-ACK */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n", - serial_num, asoc->asconf_seq_out_acked + 1); - return; - } - - if (serial_num == asoc->asconf_seq_out - 1) { - /* stop our timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_ASCONF + SCTP_LOC_5); - } - - /* process the ASCONF-ACK contents */ - ack_length = ntohs(cp->ch.chunk_length) - - sizeof(struct sctp_asconf_ack_chunk); - offset += sizeof(struct sctp_asconf_ack_chunk); - /* process through all parameters */ - while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) { - unsigned int param_length, param_type; - - /* get pointer to next asconf parameter */ - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, - sizeof(struct sctp_asconf_paramhdr), aparam_buf); - if (aph == NULL) { - /* can't get an asconf paramhdr */ - sctp_asconf_ack_clear(stcb); - return; - } - param_type = ntohs(aph->ph.param_type); - param_length = ntohs(aph->ph.param_length); - if (param_length > ack_length) { - sctp_asconf_ack_clear(stcb); - return; - } - if (param_length < sizeof(struct sctp_asconf_paramhdr)) { - sctp_asconf_ack_clear(stcb); - return; - } - /* get the complete parameter... */ - if (param_length > sizeof(aparam_buf)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "param length (%u) larger than buffer size!\n", param_length); - sctp_asconf_ack_clear(stcb); - return; - } - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf); - if (aph == NULL) { - sctp_asconf_ack_clear(stcb); - return; - } - /* correlation_id is transparent to peer, no ntohl needed */ - id = aph->correlation_id; - - switch (param_type) { - case SCTP_ERROR_CAUSE_IND: - last_error_id = id; - /* find the corresponding asconf param in our queue */ - ap = sctp_asconf_find_param(stcb, id); - if (ap == NULL) { - /* hmm... can't find this in our queue! */ - break; - } - /* process the parameter, failed flag */ - sctp_asconf_process_param_ack(stcb, ap, 0); - /* process the error response */ - sctp_asconf_process_error(stcb, aph); - break; - case SCTP_SUCCESS_REPORT: - /* find the corresponding asconf param in our queue */ - ap = sctp_asconf_find_param(stcb, id); - if (ap == NULL) { - /* hmm... can't find this in our queue! */ - break; - } - /* process the parameter, success flag */ - sctp_asconf_process_param_ack(stcb, ap, 1); - break; - default: - break; - } /* switch */ - - /* update remaining ASCONF-ACK message length to process */ - if (ack_length > SCTP_SIZE32(param_length)) { - ack_length -= SCTP_SIZE32(param_length); - } else { - break; - } - offset += SCTP_SIZE32(param_length); - } /* while */ - - /* - * if there are any "sent" params still on the queue, these are - * implicitly "success", or "failed" (if we got an error back) ... - * so process these appropriately - * - * we assume that the correlation_id's are monotonically increasing - * beginning from 1 and that we don't have *that* many outstanding - * at any given time - */ - if (last_error_id == 0) - last_error_id--; /* set to "max" value */ - TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { - if (aa->sent == 1) { - /* - * implicitly successful or failed if correlation_id - * < last_error_id, then success else, failure - */ - if (aa->ap.aph.correlation_id < last_error_id) - sctp_asconf_process_param_ack(stcb, aa, 1); - else - sctp_asconf_process_param_ack(stcb, aa, 0); - } else { - /* - * since we always process in order (FIFO queue) if - * we reach one that hasn't been sent, the rest - * should not have been sent either. so, we're - * done... - */ - break; - } - } - - /* update the next sequence number to use */ - asoc->asconf_seq_out_acked++; - /* remove the old ASCONF on our outbound queue */ - sctp_toss_old_asconf(stcb); - if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) { -#ifdef SCTP_TIMER_BASED_ASCONF - /* we have more params, so restart our timer */ - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, - stcb, net); -#else - /* we have more params, so send out more */ - sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); -#endif - } -} - -#ifdef INET6 -static uint32_t -sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa) -{ - struct sockaddr_in6 *sin6, *net6; - struct sctp_nets *net; - - if (sa->sa_family != AF_INET6) { - /* wrong family */ - return (0); - } - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) { - /* not link local address */ - return (0); - } - /* hunt through our destination nets list for this scope_id */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (((struct sockaddr *)(&net->ro._l_addr))->sa_family != - AF_INET6) - continue; - net6 = (struct sockaddr_in6 *)&net->ro._l_addr; - if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0) - continue; - if (sctp_is_same_scope(sin6, net6)) { - /* found one */ - return (1); - } - } - /* didn't find one */ - return (0); -} -#endif - -/* - * address management functions - */ -static void -sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_ifa *ifa, uint16_t type, int addr_locked) -{ - int status; - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 || - sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { - /* subset bound, no ASCONF allowed case, so ignore */ - return; - } - /* - * note: we know this is not the subset bound, no ASCONF case eg. - * this is boundall or subset bound w/ASCONF allowed - */ - - /* first, make sure that the address is IPv4 or IPv6 and not jailed */ - switch (ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &ifa->address.sin6.sin6_addr) != 0) { - return; - } -#endif - break; -#endif -#ifdef INET - case AF_INET: -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &ifa->address.sin.sin_addr) != 0) { - return; - } -#endif - break; -#endif - default: - return; - } -#ifdef INET6 - /* make sure we're "allowed" to add this type of addr */ - if (ifa->address.sa.sa_family == AF_INET6) { - /* invalid if we're not a v6 endpoint */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) - return; - /* is the v6 addr really valid ? */ - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - return; - } - } -#endif - /* put this address on the "pending/do not use yet" list */ - sctp_add_local_addr_restricted(stcb, ifa); - /* - * check address scope if address is out of scope, don't queue - * anything... note: this would leave the address on both inp and - * asoc lists - */ - switch (ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = &ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecified addresses */ - return; - } - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (stcb->asoc.scope.local_scope == 0) { - return; - } - /* is it the right link local scope? */ - if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) { - return; - } - } - if (stcb->asoc.scope.site_scope == 0 && - IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - return; - } - break; - } -#endif -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - /* invalid if we are a v6 only endpoint */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) - return; - - sin = &ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - /* we skip unspecified addresses */ - return; - } - if (stcb->asoc.scope.ipv4_local_scope == 0 && - IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { - return; - } - break; - } -#endif - default: - /* else, not AF_INET or AF_INET6, so skip */ - return; - } - - /* queue an asconf for this address add/delete */ - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { - /* does the peer do asconf? */ - if (stcb->asoc.asconf_supported) { - /* queue an asconf for this addr */ - status = sctp_asconf_queue_add(stcb, ifa, type); - - /* - * if queued ok, and in the open state, send out the - * ASCONF. If in the non-open state, these will be - * sent when the state goes open. - */ - if (status == 0 && - ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED))) { -#ifdef SCTP_TIMER_BASED_ASCONF - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, - stcb, stcb->asoc.primary_destination); -#else - sctp_send_asconf(stcb, NULL, addr_locked); -#endif - } - } - } -} - -int -sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED) -{ - struct sctp_asconf_iterator *asc; - struct sctp_ifa *ifa; - struct sctp_laddr *l; - int cnt_invalid = 0; - - asc = (struct sctp_asconf_iterator *)ptr; - LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { - ifa = l->ifa; - switch (ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - /* invalid if we're not a v6 endpoint */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return (1); - } - break; -#endif -#ifdef INET - case AF_INET: - { - /* invalid if we are a v6 only endpoint */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return (1); - } - break; - } -#endif - default: - /* invalid address family */ - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return (1); - } - } - return (0); -} - -static int -sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED) -{ - struct sctp_ifa *ifa; - struct sctp_asconf_iterator *asc; - struct sctp_laddr *laddr, *nladdr, *l; - - /* Only for specific case not bound all */ - asc = (struct sctp_asconf_iterator *)ptr; - LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { - ifa = l->ifa; - if (l->action == SCTP_ADD_IP_ADDRESS) { - LIST_FOREACH(laddr, &inp->sctp_addr_list, - sctp_nxt_addr) { - if (laddr->ifa == ifa) { - laddr->action = 0; - break; - } - } - } else if (l->action == SCTP_DEL_IP_ADDRESS) { - LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { - /* remove only after all guys are done */ - if (laddr->ifa == ifa) { - sctp_del_local_addr_ep(inp, ifa); - } - } - } - } - return (0); -} - -void -sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - void *ptr, uint32_t val SCTP_UNUSED) -{ - struct sctp_asconf_iterator *asc; - struct sctp_ifa *ifa; - struct sctp_laddr *l; - int cnt_invalid = 0; - int type, status; - int num_queued = 0; - - asc = (struct sctp_asconf_iterator *)ptr; - LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { - ifa = l->ifa; - type = l->action; - - /* address's vrf_id must be the vrf_id of the assoc */ - if (ifa->vrf_id != stcb->asoc.vrf_id) { - continue; - } - - /* Same checks again for assoc */ - switch (ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - { - /* invalid if we're not a v6 endpoint */ - struct sockaddr_in6 *sin6; - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return; - else - continue; - } - sin6 = &ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecified addresses */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (stcb->asoc.scope.local_scope == 0) { - continue; - } - /* is it the right link local scope? */ - if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) { - continue; - } - } - break; - } -#endif -#ifdef INET - case AF_INET: - { - /* invalid if we are a v6 only endpoint */ - struct sockaddr_in *sin; - - /* invalid if we are a v6 only endpoint */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) - continue; - - sin = &ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - /* we skip unspecified addresses */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if (stcb->asoc.scope.ipv4_local_scope == 0 && - IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { - continue; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return; - else - continue; - } - break; - } -#endif - default: - /* invalid address family */ - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return; - else - continue; - } - - if (type == SCTP_ADD_IP_ADDRESS) { - /* prevent this address from being used as a source */ - sctp_add_local_addr_restricted(stcb, ifa); - } else if (type == SCTP_DEL_IP_ADDRESS) { - struct sctp_nets *net; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* delete this address if cached */ - if (net->ro._s_addr == ifa) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(&net->ro); -#else - if (net->ro.ro_rt) { - RTFREE(net->ro.ro_rt); - net->ro.ro_rt = NULL; - } -#endif - /* - * Now we deleted our src address, - * should we not also now reset the - * cwnd/rto to start as if its a new - * address? - */ - stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); - net->RTO = 0; - } - } - } else if (type == SCTP_SET_PRIM_ADDR) { - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { - /* must validate the ifa is in the ep */ - if (sctp_is_addr_in_ep(stcb->sctp_ep, ifa) == 0) { - continue; - } - } else { - /* Need to check scopes for this guy */ - if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { - continue; - } - } - } - /* queue an asconf for this address add/delete */ - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) && - stcb->asoc.asconf_supported == 1) { - /* queue an asconf for this addr */ - status = sctp_asconf_queue_add(stcb, ifa, type); - /* - * if queued ok, and in the open state, update the - * count of queued params. If in the non-open state, - * these get sent when the assoc goes open. - */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - if (status >= 0) { - num_queued++; - } - } - } - } - /* - * If we have queued params in the open state, send out an ASCONF. - */ - if (num_queued > 0) { - sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); - } -} - -void -sctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED) -{ - struct sctp_asconf_iterator *asc; - struct sctp_ifa *ifa; - struct sctp_laddr *l, *nl; - - asc = (struct sctp_asconf_iterator *)ptr; - LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) { - ifa = l->ifa; - if (l->action == SCTP_ADD_IP_ADDRESS) { - /* Clear the defer use flag */ - ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - sctp_free_ifa(ifa); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l); - SCTP_DECR_LADDR_COUNT(); - } - SCTP_FREE(asc, SCTP_M_ASC_IT); -} - -/* - * sa is the sockaddr to ask the peer to set primary to. - * returns: 0 = completed, -1 = error - */ -int32_t -sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) -{ - uint32_t vrf_id; - struct sctp_ifa *ifa; - - /* find the ifa for the desired set primary */ - vrf_id = stcb->asoc.vrf_id; - ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); - if (ifa == NULL) { - /* Invalid address */ - return (-1); - } - - /* queue an ASCONF:SET_PRIM_ADDR to be sent */ - if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) { - /* set primary queuing succeeded */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "set_primary_ip_address_sa: queued on tcb=%p, ", - (void *)stcb); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { -#ifdef SCTP_TIMER_BASED_ASCONF - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, - stcb->sctp_ep, stcb, - stcb->asoc.primary_destination); -#else - sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); -#endif - } - } else { - SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ", - (void *)stcb); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - return (-1); - } - return (0); -} - -int -sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) -{ - struct sctp_tmit_chunk *chk, *nchk; - unsigned int offset, asconf_limit; - struct sctp_asconf_chunk *acp; - struct sctp_asconf_paramhdr *aph; - uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_paramhdr *ph; - int add_cnt, del_cnt; - uint16_t last_param_type; - - add_cnt = del_cnt = 0; - last_param_type = 0; - TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) { - if (chk->data == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n"); - continue; - } - offset = 0; - acp = mtod(chk->data, struct sctp_asconf_chunk *); - offset += sizeof(struct sctp_asconf_chunk); - asconf_limit = ntohs(acp->ch.chunk_length); - ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf); - if (ph == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n"); - continue; - } - offset += ntohs(ph->param_length); - - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf); - if (aph == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n"); - continue; - } - while (aph != NULL) { - unsigned int param_length, param_type; - - param_type = ntohs(aph->ph.param_type); - param_length = ntohs(aph->ph.param_length); - if (offset + param_length > asconf_limit) { - /* parameter goes beyond end of chunk! */ - break; - } - if (param_length > sizeof(aparam_buf)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length); - break; - } - if (param_length <= sizeof(struct sctp_paramhdr)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length); - break; - } - - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf); - if (aph == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n"); - break; - } - - ph = (struct sctp_paramhdr *)(aph + 1); - if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) { - switch (param_type) { - case SCTP_ADD_IP_ADDRESS: - add_cnt++; - break; - case SCTP_DEL_IP_ADDRESS: - del_cnt++; - break; - default: - break; - } - last_param_type = param_type; - } - - offset += SCTP_SIZE32(param_length); - if (offset >= asconf_limit) { - /* no more data in the mbuf chain */ - break; - } - /* get pointer to next asconf param */ - aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf); - } - } - - /* we want to find the sequences which consist of ADD -> DEL -> ADD or DEL -> ADD */ - if (add_cnt > del_cnt || - (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) { - return (1); - } - return (0); -} - -static struct sockaddr * -sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked) -{ - struct sctp_vrf *vrf = NULL; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(stcb->asoc.vrf_id); - if (vrf == NULL) { - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RUNLOCK(); - return (NULL); - } - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if (stcb->asoc.scope.loopback_scope == 0 && - SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* Skip if loopback_scope not set */ - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (stcb->asoc.scope.ipv4_addr_legal) { - struct sockaddr_in *sin; - - sin = &sctp_ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - /* skip unspecified addresses */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if (stcb->asoc.scope.ipv4_local_scope == 0 && - IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) - continue; - - if (sctp_is_addr_restricted(stcb, sctp_ifa) && - (!sctp_is_addr_pending(stcb, sctp_ifa))) - continue; - /* found a valid local v4 address to use */ - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RUNLOCK(); - return (&sctp_ifa->address.sa); - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (stcb->asoc.scope.ipv6_addr_legal) { - struct sockaddr_in6 *sin6; - - if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - continue; - } - - sin6 = &sctp_ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecified addresses */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if (stcb->asoc.scope.local_scope == 0 && - IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - continue; - if (stcb->asoc.scope.site_scope == 0 && - IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) - continue; - - if (sctp_is_addr_restricted(stcb, sctp_ifa) && - (!sctp_is_addr_pending(stcb, sctp_ifa))) - continue; - /* found a valid local v6 address to use */ - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RUNLOCK(); - return (&sctp_ifa->address.sa); - } - break; -#endif - default: - break; - } - } - } - /* no valid addresses found */ - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RUNLOCK(); - return (NULL); -} - -static struct sockaddr * -sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb) -{ - struct sctp_laddr *laddr; - - LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - continue; - } - /* is the address restricted ? */ - if (sctp_is_addr_restricted(stcb, laddr->ifa) && - (!sctp_is_addr_pending(stcb, laddr->ifa))) - continue; - - /* found a valid local address to use */ - return (&laddr->ifa->address.sa); - } - /* no valid addresses found */ - return (NULL); -} - -/* - * builds an ASCONF chunk from queued ASCONF params. - * returns NULL on error (no mbuf, no ASCONF params queued, etc). - */ -struct mbuf * -sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) -{ - struct mbuf *m_asconf, *m_asconf_chk; - struct sctp_asconf_addr *aa; - struct sctp_asconf_chunk *acp; - struct sctp_asconf_paramhdr *aph; - struct sctp_asconf_addr_param *aap; - uint32_t p_length, overhead; - uint32_t correlation_id = 1; /* 0 is reserved... */ - caddr_t ptr, lookup_ptr; - uint8_t lookup_used = 0; - - /* are there any asconf params to send? */ - TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) { - if (aa->sent == 0) - break; - } - if (aa == NULL) - return (NULL); - - /* Consider IP header and SCTP common header. */ - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - overhead = SCTP_MIN_OVERHEAD; - } else { - overhead = SCTP_MIN_V4_OVERHEAD; - } - /* Consider ASONF chunk. */ - overhead += sizeof(struct sctp_asconf_chunk); - /* Consider AUTH chunk. */ - overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - if (stcb->asoc.smallest_mtu <= overhead) { - /* MTU too small. */ - return (NULL); - } - /* - * get a chunk header mbuf and a cluster for the asconf params since - * it's simpler to fill in the asconf chunk header lookup address on - * the fly - */ - m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 0, M_NOWAIT, 1, MT_DATA); - if (m_asconf_chk == NULL) { - /* no mbuf's */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "sctp_compose_asconf: couldn't get chunk mbuf!\n"); - return (NULL); - } - m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (m_asconf == NULL) { - /* no mbuf's */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "sctp_compose_asconf: couldn't get mbuf!\n"); - sctp_m_freem(m_asconf_chk); - return (NULL); - } - SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk); - SCTP_BUF_LEN(m_asconf) = 0; - acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *); - memset(acp, 0, sizeof(struct sctp_asconf_chunk)); - /* save pointers to lookup address and asconf params */ - lookup_ptr = (caddr_t)(acp + 1); /* after the header */ - ptr = mtod(m_asconf, caddr_t); /* beginning of cluster */ - - /* fill in chunk header info */ - acp->ch.chunk_type = SCTP_ASCONF; - acp->ch.chunk_flags = 0; - acp->serial_number = htonl(stcb->asoc.asconf_seq_out); - stcb->asoc.asconf_seq_out++; - - /* add parameters... up to smallest MTU allowed */ - TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) { - if (aa->sent) - continue; - /* get the parameter length */ - p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length); - /* will it fit in current chunk? */ - if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu - overhead) || - (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) { - /* won't fit, so we're done with this chunk */ - break; - } - /* assign (and store) a correlation id */ - aa->ap.aph.correlation_id = correlation_id++; - - /* - * fill in address if we're doing a delete this is a simple - * way for us to fill in the correlation address, which - * should only be used by the peer if we're deleting our - * source address and adding a new address (e.g. renumbering - * case) - */ - if (lookup_used == 0 && - (aa->special_del == 0) && - aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) { - struct sctp_ipv6addr_param *lookup; - uint16_t p_size, addr_size; - - lookup = (struct sctp_ipv6addr_param *)lookup_ptr; - lookup->ph.param_type = - htons(aa->ap.addrp.ph.param_type); - if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) { - /* copy IPv6 address */ - p_size = sizeof(struct sctp_ipv6addr_param); - addr_size = sizeof(struct in6_addr); - } else { - /* copy IPv4 address */ - p_size = sizeof(struct sctp_ipv4addr_param); - addr_size = sizeof(struct in_addr); - } - lookup->ph.param_length = htons(SCTP_SIZE32(p_size)); - memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size); - SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size); - lookup_used = 1; - } - /* copy into current space */ - memcpy(ptr, &aa->ap, p_length); - - /* network elements and update lengths */ - aph = (struct sctp_asconf_paramhdr *)ptr; - aap = (struct sctp_asconf_addr_param *)ptr; - /* correlation_id is transparent to peer, no htonl needed */ - aph->ph.param_type = htons(aph->ph.param_type); - aph->ph.param_length = htons(aph->ph.param_length); - aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type); - aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length); - - SCTP_BUF_LEN(m_asconf) += SCTP_SIZE32(p_length); - ptr += SCTP_SIZE32(p_length); - - /* - * these params are removed off the pending list upon - * getting an ASCONF-ACK back from the peer, just set flag - */ - aa->sent = 1; - } - /* check to see if the lookup addr has been populated yet */ - if (lookup_used == 0) { - /* NOTE: if the address param is optional, can skip this... */ - /* add any valid (existing) address... */ - struct sctp_ipv6addr_param *lookup; - uint16_t p_size, addr_size; - struct sockaddr *found_addr; - caddr_t addr_ptr; - - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) - found_addr = sctp_find_valid_localaddr(stcb, - addr_locked); - else - found_addr = sctp_find_valid_localaddr_ep(stcb); - - lookup = (struct sctp_ipv6addr_param *)lookup_ptr; - if (found_addr != NULL) { - switch (found_addr->sa_family) { -#ifdef INET6 - case AF_INET6: - /* copy IPv6 address */ - lookup->ph.param_type = - htons(SCTP_IPV6_ADDRESS); - p_size = sizeof(struct sctp_ipv6addr_param); - addr_size = sizeof(struct in6_addr); - addr_ptr = (caddr_t)&((struct sockaddr_in6 *) - found_addr)->sin6_addr; - break; -#endif -#ifdef INET - case AF_INET: - /* copy IPv4 address */ - lookup->ph.param_type = - htons(SCTP_IPV4_ADDRESS); - p_size = sizeof(struct sctp_ipv4addr_param); - addr_size = sizeof(struct in_addr); - addr_ptr = (caddr_t)&((struct sockaddr_in *) - found_addr)->sin_addr; - break; -#endif - default: - SCTPDBG(SCTP_DEBUG_ASCONF1, - "sctp_compose_asconf: no usable lookup addr (family = %d)!\n", - found_addr->sa_family); - sctp_m_freem(m_asconf_chk); - sctp_m_freem(m_asconf); - return (NULL); - } - lookup->ph.param_length = htons(SCTP_SIZE32(p_size)); - memcpy(lookup->addr, addr_ptr, addr_size); - SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size); - } else { - /* uh oh... don't have any address?? */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "sctp_compose_asconf: no lookup addr!\n"); - sctp_m_freem(m_asconf_chk); - sctp_m_freem(m_asconf); - return (NULL); - } - } - /* chain it all together */ - SCTP_BUF_NEXT(m_asconf_chk) = m_asconf; - *retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf); - acp->ch.chunk_length = htons(*retlen); - - return (m_asconf_chk); -} - -/* - * section to handle address changes before an association is up eg. changes - * during INIT/INIT-ACK/COOKIE-ECHO handshake - */ - -/* - * processes the (local) addresses in the INIT-ACK chunk - */ -static void -sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, - unsigned int offset, unsigned int length) -{ - struct sctp_paramhdr tmp_param, *ph; - uint16_t plen, ptype; - struct sctp_ifa *sctp_ifa; - union sctp_sockstore store; -#ifdef INET6 - struct sctp_ipv6addr_param addr6_store; -#endif -#ifdef INET - struct sctp_ipv4addr_param addr4_store; -#endif - - SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n"); - if (stcb == NULL) /* Un-needed check for SA */ - return; - - /* convert to upper bound */ - length += offset; - - if ((offset + sizeof(struct sctp_paramhdr)) > length) { - return; - } - /* go through the addresses in the init-ack */ - ph = (struct sctp_paramhdr *) - sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), - (uint8_t *)&tmp_param); - while (ph != NULL) { - ptype = ntohs(ph->param_type); - plen = ntohs(ph->param_length); - switch (ptype) { -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - { - struct sctp_ipv6addr_param *a6p; - - /* get the entire IPv6 address param */ - a6p = (struct sctp_ipv6addr_param *) - sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv6addr_param), - (uint8_t *)&addr6_store); - if (plen != sizeof(struct sctp_ipv6addr_param) || - a6p == NULL) { - return; - } - memset(&store, 0, sizeof(union sctp_sockstore)); - store.sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - store.sin6.sin6_len = sizeof(struct sockaddr_in6); -#endif - store.sin6.sin6_port = stcb->rport; - memcpy(&store.sin6.sin6_addr, a6p->addr, sizeof(struct in6_addr)); - break; - } -#endif -#ifdef INET - case SCTP_IPV4_ADDRESS: - { - struct sctp_ipv4addr_param *a4p; - - /* get the entire IPv4 address param */ - a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv4addr_param), - (uint8_t *)&addr4_store); - if (plen != sizeof(struct sctp_ipv4addr_param) || - a4p == NULL) { - return; - } - memset(&store, 0, sizeof(union sctp_sockstore)); - store.sin.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - store.sin.sin_len = sizeof(struct sockaddr_in); -#endif - store.sin.sin_port = stcb->rport; - store.sin.sin_addr.s_addr = a4p->addr; - break; - } -#endif - default: - goto next_addr; - } - - /* see if this address really (still) exists */ - sctp_ifa = sctp_find_ifa_by_addr(&store.sa, stcb->asoc.vrf_id, - SCTP_ADDR_NOT_LOCKED); - if (sctp_ifa == NULL) { - /* address doesn't exist anymore */ - int status; - - /* are ASCONFs allowed ? */ - if ((sctp_is_feature_on(stcb->sctp_ep, - SCTP_PCB_FLAGS_DO_ASCONF)) && - stcb->asoc.asconf_supported) { - /* queue an ASCONF DEL_IP_ADDRESS */ - status = sctp_asconf_queue_sa_delete(stcb, &store.sa); - /* - * if queued ok, and in correct state, send - * out the ASCONF. - */ - if (status == 0 && - SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { -#ifdef SCTP_TIMER_BASED_ASCONF - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, - stcb->sctp_ep, stcb, - stcb->asoc.primary_destination); -#else - sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); -#endif - } - } - } - -next_addr: - /* - * Sanity check: Make sure the length isn't 0, otherwise - * we'll be stuck in this loop for a long time... - */ - if (SCTP_SIZE32(plen) == 0) { - SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n", - plen, ptype); - return; - } - /* get next parameter */ - offset += SCTP_SIZE32(plen); - if ((offset + sizeof(struct sctp_paramhdr)) > length) - return; - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, - sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param); - } /* while */ -} - -/* FIX ME: need to verify return result for v6 address type if v6 disabled */ -/* - * checks to see if a specific address is in the initack address list returns - * 1 if found, 0 if not - */ -static uint32_t -sctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa) -{ - struct sctp_paramhdr tmp_param, *ph; - uint16_t plen, ptype; -#ifdef INET - struct sockaddr_in *sin; - struct sctp_ipv4addr_param *a4p; - struct sctp_ipv6addr_param addr4_store; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; - struct sctp_ipv6addr_param *a6p; - struct sctp_ipv6addr_param addr6_store; -#ifdef SCTP_EMBEDDED_V6_SCOPE - struct sockaddr_in6 sin6_tmp; -#endif -#endif - - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - break; -#endif -#ifdef INET6 - case AF_INET6: - break; -#endif - default: - return (0); - } - - SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa); - /* convert to upper bound */ - length += offset; - - if ((offset + sizeof(struct sctp_paramhdr)) > length) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "find_initack_addr: invalid offset?\n"); - return (0); - } - /* go through the addresses in the init-ack */ - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, - sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param); - while (ph != NULL) { - ptype = ntohs(ph->param_type); - plen = ntohs(ph->param_length); - switch (ptype) { -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - if (sa->sa_family == AF_INET6) { - /* get the entire IPv6 address param */ - if (plen != sizeof(struct sctp_ipv6addr_param)) { - break; - } - /* get the entire IPv6 address param */ - a6p = (struct sctp_ipv6addr_param *) - sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv6addr_param), - (uint8_t *)&addr6_store); - if (a6p == NULL) { - return (0); - } - sin6 = (struct sockaddr_in6 *)sa; -#ifdef SCTP_EMBEDDED_V6_SCOPE - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { - /* create a copy and clear scope */ - memcpy(&sin6_tmp, sin6, - sizeof(struct sockaddr_in6)); - sin6 = &sin6_tmp; - in6_clearscope(&sin6->sin6_addr); - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - if (memcmp(&sin6->sin6_addr, a6p->addr, - sizeof(struct in6_addr)) == 0) { - /* found it */ - return (1); - } - } - break; -#endif /* INET6 */ -#ifdef INET - case SCTP_IPV4_ADDRESS: - if (sa->sa_family == AF_INET) { - if (plen != sizeof(struct sctp_ipv4addr_param)) { - break; - } - /* get the entire IPv4 address param */ - a4p = (struct sctp_ipv4addr_param *) - sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv4addr_param), - (uint8_t *)&addr4_store); - if (a4p == NULL) { - return (0); - } - sin = (struct sockaddr_in *)sa; - if (sin->sin_addr.s_addr == a4p->addr) { - /* found it */ - return (1); - } - } - break; -#endif - default: - break; - } - /* get next parameter */ - offset += SCTP_SIZE32(plen); - if (offset + sizeof(struct sctp_paramhdr) > length) { - return (0); - } - ph = (struct sctp_paramhdr *) - sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), - (uint8_t *) & tmp_param); - } /* while */ - /* not found! */ - return (0); -} - -/* - * makes sure that the current endpoint local addr list is consistent with - * the new association (eg. subset bound, asconf allowed) adds addresses as - * necessary - */ -static void -sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset, - int length, struct sockaddr *init_addr) -{ - struct sctp_laddr *laddr; - - /* go through the endpoint list */ - LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { - /* be paranoid and validate the laddr */ - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "check_addr_list_ep: laddr->ifa is NULL"); - continue; - } - /* do i have it implicitly? */ - if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) { - continue; - } - /* check to see if in the init-ack */ - if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) { - /* try to add it */ - sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa, - SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED); - } - } -} - -/* - * makes sure that the current kernel address list is consistent with the new - * association (with all addrs bound) adds addresses as necessary - */ -static void -sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, - int length, struct sockaddr *init_addr, - uint16_t local_scope, uint16_t site_scope, - uint16_t ipv4_scope, uint16_t loopback_scope) -{ - struct sctp_vrf *vrf = NULL; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - uint32_t vrf_id; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - - if (stcb) { - vrf_id = stcb->asoc.vrf_id; - } else { - return; - } - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - SCTP_IPI_ADDR_RUNLOCK(); - return; - } - /* go through all our known interfaces */ - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* skip loopback interface */ - continue; - } - /* go through each interface address */ - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - /* do i have it implicitly? */ - if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) { - continue; - } - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - sin = &sctp_ifa->address.sin; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if ((ipv4_scope == 0) && - (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { - /* private address not in scope */ - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - sin6 = &sctp_ifa->address.sin6; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if ((local_scope == 0) && - (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { - continue; - } - if ((site_scope == 0) && - (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - continue; - } - break; -#endif - default: - break; - } - /* check to see if in the init-ack */ - if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) { - /* try to add it */ - sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, - sctp_ifa, SCTP_ADD_IP_ADDRESS, - SCTP_ADDR_LOCKED); - } - } /* end foreach ifa */ - } /* end foreach ifn */ - SCTP_IPI_ADDR_RUNLOCK(); -} - -/* - * validates an init-ack chunk (from a cookie-echo) with current addresses - * adds addresses from the init-ack into our local address list, if needed - * queues asconf adds/deletes addresses as needed and makes appropriate list - * changes for source address selection m, offset: points to the start of the - * address list in an init-ack chunk length: total length of the address - * params only init_addr: address where my INIT-ACK was sent from - */ -void -sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset, - int length, struct sockaddr *init_addr, - uint16_t local_scope, uint16_t site_scope, - uint16_t ipv4_scope, uint16_t loopback_scope) -{ - /* process the local addresses in the initack */ - sctp_process_initack_addresses(stcb, m, offset, length); - - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* bound all case */ - sctp_check_address_list_all(stcb, m, offset, length, init_addr, - local_scope, site_scope, ipv4_scope, loopback_scope); - } else { - /* subset bound case */ - if (sctp_is_feature_on(stcb->sctp_ep, - SCTP_PCB_FLAGS_DO_ASCONF)) { - /* asconf's allowed */ - sctp_check_address_list_ep(stcb, m, offset, length, - init_addr); - } - /* else, no asconfs allowed, so what we sent is what we get */ - } -} - -/* - * sctp_bindx() support - */ -uint32_t -sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, - uint32_t type, uint32_t vrf_id) -{ - struct sctp_ifa *ifa; - struct sctp_laddr *laddr, *nladdr; - -#ifdef HAVE_SA_LEN - if (sa->sa_len == 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); - return (EINVAL); - } -#endif - if (type == SCTP_ADD_IP_ADDRESS) { - /* For an add the address MUST be on the system */ - ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); - } else if (type == SCTP_DEL_IP_ADDRESS) { - /* For a delete we need to find it in the inp */ - ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED); - } else { - ifa = NULL; - } - if (ifa != NULL) { - if (type == SCTP_ADD_IP_ADDRESS) { - sctp_add_local_addr_ep(inp, ifa, type); - } else if (type == SCTP_DEL_IP_ADDRESS) { - if (inp->laddr_count < 2) { - /* can't delete the last local address */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); - return (EINVAL); - } - LIST_FOREACH(laddr, &inp->sctp_addr_list, - sctp_nxt_addr) { - if (ifa == laddr->ifa) { - /* Mark in the delete */ - laddr->action = type; - } - } - } - if (LIST_EMPTY(&inp->sctp_asoc_list)) { - /* - * There is no need to start the iterator if - * the inp has no associations. - */ - if (type == SCTP_DEL_IP_ADDRESS) { - LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { - if (laddr->ifa == ifa) { - sctp_del_local_addr_ep(inp, ifa); - } - } - } - } else { - struct sctp_asconf_iterator *asc; - struct sctp_laddr *wi; - int ret; - - SCTP_MALLOC(asc, struct sctp_asconf_iterator *, - sizeof(struct sctp_asconf_iterator), - SCTP_M_ASC_IT); - if (asc == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM); - return (ENOMEM); - } - wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (wi == NULL) { - SCTP_FREE(asc, SCTP_M_ASC_IT); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM); - return (ENOMEM); - } - LIST_INIT(&asc->list_of_work); - asc->cnt = 1; - SCTP_INCR_LADDR_COUNT(); - wi->ifa = ifa; - wi->action = type; - atomic_add_int(&ifa->refcount, 1); - LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); - ret = sctp_initiate_iterator(sctp_asconf_iterator_ep, - sctp_asconf_iterator_stcb, - sctp_asconf_iterator_ep_end, - SCTP_PCB_ANY_FLAGS, - SCTP_PCB_ANY_FEATURES, - SCTP_ASOC_ANY_STATE, - (void *)asc, 0, - sctp_asconf_iterator_end, inp, 0); - if (ret) { - SCTP_PRINTF("Failed to initiate iterator for addr_mgmt_ep_sa\n"); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EFAULT); - sctp_asconf_iterator_end(asc, 0); - return (EFAULT); - } - } - return (0); - } else { - /* invalid address! */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL); - return (EADDRNOTAVAIL); - } -} - -void -sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - struct sctp_asconf_addr *aa_vtag, *aa_add, *aa_del; - struct sctp_ifa *sctp_ifap; - struct sctp_asconf_tag_param *vtag; -#ifdef INET - struct sockaddr_in *to; -#endif -#ifdef INET6 - struct sockaddr_in6 *to6; -#endif - - if (net == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n"); - return; - } - if (stcb == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n"); - return; - } - /* Need to have in the ASCONF: - * - VTAG(my_vtag/peer_vtag) - * - ADD(wildcard) - * - DEL(wildcard) - * - ADD(Any global addresses) - */ - SCTP_MALLOC(aa_vtag, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR); - SCTP_MALLOC(aa_add, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR); - SCTP_MALLOC(aa_del, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR); - - if ((aa_vtag == NULL) || (aa_add == NULL) || (aa_del == NULL)) { - /* Didn't get memory */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: failed to get memory!\n"); -out: - if (aa_vtag != NULL) { - SCTP_FREE(aa_vtag, SCTP_M_ASC_ADDR); - } - if (aa_add != NULL) { - SCTP_FREE(aa_add, SCTP_M_ASC_ADDR); - } - if (aa_del != NULL) { - SCTP_FREE(aa_del, SCTP_M_ASC_ADDR); - } - return; - } - memset(aa_vtag, 0, sizeof(struct sctp_asconf_addr)); - aa_vtag->special_del = 0; - /* Fill in ASCONF address parameter fields. */ - /* Top level elements are "networked" during send. */ - aa_vtag->ifa = NULL; - aa_vtag->sent = 0; /* clear sent flag */ - vtag = (struct sctp_asconf_tag_param *)&aa_vtag->ap.aph; - vtag->aph.ph.param_type = SCTP_NAT_VTAGS; - vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param); - vtag->local_vtag = htonl(stcb->asoc.my_vtag); - vtag->remote_vtag = htonl(stcb->asoc.peer_vtag); - - memset(aa_add, 0, sizeof(struct sctp_asconf_addr)); - memset(aa_del, 0, sizeof(struct sctp_asconf_addr)); - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; - aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param); - aa_add->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; - aa_add->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param); - /* No need to fill the address, we are using 0.0.0.0 */ - aa_del->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS; - aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param); - aa_del->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; - aa_del->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param); - /* No need to fill the address, we are using 0.0.0.0 */ - break; -#endif -#ifdef INET6 - case AF_INET6: - aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; - aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param); - aa_add->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; - aa_add->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param); - /* No need to fill the address, we are using ::0 */ - aa_del->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS; - aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param); - aa_del->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; - aa_del->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param); - /* No need to fill the address, we are using ::0 */ - break; -#endif - default: - SCTPDBG(SCTP_DEBUG_ASCONF1, - "sctp_asconf_send_nat_state_update: unknown address family %d\n", - net->ro._l_addr.sa.sa_family); - goto out; - } - TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_vtag, next); - TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_add, next); - TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_del, next); - - /* Now we must hunt the addresses and add all global addresses */ - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - struct sctp_vrf *vrf = NULL; - struct sctp_ifn *sctp_ifnp; - uint32_t vrf_id; - - vrf_id = stcb->sctp_ep->def_vrf_id; - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - goto skip_rest; - } - - SCTP_IPI_ADDR_RLOCK(); - LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { - LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { - switch (sctp_ifap->address.sa.sa_family) { -#ifdef INET - case AF_INET: - to = &sctp_ifap->address.sin; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, - &to->sin_addr) != 0) { - continue; - } -#endif - if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) { - continue; - } - if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - to6 = &sctp_ifap->address.sin6; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, - &to6->sin6_addr) != 0) { - continue; - } -#endif - if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { - continue; - } - if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { - continue; - } - break; -#endif - default: - continue; - } - sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS); - } - } - SCTP_IPI_ADDR_RUNLOCK(); - } else { - struct sctp_laddr *laddr; - - LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - continue; - } - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) - /* Address being deleted by the system, dont - * list. - */ - continue; - if (laddr->action == SCTP_DEL_IP_ADDRESS) { - /* Address being deleted on this ep - * don't list. - */ - continue; - } - sctp_ifap = laddr->ifa; - switch (sctp_ifap->address.sa.sa_family) { -#ifdef INET - case AF_INET: - to = &sctp_ifap->address.sin; - if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) { - continue; - } - if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - to6 = &sctp_ifap->address.sin6; - if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { - continue; - } - if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { - continue; - } - break; -#endif - default: - continue; - } - sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS); - } - } - skip_rest: - /* Now we must send the asconf into the queue */ - sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); -} diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.h deleted file mode 100644 index 318b26b1..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_asconf.h +++ /dev/null @@ -1,94 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_ASCONF_H_ -#define _NETINET_SCTP_ASCONF_H_ - -#if defined(_KERNEL) || defined(__Userspace__) - -/* - * function prototypes - */ -extern void sctp_asconf_cleanup(struct sctp_tcb *); - -extern struct mbuf *sctp_compose_asconf(struct sctp_tcb *, int *, int); - -extern void -sctp_handle_asconf(struct mbuf *, unsigned int, struct sockaddr *, - struct sctp_asconf_chunk *, struct sctp_tcb *, int); - -extern void -sctp_handle_asconf_ack(struct mbuf *, int, struct sctp_asconf_ack_chunk *, - struct sctp_tcb *, struct sctp_nets *, int *); - -extern uint32_t -sctp_addr_mgmt_ep_sa(struct sctp_inpcb *, struct sockaddr *, uint32_t, - uint32_t); - -extern int sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, - uint32_t val); -extern void sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - void *ptr, uint32_t type); -extern void sctp_asconf_iterator_end(void *ptr, uint32_t val); - -extern int32_t -sctp_set_primary_ip_address_sa(struct sctp_tcb *, - struct sockaddr *); - -extern void -sctp_check_address_list(struct sctp_tcb *, struct mbuf *, int, int, - struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t); - -extern void -sctp_assoc_immediate_retrans(struct sctp_tcb *, struct sctp_nets *); -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) -extern void -sctp_net_immediate_retrans(struct sctp_tcb *, struct sctp_nets *); -#endif - -extern void -sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, - struct sctp_nets *net); - -extern int -sctp_is_addr_pending(struct sctp_tcb *, struct sctp_ifa *); -#endif /* _KERNEL */ - -#endif /* !_NETINET_SCTP_ASCONF_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.c deleted file mode 100644 index 39a0f501..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.c +++ /dev/null @@ -1,2302 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef SCTP_DEBUG -#define SCTP_AUTH_DEBUG (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH1) -#define SCTP_AUTH_DEBUG2 (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH2) -#endif /* SCTP_DEBUG */ - -void -sctp_clear_chunklist(sctp_auth_chklist_t *chklist) -{ - memset(chklist, 0, sizeof(*chklist)); - /* chklist->num_chunks = 0; */ -} - -sctp_auth_chklist_t * -sctp_alloc_chunklist(void) -{ - sctp_auth_chklist_t *chklist; - - SCTP_MALLOC(chklist, sctp_auth_chklist_t *, sizeof(*chklist), - SCTP_M_AUTH_CL); - if (chklist == NULL) { - SCTPDBG(SCTP_DEBUG_AUTH1, "sctp_alloc_chunklist: failed to get memory!\n"); - } else { - sctp_clear_chunklist(chklist); - } - return (chklist); -} - -void -sctp_free_chunklist(sctp_auth_chklist_t *list) -{ - if (list != NULL) - SCTP_FREE(list, SCTP_M_AUTH_CL); -} - -sctp_auth_chklist_t * -sctp_copy_chunklist(sctp_auth_chklist_t *list) -{ - sctp_auth_chklist_t *new_list; - - if (list == NULL) - return (NULL); - - /* get a new list */ - new_list = sctp_alloc_chunklist(); - if (new_list == NULL) - return (NULL); - /* copy it */ - memcpy(new_list, list, sizeof(*new_list)); - - return (new_list); -} - -/* - * add a chunk to the required chunks list - */ -int -sctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t *list) -{ - if (list == NULL) - return (-1); - - /* is chunk restricted? */ - if ((chunk == SCTP_INITIATION) || - (chunk == SCTP_INITIATION_ACK) || - (chunk == SCTP_SHUTDOWN_COMPLETE) || - (chunk == SCTP_AUTHENTICATION)) { - return (-1); - } - if (list->chunks[chunk] == 0) { - list->chunks[chunk] = 1; - list->num_chunks++; - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: added chunk %u (0x%02x) to Auth list\n", - chunk, chunk); - } - return (0); -} - -/* - * delete a chunk from the required chunks list - */ -int -sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t *list) -{ - if (list == NULL) - return (-1); - - if (list->chunks[chunk] == 1) { - list->chunks[chunk] = 0; - list->num_chunks--; - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: deleted chunk %u (0x%02x) from Auth list\n", - chunk, chunk); - } - return (0); -} - -size_t -sctp_auth_get_chklist_size(const sctp_auth_chklist_t *list) -{ - if (list == NULL) - return (0); - else - return (list->num_chunks); -} - -/* - * return the current number and list of required chunks caller must - * guarantee ptr has space for up to 256 bytes - */ -int -sctp_serialize_auth_chunks(const sctp_auth_chklist_t *list, uint8_t *ptr) -{ - int i, count = 0; - - if (list == NULL) - return (0); - - for (i = 0; i < 256; i++) { - if (list->chunks[i] != 0) { - *ptr++ = i; - count++; - } - } - return (count); -} - -int -sctp_pack_auth_chunks(const sctp_auth_chklist_t *list, uint8_t *ptr) -{ - int i, size = 0; - - if (list == NULL) - return (0); - - if (list->num_chunks <= 32) { - /* just list them, one byte each */ - for (i = 0; i < 256; i++) { - if (list->chunks[i] != 0) { - *ptr++ = i; - size++; - } - } - } else { - int index, offset; - - /* pack into a 32 byte bitfield */ - for (i = 0; i < 256; i++) { - if (list->chunks[i] != 0) { - index = i / 8; - offset = i % 8; - ptr[index] |= (1 << offset); - } - } - size = 32; - } - return (size); -} - -int -sctp_unpack_auth_chunks(const uint8_t *ptr, uint8_t num_chunks, - sctp_auth_chklist_t *list) -{ - int i; - int size; - - if (list == NULL) - return (0); - - if (num_chunks <= 32) { - /* just pull them, one byte each */ - for (i = 0; i < num_chunks; i++) { - (void)sctp_auth_add_chunk(*ptr++, list); - } - size = num_chunks; - } else { - int index, offset; - - /* unpack from a 32 byte bitfield */ - for (index = 0; index < 32; index++) { - for (offset = 0; offset < 8; offset++) { - if (ptr[index] & (1 << offset)) { - (void)sctp_auth_add_chunk((index * 8) + offset, list); - } - } - } - size = 32; - } - return (size); -} - -/* - * allocate structure space for a key of length keylen - */ -sctp_key_t * -sctp_alloc_key(uint32_t keylen) -{ - sctp_key_t *new_key; - - SCTP_MALLOC(new_key, sctp_key_t *, sizeof(*new_key) + keylen, - SCTP_M_AUTH_KY); - if (new_key == NULL) { - /* out of memory */ - return (NULL); - } - new_key->keylen = keylen; - return (new_key); -} - -void -sctp_free_key(sctp_key_t *key) -{ - if (key != NULL) - SCTP_FREE(key,SCTP_M_AUTH_KY); -} - -void -sctp_print_key(sctp_key_t *key, const char *str) -{ - uint32_t i; - - if (key == NULL) { - SCTP_PRINTF("%s: [Null key]\n", str); - return; - } - SCTP_PRINTF("%s: len %u, ", str, key->keylen); - if (key->keylen) { - for (i = 0; i < key->keylen; i++) - SCTP_PRINTF("%02x", key->key[i]); - SCTP_PRINTF("\n"); - } else { - SCTP_PRINTF("[Null key]\n"); - } -} - -void -sctp_show_key(sctp_key_t *key, const char *str) -{ - uint32_t i; - - if (key == NULL) { - SCTP_PRINTF("%s: [Null key]\n", str); - return; - } - SCTP_PRINTF("%s: len %u, ", str, key->keylen); - if (key->keylen) { - for (i = 0; i < key->keylen; i++) - SCTP_PRINTF("%02x", key->key[i]); - SCTP_PRINTF("\n"); - } else { - SCTP_PRINTF("[Null key]\n"); - } -} - -static uint32_t -sctp_get_keylen(sctp_key_t *key) -{ - if (key != NULL) - return (key->keylen); - else - return (0); -} - -/* - * generate a new random key of length 'keylen' - */ -sctp_key_t * -sctp_generate_random_key(uint32_t keylen) -{ - sctp_key_t *new_key; - - new_key = sctp_alloc_key(keylen); - if (new_key == NULL) { - /* out of memory */ - return (NULL); - } - SCTP_READ_RANDOM(new_key->key, keylen); - new_key->keylen = keylen; - return (new_key); -} - -sctp_key_t * -sctp_set_key(uint8_t *key, uint32_t keylen) -{ - sctp_key_t *new_key; - - new_key = sctp_alloc_key(keylen); - if (new_key == NULL) { - /* out of memory */ - return (NULL); - } - memcpy(new_key->key, key, keylen); - return (new_key); -} - -/*- - * given two keys of variable size, compute which key is "larger/smaller" - * returns: 1 if key1 > key2 - * -1 if key1 < key2 - * 0 if key1 = key2 - */ -static int -sctp_compare_key(sctp_key_t *key1, sctp_key_t *key2) -{ - uint32_t maxlen; - uint32_t i; - uint32_t key1len, key2len; - uint8_t *key_1, *key_2; - uint8_t val1, val2; - - /* sanity/length check */ - key1len = sctp_get_keylen(key1); - key2len = sctp_get_keylen(key2); - if ((key1len == 0) && (key2len == 0)) - return (0); - else if (key1len == 0) - return (-1); - else if (key2len == 0) - return (1); - - if (key1len < key2len) { - maxlen = key2len; - } else { - maxlen = key1len; - } - key_1 = key1->key; - key_2 = key2->key; - /* check for numeric equality */ - for (i = 0; i < maxlen; i++) { - /* left-pad with zeros */ - val1 = (i < (maxlen - key1len)) ? 0 : *(key_1++); - val2 = (i < (maxlen - key2len)) ? 0 : *(key_2++); - if (val1 > val2) { - return (1); - } else if (val1 < val2) { - return (-1); - } - } - /* keys are equal value, so check lengths */ - if (key1len == key2len) - return (0); - else if (key1len < key2len) - return (-1); - else - return (1); -} - -/* - * generate the concatenated keying material based on the two keys and the - * shared key (if available). draft-ietf-tsvwg-auth specifies the specific - * order for concatenation - */ -sctp_key_t * -sctp_compute_hashkey(sctp_key_t *key1, sctp_key_t *key2, sctp_key_t *shared) -{ - uint32_t keylen; - sctp_key_t *new_key; - uint8_t *key_ptr; - - keylen = sctp_get_keylen(key1) + sctp_get_keylen(key2) + - sctp_get_keylen(shared); - - if (keylen > 0) { - /* get space for the new key */ - new_key = sctp_alloc_key(keylen); - if (new_key == NULL) { - /* out of memory */ - return (NULL); - } - new_key->keylen = keylen; - key_ptr = new_key->key; - } else { - /* all keys empty/null?! */ - return (NULL); - } - - /* concatenate the keys */ - if (sctp_compare_key(key1, key2) <= 0) { - /* key is shared + key1 + key2 */ - if (sctp_get_keylen(shared)) { - memcpy(key_ptr, shared->key, shared->keylen); - key_ptr += shared->keylen; - } - if (sctp_get_keylen(key1)) { - memcpy(key_ptr, key1->key, key1->keylen); - key_ptr += key1->keylen; - } - if (sctp_get_keylen(key2)) { - memcpy(key_ptr, key2->key, key2->keylen); - } - } else { - /* key is shared + key2 + key1 */ - if (sctp_get_keylen(shared)) { - memcpy(key_ptr, shared->key, shared->keylen); - key_ptr += shared->keylen; - } - if (sctp_get_keylen(key2)) { - memcpy(key_ptr, key2->key, key2->keylen); - key_ptr += key2->keylen; - } - if (sctp_get_keylen(key1)) { - memcpy(key_ptr, key1->key, key1->keylen); - } - } - return (new_key); -} - -sctp_sharedkey_t * -sctp_alloc_sharedkey(void) -{ - sctp_sharedkey_t *new_key; - - SCTP_MALLOC(new_key, sctp_sharedkey_t *, sizeof(*new_key), - SCTP_M_AUTH_KY); - if (new_key == NULL) { - /* out of memory */ - return (NULL); - } - new_key->keyid = 0; - new_key->key = NULL; - new_key->refcount = 1; - new_key->deactivated = 0; - return (new_key); -} - -void -sctp_free_sharedkey(sctp_sharedkey_t *skey) -{ - if (skey == NULL) - return; - - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&skey->refcount)) { - if (skey->key != NULL) - sctp_free_key(skey->key); - SCTP_FREE(skey, SCTP_M_AUTH_KY); - } -} - -sctp_sharedkey_t * -sctp_find_sharedkey(struct sctp_keyhead *shared_keys, uint16_t key_id) -{ - sctp_sharedkey_t *skey; - - LIST_FOREACH(skey, shared_keys, next) { - if (skey->keyid == key_id) - return (skey); - } - return (NULL); -} - -int -sctp_insert_sharedkey(struct sctp_keyhead *shared_keys, - sctp_sharedkey_t *new_skey) -{ - sctp_sharedkey_t *skey; - - if ((shared_keys == NULL) || (new_skey == NULL)) - return (EINVAL); - - /* insert into an empty list? */ - if (LIST_EMPTY(shared_keys)) { - LIST_INSERT_HEAD(shared_keys, new_skey, next); - return (0); - } - /* insert into the existing list, ordered by key id */ - LIST_FOREACH(skey, shared_keys, next) { - if (new_skey->keyid < skey->keyid) { - /* insert it before here */ - LIST_INSERT_BEFORE(skey, new_skey, next); - return (0); - } else if (new_skey->keyid == skey->keyid) { - /* replace the existing key */ - /* verify this key *can* be replaced */ - if ((skey->deactivated) || (skey->refcount > 1)) { - SCTPDBG(SCTP_DEBUG_AUTH1, - "can't replace shared key id %u\n", - new_skey->keyid); - return (EBUSY); - } - SCTPDBG(SCTP_DEBUG_AUTH1, - "replacing shared key id %u\n", - new_skey->keyid); - LIST_INSERT_BEFORE(skey, new_skey, next); - LIST_REMOVE(skey, next); - sctp_free_sharedkey(skey); - return (0); - } - if (LIST_NEXT(skey, next) == NULL) { - /* belongs at the end of the list */ - LIST_INSERT_AFTER(skey, new_skey, next); - return (0); - } - } - /* shouldn't reach here */ - return (EINVAL); -} - -void -sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t key_id) -{ - sctp_sharedkey_t *skey; - - /* find the shared key */ - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id); - - /* bump the ref count */ - if (skey) { - atomic_add_int(&skey->refcount, 1); - SCTPDBG(SCTP_DEBUG_AUTH2, - "%s: stcb %p key %u refcount acquire to %d\n", - __func__, (void *)stcb, key_id, skey->refcount); - } -} - -void -sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked) -{ - sctp_sharedkey_t *skey; - - /* find the shared key */ - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id); - - /* decrement the ref count */ - if (skey) { - SCTPDBG(SCTP_DEBUG_AUTH2, - "%s: stcb %p key %u refcount release to %d\n", - __func__, (void *)stcb, key_id, skey->refcount); - - /* see if a notification should be generated */ - if ((skey->refcount <= 2) && (skey->deactivated)) { - /* notify ULP that key is no longer used */ - sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, - key_id, 0, so_locked); - SCTPDBG(SCTP_DEBUG_AUTH2, - "%s: stcb %p key %u no longer used, %d\n", - __func__, (void *)stcb, key_id, skey->refcount); - } - sctp_free_sharedkey(skey); - } -} - -static sctp_sharedkey_t * -sctp_copy_sharedkey(const sctp_sharedkey_t *skey) -{ - sctp_sharedkey_t *new_skey; - - if (skey == NULL) - return (NULL); - new_skey = sctp_alloc_sharedkey(); - if (new_skey == NULL) - return (NULL); - if (skey->key != NULL) - new_skey->key = sctp_set_key(skey->key->key, skey->key->keylen); - else - new_skey->key = NULL; - new_skey->keyid = skey->keyid; - return (new_skey); -} - -int -sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest) -{ - sctp_sharedkey_t *skey, *new_skey; - int count = 0; - - if ((src == NULL) || (dest == NULL)) - return (0); - LIST_FOREACH(skey, src, next) { - new_skey = sctp_copy_sharedkey(skey); - if (new_skey != NULL) { - if (sctp_insert_sharedkey(dest, new_skey)) { - sctp_free_sharedkey(new_skey); - } else { - count++; - } - } - } - return (count); -} - -sctp_hmaclist_t * -sctp_alloc_hmaclist(uint16_t num_hmacs) -{ - sctp_hmaclist_t *new_list; - int alloc_size; - - alloc_size = sizeof(*new_list) + num_hmacs * sizeof(new_list->hmac[0]); - SCTP_MALLOC(new_list, sctp_hmaclist_t *, alloc_size, - SCTP_M_AUTH_HL); - if (new_list == NULL) { - /* out of memory */ - return (NULL); - } - new_list->max_algo = num_hmacs; - new_list->num_algo = 0; - return (new_list); -} - -void -sctp_free_hmaclist(sctp_hmaclist_t *list) -{ - if (list != NULL) { - SCTP_FREE(list,SCTP_M_AUTH_HL); - } -} - -int -sctp_auth_add_hmacid(sctp_hmaclist_t *list, uint16_t hmac_id) -{ - int i; - if (list == NULL) - return (-1); - if (list->num_algo == list->max_algo) { - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: HMAC id list full, ignoring add %u\n", hmac_id); - return (-1); - } -#if defined(SCTP_SUPPORT_HMAC_SHA256) - if ((hmac_id != SCTP_AUTH_HMAC_ID_SHA1) && - (hmac_id != SCTP_AUTH_HMAC_ID_SHA256)) { -#else - if (hmac_id != SCTP_AUTH_HMAC_ID_SHA1) { -#endif - return (-1); - } - /* Now is it already in the list */ - for (i = 0; i < list->num_algo; i++) { - if (list->hmac[i] == hmac_id) { - /* already in list */ - return (-1); - } - } - SCTPDBG(SCTP_DEBUG_AUTH1, "SCTP: add HMAC id %u to list\n", hmac_id); - list->hmac[list->num_algo++] = hmac_id; - return (0); -} - -sctp_hmaclist_t * -sctp_copy_hmaclist(sctp_hmaclist_t *list) -{ - sctp_hmaclist_t *new_list; - int i; - - if (list == NULL) - return (NULL); - /* get a new list */ - new_list = sctp_alloc_hmaclist(list->max_algo); - if (new_list == NULL) - return (NULL); - /* copy it */ - new_list->max_algo = list->max_algo; - new_list->num_algo = list->num_algo; - for (i = 0; i < list->num_algo; i++) - new_list->hmac[i] = list->hmac[i]; - return (new_list); -} - -sctp_hmaclist_t * -sctp_default_supported_hmaclist(void) -{ - sctp_hmaclist_t *new_list; - -#if defined(SCTP_SUPPORT_HMAC_SHA256) - new_list = sctp_alloc_hmaclist(2); -#else - new_list = sctp_alloc_hmaclist(1); -#endif - if (new_list == NULL) - return (NULL); -#if defined(SCTP_SUPPORT_HMAC_SHA256) - /* We prefer SHA256, so list it first */ - (void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA256); -#endif - (void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA1); - return (new_list); -} - -/*- - * HMAC algos are listed in priority/preference order - * find the best HMAC id to use for the peer based on local support - */ -uint16_t -sctp_negotiate_hmacid(sctp_hmaclist_t *peer, sctp_hmaclist_t *local) -{ - int i, j; - - if ((local == NULL) || (peer == NULL)) - return (SCTP_AUTH_HMAC_ID_RSVD); - - for (i = 0; i < peer->num_algo; i++) { - for (j = 0; j < local->num_algo; j++) { - if (peer->hmac[i] == local->hmac[j]) { - /* found the "best" one */ - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: negotiated peer HMAC id %u\n", - peer->hmac[i]); - return (peer->hmac[i]); - } - } - } - /* didn't find one! */ - return (SCTP_AUTH_HMAC_ID_RSVD); -} - -/*- - * serialize the HMAC algo list and return space used - * caller must guarantee ptr has appropriate space - */ -int -sctp_serialize_hmaclist(sctp_hmaclist_t *list, uint8_t *ptr) -{ - int i; - uint16_t hmac_id; - - if (list == NULL) - return (0); - - for (i = 0; i < list->num_algo; i++) { - hmac_id = htons(list->hmac[i]); - memcpy(ptr, &hmac_id, sizeof(hmac_id)); - ptr += sizeof(hmac_id); - } - return (list->num_algo * sizeof(hmac_id)); -} - -int -sctp_verify_hmac_param (struct sctp_auth_hmac_algo *hmacs, uint32_t num_hmacs) -{ - uint32_t i; - - for (i = 0; i < num_hmacs; i++) { - if (ntohs(hmacs->hmac_ids[i]) == SCTP_AUTH_HMAC_ID_SHA1) { - return (0); - } - } - return (-1); -} - -sctp_authinfo_t * -sctp_alloc_authinfo(void) -{ - sctp_authinfo_t *new_authinfo; - - SCTP_MALLOC(new_authinfo, sctp_authinfo_t *, sizeof(*new_authinfo), - SCTP_M_AUTH_IF); - - if (new_authinfo == NULL) { - /* out of memory */ - return (NULL); - } - memset(new_authinfo, 0, sizeof(*new_authinfo)); - return (new_authinfo); -} - -void -sctp_free_authinfo(sctp_authinfo_t *authinfo) -{ - if (authinfo == NULL) - return; - - if (authinfo->random != NULL) - sctp_free_key(authinfo->random); - if (authinfo->peer_random != NULL) - sctp_free_key(authinfo->peer_random); - if (authinfo->assoc_key != NULL) - sctp_free_key(authinfo->assoc_key); - if (authinfo->recv_key != NULL) - sctp_free_key(authinfo->recv_key); - - /* We are NOT dynamically allocating authinfo's right now... */ - /* SCTP_FREE(authinfo, SCTP_M_AUTH_??); */ -} - -uint32_t -sctp_get_auth_chunk_len(uint16_t hmac_algo) -{ - int size; - - size = sizeof(struct sctp_auth_chunk) + sctp_get_hmac_digest_len(hmac_algo); - return (SCTP_SIZE32(size)); -} - -uint32_t -sctp_get_hmac_digest_len(uint16_t hmac_algo) -{ - switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: - return (SCTP_AUTH_DIGEST_LEN_SHA1); -#if defined(SCTP_SUPPORT_HMAC_SHA256) - case SCTP_AUTH_HMAC_ID_SHA256: - return (SCTP_AUTH_DIGEST_LEN_SHA256); -#endif - default: - /* unknown HMAC algorithm: can't do anything */ - return (0); - } /* end switch */ -} - -static inline int -sctp_get_hmac_block_len(uint16_t hmac_algo) -{ - switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: - return (64); -#if defined(SCTP_SUPPORT_HMAC_SHA256) - case SCTP_AUTH_HMAC_ID_SHA256: - return (64); -#endif - case SCTP_AUTH_HMAC_ID_RSVD: - default: - /* unknown HMAC algorithm: can't do anything */ - return (0); - } /* end switch */ -} - -#if defined(__Userspace__) -/* __Userspace__ SHA1_Init is defined in libcrypto.a (libssl-dev on Ubuntu) */ -#endif -static void -sctp_hmac_init(uint16_t hmac_algo, sctp_hash_context_t *ctx) -{ - switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: - SCTP_SHA1_INIT(&ctx->sha1); - break; -#if defined(SCTP_SUPPORT_HMAC_SHA256) - case SCTP_AUTH_HMAC_ID_SHA256: - SCTP_SHA256_INIT(&ctx->sha256); - break; -#endif - case SCTP_AUTH_HMAC_ID_RSVD: - default: - /* unknown HMAC algorithm: can't do anything */ - return; - } /* end switch */ -} - -static void -sctp_hmac_update(uint16_t hmac_algo, sctp_hash_context_t *ctx, - uint8_t *text, uint32_t textlen) -{ - switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: - SCTP_SHA1_UPDATE(&ctx->sha1, text, textlen); - break; -#if defined(SCTP_SUPPORT_HMAC_SHA256) - case SCTP_AUTH_HMAC_ID_SHA256: - SCTP_SHA256_UPDATE(&ctx->sha256, text, textlen); - break; -#endif - case SCTP_AUTH_HMAC_ID_RSVD: - default: - /* unknown HMAC algorithm: can't do anything */ - return; - } /* end switch */ -} - -static void -sctp_hmac_final(uint16_t hmac_algo, sctp_hash_context_t *ctx, - uint8_t *digest) -{ - switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: - SCTP_SHA1_FINAL(digest, &ctx->sha1); - break; -#if defined(SCTP_SUPPORT_HMAC_SHA256) - case SCTP_AUTH_HMAC_ID_SHA256: - SCTP_SHA256_FINAL(digest, &ctx->sha256); - break; -#endif - case SCTP_AUTH_HMAC_ID_RSVD: - default: - /* unknown HMAC algorithm: can't do anything */ - return; - } /* end switch */ -} - -/*- - * Keyed-Hashing for Message Authentication: FIPS 198 (RFC 2104) - * - * Compute the HMAC digest using the desired hash key, text, and HMAC - * algorithm. Resulting digest is placed in 'digest' and digest length - * is returned, if the HMAC was performed. - * - * WARNING: it is up to the caller to supply sufficient space to hold the - * resultant digest. - */ -uint32_t -sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, - uint8_t *text, uint32_t textlen, uint8_t *digest) -{ - uint32_t digestlen; - uint32_t blocklen; - sctp_hash_context_t ctx; - uint8_t ipad[128], opad[128]; /* keyed hash inner/outer pads */ - uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; - uint32_t i; - - /* sanity check the material and length */ - if ((key == NULL) || (keylen == 0) || (text == NULL) || - (textlen == 0) || (digest == NULL)) { - /* can't do HMAC with empty key or text or digest store */ - return (0); - } - /* validate the hmac algo and get the digest length */ - digestlen = sctp_get_hmac_digest_len(hmac_algo); - if (digestlen == 0) - return (0); - - /* hash the key if it is longer than the hash block size */ - blocklen = sctp_get_hmac_block_len(hmac_algo); - if (keylen > blocklen) { - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, key, keylen); - sctp_hmac_final(hmac_algo, &ctx, temp); - /* set the hashed key as the key */ - keylen = digestlen; - key = temp; - } - /* initialize the inner/outer pads with the key and "append" zeroes */ - memset(ipad, 0, blocklen); - memset(opad, 0, blocklen); - memcpy(ipad, key, keylen); - memcpy(opad, key, keylen); - - /* XOR the key with ipad and opad values */ - for (i = 0; i < blocklen; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - /* perform inner hash */ - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen); - sctp_hmac_update(hmac_algo, &ctx, text, textlen); - sctp_hmac_final(hmac_algo, &ctx, temp); - - /* perform outer hash */ - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, opad, blocklen); - sctp_hmac_update(hmac_algo, &ctx, temp, digestlen); - sctp_hmac_final(hmac_algo, &ctx, digest); - - return (digestlen); -} - -/* mbuf version */ -uint32_t -sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, - struct mbuf *m, uint32_t m_offset, uint8_t *digest, uint32_t trailer) -{ - uint32_t digestlen; - uint32_t blocklen; - sctp_hash_context_t ctx; - uint8_t ipad[128], opad[128]; /* keyed hash inner/outer pads */ - uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; - uint32_t i; - struct mbuf *m_tmp; - - /* sanity check the material and length */ - if ((key == NULL) || (keylen == 0) || (m == NULL) || (digest == NULL)) { - /* can't do HMAC with empty key or text or digest store */ - return (0); - } - /* validate the hmac algo and get the digest length */ - digestlen = sctp_get_hmac_digest_len(hmac_algo); - if (digestlen == 0) - return (0); - - /* hash the key if it is longer than the hash block size */ - blocklen = sctp_get_hmac_block_len(hmac_algo); - if (keylen > blocklen) { - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, key, keylen); - sctp_hmac_final(hmac_algo, &ctx, temp); - /* set the hashed key as the key */ - keylen = digestlen; - key = temp; - } - /* initialize the inner/outer pads with the key and "append" zeroes */ - memset(ipad, 0, blocklen); - memset(opad, 0, blocklen); - memcpy(ipad, key, keylen); - memcpy(opad, key, keylen); - - /* XOR the key with ipad and opad values */ - for (i = 0; i < blocklen; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - /* perform inner hash */ - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen); - /* find the correct starting mbuf and offset (get start of text) */ - m_tmp = m; - while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) { - m_offset -= SCTP_BUF_LEN(m_tmp); - m_tmp = SCTP_BUF_NEXT(m_tmp); - } - /* now use the rest of the mbuf chain for the text */ - while (m_tmp != NULL) { - if ((SCTP_BUF_NEXT(m_tmp) == NULL) && trailer) { - sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset, - SCTP_BUF_LEN(m_tmp) - (trailer+m_offset)); - } else { - sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset, - SCTP_BUF_LEN(m_tmp) - m_offset); - } - - /* clear the offset since it's only for the first mbuf */ - m_offset = 0; - m_tmp = SCTP_BUF_NEXT(m_tmp); - } - sctp_hmac_final(hmac_algo, &ctx, temp); - - /* perform outer hash */ - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, opad, blocklen); - sctp_hmac_update(hmac_algo, &ctx, temp, digestlen); - sctp_hmac_final(hmac_algo, &ctx, digest); - - return (digestlen); -} - -/* - * computes the requested HMAC using a key struct (which may be modified if - * the keylen exceeds the HMAC block len). - */ -uint32_t -sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key, uint8_t *text, - uint32_t textlen, uint8_t *digest) -{ - uint32_t digestlen; - uint32_t blocklen; - sctp_hash_context_t ctx; - uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; - - /* sanity check */ - if ((key == NULL) || (text == NULL) || (textlen == 0) || - (digest == NULL)) { - /* can't do HMAC with empty key or text or digest store */ - return (0); - } - /* validate the hmac algo and get the digest length */ - digestlen = sctp_get_hmac_digest_len(hmac_algo); - if (digestlen == 0) - return (0); - - /* hash the key if it is longer than the hash block size */ - blocklen = sctp_get_hmac_block_len(hmac_algo); - if (key->keylen > blocklen) { - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen); - sctp_hmac_final(hmac_algo, &ctx, temp); - /* save the hashed key as the new key */ - key->keylen = digestlen; - memcpy(key->key, temp, key->keylen); - } - return (sctp_hmac(hmac_algo, key->key, key->keylen, text, textlen, - digest)); -} - -/* mbuf version */ -uint32_t -sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t *key, struct mbuf *m, - uint32_t m_offset, uint8_t *digest) -{ - uint32_t digestlen; - uint32_t blocklen; - sctp_hash_context_t ctx; - uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; - - /* sanity check */ - if ((key == NULL) || (m == NULL) || (digest == NULL)) { - /* can't do HMAC with empty key or text or digest store */ - return (0); - } - /* validate the hmac algo and get the digest length */ - digestlen = sctp_get_hmac_digest_len(hmac_algo); - if (digestlen == 0) - return (0); - - /* hash the key if it is longer than the hash block size */ - blocklen = sctp_get_hmac_block_len(hmac_algo); - if (key->keylen > blocklen) { - sctp_hmac_init(hmac_algo, &ctx); - sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen); - sctp_hmac_final(hmac_algo, &ctx, temp); - /* save the hashed key as the new key */ - key->keylen = digestlen; - memcpy(key->key, temp, key->keylen); - } - return (sctp_hmac_m(hmac_algo, key->key, key->keylen, m, m_offset, digest, 0)); -} - -int -sctp_auth_is_supported_hmac(sctp_hmaclist_t *list, uint16_t id) -{ - int i; - - if ((list == NULL) || (id == SCTP_AUTH_HMAC_ID_RSVD)) - return (0); - - for (i = 0; i < list->num_algo; i++) - if (list->hmac[i] == id) - return (1); - - /* not in the list */ - return (0); -} - -/*- - * clear any cached key(s) if they match the given key id on an association. - * the cached key(s) will be recomputed and re-cached at next use. - * ASSUMES TCB_LOCK is already held - */ -void -sctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid) -{ - if (stcb == NULL) - return; - - if (keyid == stcb->asoc.authinfo.assoc_keyid) { - sctp_free_key(stcb->asoc.authinfo.assoc_key); - stcb->asoc.authinfo.assoc_key = NULL; - } - if (keyid == stcb->asoc.authinfo.recv_keyid) { - sctp_free_key(stcb->asoc.authinfo.recv_key); - stcb->asoc.authinfo.recv_key = NULL; - } -} - -/*- - * clear any cached key(s) if they match the given key id for all assocs on - * an endpoint. - * ASSUMES INP_WLOCK is already held - */ -void -sctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid) -{ - struct sctp_tcb *stcb; - - if (inp == NULL) - return; - - /* clear the cached keys on all assocs on this instance */ - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - sctp_clear_cachedkeys(stcb, keyid); - SCTP_TCB_UNLOCK(stcb); - } -} - -/*- - * delete a shared key from an association - * ASSUMES TCB_LOCK is already held - */ -int -sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid) -{ - sctp_sharedkey_t *skey; - - if (stcb == NULL) - return (-1); - - /* is the keyid the assoc active sending key */ - if (keyid == stcb->asoc.authinfo.active_keyid) - return (-1); - - /* does the key exist? */ - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); - if (skey == NULL) - return (-1); - - /* are there other refcount holders on the key? */ - if (skey->refcount > 1) - return (-1); - - /* remove it */ - LIST_REMOVE(skey, next); - sctp_free_sharedkey(skey); /* frees skey->key as well */ - - /* clear any cached keys */ - sctp_clear_cachedkeys(stcb, keyid); - return (0); -} - -/*- - * deletes a shared key from the endpoint - * ASSUMES INP_WLOCK is already held - */ -int -sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid) -{ - sctp_sharedkey_t *skey; - - if (inp == NULL) - return (-1); - - /* is the keyid the active sending key on the endpoint */ - if (keyid == inp->sctp_ep.default_keyid) - return (-1); - - /* does the key exist? */ - skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid); - if (skey == NULL) - return (-1); - - /* endpoint keys are not refcounted */ - - /* remove it */ - LIST_REMOVE(skey, next); - sctp_free_sharedkey(skey); /* frees skey->key as well */ - - /* clear any cached keys */ - sctp_clear_cachedkeys_ep(inp, keyid); - return (0); -} - -/*- - * set the active key on an association - * ASSUMES TCB_LOCK is already held - */ -int -sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid) -{ - sctp_sharedkey_t *skey = NULL; - - /* find the key on the assoc */ - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); - if (skey == NULL) { - /* that key doesn't exist */ - return (-1); - } - if ((skey->deactivated) && (skey->refcount > 1)) { - /* can't reactivate a deactivated key with other refcounts */ - return (-1); - } - - /* set the (new) active key */ - stcb->asoc.authinfo.active_keyid = keyid; - /* reset the deactivated flag */ - skey->deactivated = 0; - - return (0); -} - -/*- - * set the active key on an endpoint - * ASSUMES INP_WLOCK is already held - */ -int -sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid) -{ - sctp_sharedkey_t *skey; - - /* find the key */ - skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid); - if (skey == NULL) { - /* that key doesn't exist */ - return (-1); - } - inp->sctp_ep.default_keyid = keyid; - return (0); -} - -/*- - * deactivates a shared key from the association - * ASSUMES INP_WLOCK is already held - */ -int -sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid) -{ - sctp_sharedkey_t *skey; - - if (stcb == NULL) - return (-1); - - /* is the keyid the assoc active sending key */ - if (keyid == stcb->asoc.authinfo.active_keyid) - return (-1); - - /* does the key exist? */ - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); - if (skey == NULL) - return (-1); - - /* are there other refcount holders on the key? */ - if (skey->refcount == 1) { - /* no other users, send a notification for this key */ - sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, keyid, 0, - SCTP_SO_LOCKED); - } - - /* mark the key as deactivated */ - skey->deactivated = 1; - - return (0); -} - -/*- - * deactivates a shared key from the endpoint - * ASSUMES INP_WLOCK is already held - */ -int -sctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid) -{ - sctp_sharedkey_t *skey; - - if (inp == NULL) - return (-1); - - /* is the keyid the active sending key on the endpoint */ - if (keyid == inp->sctp_ep.default_keyid) - return (-1); - - /* does the key exist? */ - skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid); - if (skey == NULL) - return (-1); - - /* endpoint keys are not refcounted */ - - /* remove it */ - LIST_REMOVE(skey, next); - sctp_free_sharedkey(skey); /* frees skey->key as well */ - - return (0); -} - -/* - * get local authentication parameters from cookie (from INIT-ACK) - */ -void -sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, - uint32_t offset, uint32_t length) -{ - struct sctp_paramhdr *phdr, tmp_param; - uint16_t plen, ptype; - uint8_t random_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_random *p_random = NULL; - uint16_t random_len = 0; - uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_hmac_algo *hmacs = NULL; - uint16_t hmacs_len = 0; - uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_chunk_list *chunks = NULL; - uint16_t num_chunks = 0; - sctp_key_t *new_key; - uint32_t keylen; - - /* convert to upper bound */ - length += offset; - - phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, - sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param); - while (phdr != NULL) { - ptype = ntohs(phdr->param_type); - plen = ntohs(phdr->param_length); - - if ((plen < sizeof(struct sctp_paramhdr)) || - (offset + plen > length)) - break; - - if (ptype == SCTP_RANDOM) { - if (plen > sizeof(random_store)) - break; - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)random_store, plen); - if (phdr == NULL) - return; - /* save the random and length for the key */ - p_random = (struct sctp_auth_random *)phdr; - random_len = plen - sizeof(*p_random); - } else if (ptype == SCTP_HMAC_LIST) { - uint16_t num_hmacs; - uint16_t i; - - if (plen > sizeof(hmacs_store)) - break; - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)hmacs_store, plen); - if (phdr == NULL) - return; - /* save the hmacs list and num for the key */ - hmacs = (struct sctp_auth_hmac_algo *)phdr; - hmacs_len = plen - sizeof(*hmacs); - num_hmacs = hmacs_len / sizeof(hmacs->hmac_ids[0]); - if (stcb->asoc.local_hmacs != NULL) - sctp_free_hmaclist(stcb->asoc.local_hmacs); - stcb->asoc.local_hmacs = sctp_alloc_hmaclist(num_hmacs); - if (stcb->asoc.local_hmacs != NULL) { - for (i = 0; i < num_hmacs; i++) { - (void)sctp_auth_add_hmacid(stcb->asoc.local_hmacs, - ntohs(hmacs->hmac_ids[i])); - } - } - } else if (ptype == SCTP_CHUNK_LIST) { - int i; - - if (plen > sizeof(chunks_store)) - break; - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)chunks_store, plen); - if (phdr == NULL) - return; - chunks = (struct sctp_auth_chunk_list *)phdr; - num_chunks = plen - sizeof(*chunks); - /* save chunks list and num for the key */ - if (stcb->asoc.local_auth_chunks != NULL) - sctp_clear_chunklist(stcb->asoc.local_auth_chunks); - else - stcb->asoc.local_auth_chunks = sctp_alloc_chunklist(); - for (i = 0; i < num_chunks; i++) { - (void)sctp_auth_add_chunk(chunks->chunk_types[i], - stcb->asoc.local_auth_chunks); - } - } - /* get next parameter */ - offset += SCTP_SIZE32(plen); - if (offset + sizeof(struct sctp_paramhdr) > length) - break; - phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), - (uint8_t *)&tmp_param); - } - /* concatenate the full random key */ - keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; - if (chunks != NULL) { - keylen += sizeof(*chunks) + num_chunks; - } - new_key = sctp_alloc_key(keylen); - if (new_key != NULL) { - /* copy in the RANDOM */ - if (p_random != NULL) { - keylen = sizeof(*p_random) + random_len; - memcpy(new_key->key, p_random, keylen); - } else { - keylen = 0; - } - /* append in the AUTH chunks */ - if (chunks != NULL) { - memcpy(new_key->key + keylen, chunks, - sizeof(*chunks) + num_chunks); - keylen += sizeof(*chunks) + num_chunks; - } - /* append in the HMACs */ - if (hmacs != NULL) { - memcpy(new_key->key + keylen, hmacs, - sizeof(*hmacs) + hmacs_len); - } - } - if (stcb->asoc.authinfo.random != NULL) - sctp_free_key(stcb->asoc.authinfo.random); - stcb->asoc.authinfo.random = new_key; - stcb->asoc.authinfo.random_len = random_len; - sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.assoc_keyid); - sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.recv_keyid); - - /* negotiate what HMAC to use for the peer */ - stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs, - stcb->asoc.local_hmacs); - - /* copy defaults from the endpoint */ - /* FIX ME: put in cookie? */ - stcb->asoc.authinfo.active_keyid = stcb->sctp_ep->sctp_ep.default_keyid; - /* copy out the shared key list (by reference) from the endpoint */ - (void)sctp_copy_skeylist(&stcb->sctp_ep->sctp_ep.shared_keys, - &stcb->asoc.shared_keys); -} - -/* - * compute and fill in the HMAC digest for a packet - */ -void -sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset, - struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t keyid) -{ - uint32_t digestlen; - sctp_sharedkey_t *skey; - sctp_key_t *key; - - if ((stcb == NULL) || (auth == NULL)) - return; - - /* zero the digest + chunk padding */ - digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id); - memset(auth->hmac, 0, SCTP_SIZE32(digestlen)); - - /* is the desired key cached? */ - if ((keyid != stcb->asoc.authinfo.assoc_keyid) || - (stcb->asoc.authinfo.assoc_key == NULL)) { - if (stcb->asoc.authinfo.assoc_key != NULL) { - /* free the old cached key */ - sctp_free_key(stcb->asoc.authinfo.assoc_key); - } - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); - /* the only way skey is NULL is if null key id 0 is used */ - if (skey != NULL) - key = skey->key; - else - key = NULL; - /* compute a new assoc key and cache it */ - stcb->asoc.authinfo.assoc_key = - sctp_compute_hashkey(stcb->asoc.authinfo.random, - stcb->asoc.authinfo.peer_random, key); - stcb->asoc.authinfo.assoc_keyid = keyid; - SCTPDBG(SCTP_DEBUG_AUTH1, "caching key id %u\n", - stcb->asoc.authinfo.assoc_keyid); -#ifdef SCTP_DEBUG - if (SCTP_AUTH_DEBUG) - sctp_print_key(stcb->asoc.authinfo.assoc_key, - "Assoc Key"); -#endif - } - - /* set in the active key id */ - auth->shared_key_id = htons(keyid); - - /* compute and fill in the digest */ - (void)sctp_compute_hmac_m(stcb->asoc.peer_hmac_id, stcb->asoc.authinfo.assoc_key, - m, auth_offset, auth->hmac); -} - -static void -sctp_zero_m(struct mbuf *m, uint32_t m_offset, uint32_t size) -{ - struct mbuf *m_tmp; - uint8_t *data; - - /* sanity check */ - if (m == NULL) - return; - - /* find the correct starting mbuf and offset (get start position) */ - m_tmp = m; - while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) { - m_offset -= SCTP_BUF_LEN(m_tmp); - m_tmp = SCTP_BUF_NEXT(m_tmp); - } - /* now use the rest of the mbuf chain */ - while ((m_tmp != NULL) && (size > 0)) { - data = mtod(m_tmp, uint8_t *) + m_offset; - if (size > (uint32_t)(SCTP_BUF_LEN(m_tmp) - m_offset)) { - memset(data, 0, SCTP_BUF_LEN(m_tmp) - m_offset); - size -= SCTP_BUF_LEN(m_tmp) - m_offset; - } else { - memset(data, 0, size); - size = 0; - } - /* clear the offset since it's only for the first mbuf */ - m_offset = 0; - m_tmp = SCTP_BUF_NEXT(m_tmp); - } -} - -/*- - * process the incoming Authentication chunk - * return codes: - * -1 on any authentication error - * 0 on authentication verification - */ -int -sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth, - struct mbuf *m, uint32_t offset) -{ - uint16_t chunklen; - uint16_t shared_key_id; - uint16_t hmac_id; - sctp_sharedkey_t *skey; - uint32_t digestlen; - uint8_t digest[SCTP_AUTH_DIGEST_LEN_MAX]; - uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX]; - - /* auth is checked for NULL by caller */ - chunklen = ntohs(auth->ch.chunk_length); - if (chunklen < sizeof(*auth)) { - SCTP_STAT_INCR(sctps_recvauthfailed); - return (-1); - } - SCTP_STAT_INCR(sctps_recvauth); - - /* get the auth params */ - shared_key_id = ntohs(auth->shared_key_id); - hmac_id = ntohs(auth->hmac_id); - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP AUTH Chunk: shared key %u, HMAC id %u\n", - shared_key_id, hmac_id); - -#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) - return (0); -#endif - /* is the indicated HMAC supported? */ - if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) { - struct mbuf *op_err; - struct sctp_error_auth_invalid_hmac *cause; - - SCTP_STAT_INCR(sctps_recvivalhmacid); - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP Auth: unsupported HMAC id %u\n", - hmac_id); - /* - * report this in an Error Chunk: Unsupported HMAC - * Identifier - */ - op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_auth_invalid_hmac), - 0, M_NOWAIT, 1, MT_HEADER); - if (op_err != NULL) { - /* pre-reserve some space */ - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - /* fill in the error */ - cause = mtod(op_err, struct sctp_error_auth_invalid_hmac *); - cause->cause.code = htons(SCTP_CAUSE_UNSUPPORTED_HMACID); - cause->cause.length = htons(sizeof(struct sctp_error_auth_invalid_hmac)); - cause->hmac_id = ntohs(hmac_id); - SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_auth_invalid_hmac); - /* queue it */ - sctp_queue_op_err(stcb, op_err); - } - return (-1); - } - /* get the indicated shared key, if available */ - if ((stcb->asoc.authinfo.recv_key == NULL) || - (stcb->asoc.authinfo.recv_keyid != shared_key_id)) { - /* find the shared key on the assoc first */ - skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, - shared_key_id); - /* if the shared key isn't found, discard the chunk */ - if (skey == NULL) { - SCTP_STAT_INCR(sctps_recvivalkeyid); - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP Auth: unknown key id %u\n", - shared_key_id); - return (-1); - } - /* generate a notification if this is a new key id */ - if (stcb->asoc.authinfo.recv_keyid != shared_key_id) - /* - * sctp_ulp_notify(SCTP_NOTIFY_AUTH_NEW_KEY, stcb, - * shared_key_id, (void - * *)stcb->asoc.authinfo.recv_keyid); - */ - sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, - shared_key_id, stcb->asoc.authinfo.recv_keyid, - SCTP_SO_NOT_LOCKED); - /* compute a new recv assoc key and cache it */ - if (stcb->asoc.authinfo.recv_key != NULL) - sctp_free_key(stcb->asoc.authinfo.recv_key); - stcb->asoc.authinfo.recv_key = - sctp_compute_hashkey(stcb->asoc.authinfo.random, - stcb->asoc.authinfo.peer_random, skey->key); - stcb->asoc.authinfo.recv_keyid = shared_key_id; -#ifdef SCTP_DEBUG - if (SCTP_AUTH_DEBUG) - sctp_print_key(stcb->asoc.authinfo.recv_key, "Recv Key"); -#endif - } - /* validate the digest length */ - digestlen = sctp_get_hmac_digest_len(hmac_id); - if (chunklen < (sizeof(*auth) + digestlen)) { - /* invalid digest length */ - SCTP_STAT_INCR(sctps_recvauthfailed); - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP Auth: chunk too short for HMAC\n"); - return (-1); - } - /* save a copy of the digest, zero the pseudo header, and validate */ - memcpy(digest, auth->hmac, digestlen); - sctp_zero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen)); - (void)sctp_compute_hmac_m(hmac_id, stcb->asoc.authinfo.recv_key, - m, offset, computed_digest); - - /* compare the computed digest with the one in the AUTH chunk */ - if (timingsafe_bcmp(digest, computed_digest, digestlen) != 0) { - SCTP_STAT_INCR(sctps_recvauthfailed); - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP Auth: HMAC digest check failed\n"); - return (-1); - } - return (0); -} - -/* - * Generate NOTIFICATION - */ -void -sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication, - uint16_t keyid, uint16_t alt_keyid, int so_locked) -{ - struct mbuf *m_notify; - struct sctp_authkey_event *auth; - struct sctp_queued_to_read *control; - - if ((stcb == NULL) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) - ) { - /* If the socket is gone we are out of here */ - return; - } - - if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_AUTHEVNT)) - /* event not enabled */ - return; - - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_authkey_event), - 0, M_NOWAIT, 1, MT_HEADER); - if (m_notify == NULL) - /* no space left */ - return; - - SCTP_BUF_LEN(m_notify) = 0; - auth = mtod(m_notify, struct sctp_authkey_event *); - memset(auth, 0, sizeof(struct sctp_authkey_event)); - auth->auth_type = SCTP_AUTHENTICATION_EVENT; - auth->auth_flags = 0; - auth->auth_length = sizeof(*auth); - auth->auth_keynumber = keyid; - auth->auth_altkeynumber = alt_keyid; - auth->auth_indication = indication; - auth->auth_assoc_id = sctp_get_associd(stcb); - - SCTP_BUF_LEN(m_notify) = sizeof(*auth); - SCTP_BUF_NEXT(m_notify) = NULL; - - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); -} - -/*- - * validates the AUTHentication related parameters in an INIT/INIT-ACK - * Note: currently only used for INIT as INIT-ACK is handled inline - * with sctp_load_addresses_from_init() - */ -int -sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) -{ - struct sctp_paramhdr *phdr, param_buf; - uint16_t ptype, plen; - int peer_supports_asconf = 0; - int peer_supports_auth = 0; - int got_random = 0, got_hmacs = 0, got_chklist = 0; - uint8_t saw_asconf = 0; - uint8_t saw_asconf_ack = 0; - - /* go through each of the params. */ - phdr = sctp_get_next_param(m, offset, ¶m_buf, sizeof(param_buf)); - while (phdr) { - ptype = ntohs(phdr->param_type); - plen = ntohs(phdr->param_length); - - if (offset + plen > limit) { - break; - } - if (plen < sizeof(struct sctp_paramhdr)) { - break; - } - if (ptype == SCTP_SUPPORTED_CHUNK_EXT) { - /* A supported extension chunk */ - struct sctp_supported_chunk_types_param *pr_supported; - uint8_t local_store[SCTP_SMALL_CHUNK_STORE]; - int num_ent, i; - - if (plen > sizeof(local_store)) { - break; - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&local_store, - plen); - if (phdr == NULL) { - return (-1); - } - pr_supported = (struct sctp_supported_chunk_types_param *)phdr; - num_ent = plen - sizeof(struct sctp_paramhdr); - for (i = 0; i < num_ent; i++) { - switch (pr_supported->chunk_types[i]) { - case SCTP_ASCONF: - case SCTP_ASCONF_ACK: - peer_supports_asconf = 1; - break; - default: - /* one we don't care about */ - break; - } - } - } else if (ptype == SCTP_RANDOM) { - /* enforce the random length */ - if (plen != (sizeof(struct sctp_auth_random) + - SCTP_AUTH_RANDOM_SIZE_REQUIRED)) { - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: invalid RANDOM len\n"); - return (-1); - } - got_random = 1; - } else if (ptype == SCTP_HMAC_LIST) { - struct sctp_auth_hmac_algo *hmacs; - uint8_t store[SCTP_PARAM_BUFFER_SIZE]; - int num_hmacs; - - if (plen > sizeof(store)) { - break; - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)store, - plen); - if (phdr == NULL) { - return (-1); - } - hmacs = (struct sctp_auth_hmac_algo *)phdr; - num_hmacs = (plen - sizeof(*hmacs)) / sizeof(hmacs->hmac_ids[0]); - /* validate the hmac list */ - if (sctp_verify_hmac_param(hmacs, num_hmacs)) { - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: invalid HMAC param\n"); - return (-1); - } - got_hmacs = 1; - } else if (ptype == SCTP_CHUNK_LIST) { - struct sctp_auth_chunk_list *chunks; - uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE]; - int i, num_chunks; - - if (plen > sizeof(chunks_store)) { - break; - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)chunks_store, - plen); - if (phdr == NULL) { - return (-1); - } - /*- - * Flip through the list and mark that the - * peer supports asconf/asconf_ack. - */ - chunks = (struct sctp_auth_chunk_list *)phdr; - num_chunks = plen - sizeof(*chunks); - for (i = 0; i < num_chunks; i++) { - /* record asconf/asconf-ack if listed */ - if (chunks->chunk_types[i] == SCTP_ASCONF) - saw_asconf = 1; - if (chunks->chunk_types[i] == SCTP_ASCONF_ACK) - saw_asconf_ack = 1; - } - if (num_chunks) - got_chklist = 1; - } - - offset += SCTP_SIZE32(plen); - if (offset >= limit) { - break; - } - phdr = sctp_get_next_param(m, offset, ¶m_buf, - sizeof(param_buf)); - } - /* validate authentication required parameters */ - if (got_random && got_hmacs) { - peer_supports_auth = 1; - } else { - peer_supports_auth = 0; - } - if (!peer_supports_auth && got_chklist) { - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: peer sent chunk list w/o AUTH\n"); - return (-1); - } - if (peer_supports_asconf && !peer_supports_auth) { - SCTPDBG(SCTP_DEBUG_AUTH1, - "SCTP: peer supports ASCONF but not AUTH\n"); - return (-1); - } else if ((peer_supports_asconf) && (peer_supports_auth) && - ((saw_asconf == 0) || (saw_asconf_ack == 0))) { - return (-2); - } - return (0); -} - -void -sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb) -{ - uint16_t chunks_len = 0; - uint16_t hmacs_len = 0; - uint16_t random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT; - sctp_key_t *new_key; - uint16_t keylen; - - /* initialize hmac list from endpoint */ - stcb->asoc.local_hmacs = sctp_copy_hmaclist(inp->sctp_ep.local_hmacs); - if (stcb->asoc.local_hmacs != NULL) { - hmacs_len = stcb->asoc.local_hmacs->num_algo * - sizeof(stcb->asoc.local_hmacs->hmac[0]); - } - /* initialize auth chunks list from endpoint */ - stcb->asoc.local_auth_chunks = - sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks); - if (stcb->asoc.local_auth_chunks != NULL) { - int i; - for (i = 0; i < 256; i++) { - if (stcb->asoc.local_auth_chunks->chunks[i]) - chunks_len++; - } - } - /* copy defaults from the endpoint */ - stcb->asoc.authinfo.active_keyid = inp->sctp_ep.default_keyid; - - /* copy out the shared key list (by reference) from the endpoint */ - (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys, - &stcb->asoc.shared_keys); - - /* now set the concatenated key (random + chunks + hmacs) */ - /* key includes parameter headers */ - keylen = (3 * sizeof(struct sctp_paramhdr)) + random_len + chunks_len + - hmacs_len; - new_key = sctp_alloc_key(keylen); - if (new_key != NULL) { - struct sctp_paramhdr *ph; - int plen; - /* generate and copy in the RANDOM */ - ph = (struct sctp_paramhdr *)new_key->key; - ph->param_type = htons(SCTP_RANDOM); - plen = sizeof(*ph) + random_len; - ph->param_length = htons(plen); - SCTP_READ_RANDOM(new_key->key + sizeof(*ph), random_len); - keylen = plen; - - /* append in the AUTH chunks */ - /* NOTE: currently we always have chunks to list */ - ph = (struct sctp_paramhdr *)(new_key->key + keylen); - ph->param_type = htons(SCTP_CHUNK_LIST); - plen = sizeof(*ph) + chunks_len; - ph->param_length = htons(plen); - keylen += sizeof(*ph); - if (stcb->asoc.local_auth_chunks) { - int i; - for (i = 0; i < 256; i++) { - if (stcb->asoc.local_auth_chunks->chunks[i]) - new_key->key[keylen++] = i; - } - } - - /* append in the HMACs */ - ph = (struct sctp_paramhdr *)(new_key->key + keylen); - ph->param_type = htons(SCTP_HMAC_LIST); - plen = sizeof(*ph) + hmacs_len; - ph->param_length = htons(plen); - keylen += sizeof(*ph); - (void)sctp_serialize_hmaclist(stcb->asoc.local_hmacs, - new_key->key + keylen); - } - if (stcb->asoc.authinfo.random != NULL) - sctp_free_key(stcb->asoc.authinfo.random); - stcb->asoc.authinfo.random = new_key; - stcb->asoc.authinfo.random_len = random_len; -} - - -#ifdef SCTP_HMAC_TEST -/* - * HMAC and key concatenation tests - */ -static void -sctp_print_digest(uint8_t *digest, uint32_t digestlen, const char *str) -{ - uint32_t i; - - SCTP_PRINTF("\n%s: 0x", str); - if (digest == NULL) - return; - - for (i = 0; i < digestlen; i++) - SCTP_PRINTF("%02x", digest[i]); -} - -static int -sctp_test_hmac(const char *str, uint16_t hmac_id, uint8_t *key, - uint32_t keylen, uint8_t *text, uint32_t textlen, - uint8_t *digest, uint32_t digestlen) -{ - uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX]; - - SCTP_PRINTF("\n%s:", str); - sctp_hmac(hmac_id, key, keylen, text, textlen, computed_digest); - sctp_print_digest(digest, digestlen, "Expected digest"); - sctp_print_digest(computed_digest, digestlen, "Computed digest"); - if (memcmp(digest, computed_digest, digestlen) != 0) { - SCTP_PRINTF("\nFAILED"); - return (-1); - } else { - SCTP_PRINTF("\nPASSED"); - return (0); - } -} - - -/* - * RFC 2202: HMAC-SHA1 test cases - */ -void -sctp_test_hmac_sha1(void) -{ - uint8_t *digest; - uint8_t key[128]; - uint32_t keylen; - uint8_t text[128]; - uint32_t textlen; - uint32_t digestlen = 20; - int failed = 0; - - /*- - * test_case = 1 - * key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b - * key_len = 20 - * data = "Hi There" - * data_len = 8 - * digest = 0xb617318655057264e28bc0b6fb378c8ef146be00 - */ - keylen = 20; - memset(key, 0x0b, keylen); - textlen = 8; - strcpy(text, "Hi There"); - digest = "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00"; - if (sctp_test_hmac("SHA1 test case 1", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /*- - * test_case = 2 - * key = "Jefe" - * key_len = 4 - * data = "what do ya want for nothing?" - * data_len = 28 - * digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79 - */ - keylen = 4; - strcpy(key, "Jefe"); - textlen = 28; - strcpy(text, "what do ya want for nothing?"); - digest = "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79"; - if (sctp_test_hmac("SHA1 test case 2", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /*- - * test_case = 3 - * key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - * key_len = 20 - * data = 0xdd repeated 50 times - * data_len = 50 - * digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3 - */ - keylen = 20; - memset(key, 0xaa, keylen); - textlen = 50; - memset(text, 0xdd, textlen); - digest = "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3"; - if (sctp_test_hmac("SHA1 test case 3", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /*- - * test_case = 4 - * key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819 - * key_len = 25 - * data = 0xcd repeated 50 times - * data_len = 50 - * digest = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da - */ - keylen = 25; - memcpy(key, "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", keylen); - textlen = 50; - memset(text, 0xcd, textlen); - digest = "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda"; - if (sctp_test_hmac("SHA1 test case 4", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /*- - * test_case = 5 - * key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c - * key_len = 20 - * data = "Test With Truncation" - * data_len = 20 - * digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04 - * digest-96 = 0x4c1a03424b55e07fe7f27be1 - */ - keylen = 20; - memset(key, 0x0c, keylen); - textlen = 20; - strcpy(text, "Test With Truncation"); - digest = "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04"; - if (sctp_test_hmac("SHA1 test case 5", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /*- - * test_case = 6 - * key = 0xaa repeated 80 times - * key_len = 80 - * data = "Test Using Larger Than Block-Size Key - Hash Key First" - * data_len = 54 - * digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112 - */ - keylen = 80; - memset(key, 0xaa, keylen); - textlen = 54; - strcpy(text, "Test Using Larger Than Block-Size Key - Hash Key First"); - digest = "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12"; - if (sctp_test_hmac("SHA1 test case 6", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /*- - * test_case = 7 - * key = 0xaa repeated 80 times - * key_len = 80 - * data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" - * data_len = 73 - * digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91 - */ - keylen = 80; - memset(key, 0xaa, keylen); - textlen = 73; - strcpy(text, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"); - digest = "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91"; - if (sctp_test_hmac("SHA1 test case 7", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, - text, textlen, digest, digestlen) < 0) - failed++; - - /* done with all tests */ - if (failed) - SCTP_PRINTF("\nSHA1 test results: %d cases failed", failed); - else - SCTP_PRINTF("\nSHA1 test results: all test cases passed"); -} - -/* - * test assoc key concatenation - */ -static int -sctp_test_key_concatenation(sctp_key_t *key1, sctp_key_t *key2, - sctp_key_t *expected_key) -{ - sctp_key_t *key; - int ret_val; - - sctp_show_key(key1, "\nkey1"); - sctp_show_key(key2, "\nkey2"); - key = sctp_compute_hashkey(key1, key2, NULL); - sctp_show_key(expected_key, "\nExpected"); - sctp_show_key(key, "\nComputed"); - if (memcmp(key, expected_key, expected_key->keylen) != 0) { - SCTP_PRINTF("\nFAILED"); - ret_val = -1; - } else { - SCTP_PRINTF("\nPASSED"); - ret_val = 0; - } - sctp_free_key(key1); - sctp_free_key(key2); - sctp_free_key(expected_key); - sctp_free_key(key); - return (ret_val); -} - - -void -sctp_test_authkey(void) -{ - sctp_key_t *key1, *key2, *expected_key; - int failed = 0; - - /* test case 1 */ - key1 = sctp_set_key("\x01\x01\x01\x01", 4); - key2 = sctp_set_key("\x01\x02\x03\x04", 4); - expected_key = sctp_set_key("\x01\x01\x01\x01\x01\x02\x03\x04", 8); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* test case 2 */ - key1 = sctp_set_key("\x00\x00\x00\x01", 4); - key2 = sctp_set_key("\x02", 1); - expected_key = sctp_set_key("\x00\x00\x00\x01\x02", 5); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* test case 3 */ - key1 = sctp_set_key("\x01", 1); - key2 = sctp_set_key("\x00\x00\x00\x02", 4); - expected_key = sctp_set_key("\x01\x00\x00\x00\x02", 5); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* test case 4 */ - key1 = sctp_set_key("\x00\x00\x00\x01", 4); - key2 = sctp_set_key("\x01", 1); - expected_key = sctp_set_key("\x01\x00\x00\x00\x01", 5); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* test case 5 */ - key1 = sctp_set_key("\x01", 1); - key2 = sctp_set_key("\x00\x00\x00\x01", 4); - expected_key = sctp_set_key("\x01\x00\x00\x00\x01", 5); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* test case 6 */ - key1 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07", 11); - key2 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 11); - expected_key = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 22); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* test case 7 */ - key1 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 11); - key2 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07", 11); - expected_key = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 22); - if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) - failed++; - - /* done with all tests */ - if (failed) - SCTP_PRINTF("\nKey concatenation test results: %d cases failed", failed); - else - SCTP_PRINTF("\nKey concatenation test results: all test cases passed"); -} - - -#if defined(STANDALONE_HMAC_TEST) -int -main(void) -{ - sctp_test_hmac_sha1(); - sctp_test_authkey(); -} - -#endif /* STANDALONE_HMAC_TEST */ - -#endif /* SCTP_HMAC_TEST */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.h deleted file mode 100644 index 718b2f5b..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_auth.h +++ /dev/null @@ -1,213 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_AUTH_H_ -#define _NETINET_SCTP_AUTH_H_ - -#include - -/* digest lengths */ -#define SCTP_AUTH_DIGEST_LEN_SHA1 20 -#define SCTP_AUTH_DIGEST_LEN_SHA256 32 -#define SCTP_AUTH_DIGEST_LEN_MAX SCTP_AUTH_DIGEST_LEN_SHA256 - -/* random sizes */ -#define SCTP_AUTH_RANDOM_SIZE_DEFAULT 32 -#define SCTP_AUTH_RANDOM_SIZE_REQUIRED 32 - -/* union of all supported HMAC algorithm contexts */ -typedef union sctp_hash_context { - SCTP_SHA1_CTX sha1; -#if defined(SCTP_SUPPORT_HMAC_SHA256) - SCTP_SHA256_CTX sha256; -#endif -} sctp_hash_context_t; - -typedef struct sctp_key { - uint32_t keylen; - uint8_t key[]; -} sctp_key_t; - -typedef struct sctp_shared_key { - LIST_ENTRY(sctp_shared_key) next; - sctp_key_t *key; /* key text */ - uint32_t refcount; /* reference count */ - uint16_t keyid; /* shared key ID */ - uint8_t deactivated; /* key is deactivated */ -} sctp_sharedkey_t; - -LIST_HEAD(sctp_keyhead, sctp_shared_key); - -/* authentication chunks list */ -typedef struct sctp_auth_chklist { - uint8_t chunks[256]; - uint8_t num_chunks; -} sctp_auth_chklist_t; - -/* hmac algos supported list */ -typedef struct sctp_hmaclist { - uint16_t max_algo; /* max algorithms allocated */ - uint16_t num_algo; /* num algorithms used */ - uint16_t hmac[]; -} sctp_hmaclist_t; - -/* authentication info */ -typedef struct sctp_authinformation { - sctp_key_t *random; /* local random key (concatenated) */ - uint32_t random_len; /* local random number length for param */ - sctp_key_t *peer_random;/* peer's random key (concatenated) */ - sctp_key_t *assoc_key; /* cached concatenated send key */ - sctp_key_t *recv_key; /* cached concatenated recv key */ - uint16_t active_keyid; /* active send keyid */ - uint16_t assoc_keyid; /* current send keyid (cached) */ - uint16_t recv_keyid; /* last recv keyid (cached) */ -} sctp_authinfo_t; - -/* - * Macros - */ -#define sctp_auth_is_required_chunk(chunk, list) ((list == NULL) ? (0) : (list->chunks[chunk] != 0)) - -/* - * function prototypes - */ - -/* socket option api functions */ -extern sctp_auth_chklist_t *sctp_alloc_chunklist(void); -extern void sctp_free_chunklist(sctp_auth_chklist_t *chklist); -extern void sctp_clear_chunklist(sctp_auth_chklist_t *chklist); -extern sctp_auth_chklist_t *sctp_copy_chunklist(sctp_auth_chklist_t *chklist); -extern int sctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t *list); -extern int sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t *list); -extern size_t sctp_auth_get_chklist_size(const sctp_auth_chklist_t *list); -extern int sctp_serialize_auth_chunks(const sctp_auth_chklist_t *list, - uint8_t *ptr); -extern int sctp_pack_auth_chunks(const sctp_auth_chklist_t *list, - uint8_t *ptr); -extern int sctp_unpack_auth_chunks(const uint8_t *ptr, uint8_t num_chunks, - sctp_auth_chklist_t *list); - -/* key handling */ -extern sctp_key_t *sctp_alloc_key(uint32_t keylen); -extern void sctp_free_key(sctp_key_t *key); -extern void sctp_print_key(sctp_key_t *key, const char *str); -extern void sctp_show_key(sctp_key_t *key, const char *str); -extern sctp_key_t *sctp_generate_random_key(uint32_t keylen); -extern sctp_key_t *sctp_set_key(uint8_t *key, uint32_t keylen); -extern sctp_key_t *sctp_compute_hashkey(sctp_key_t *key1, sctp_key_t *key2, - sctp_key_t *shared); - -/* shared key handling */ -extern sctp_sharedkey_t *sctp_alloc_sharedkey(void); -extern void sctp_free_sharedkey(sctp_sharedkey_t *skey); -extern sctp_sharedkey_t *sctp_find_sharedkey(struct sctp_keyhead *shared_keys, - uint16_t key_id); -extern int sctp_insert_sharedkey(struct sctp_keyhead *shared_keys, - sctp_sharedkey_t *new_skey); -extern int sctp_copy_skeylist(const struct sctp_keyhead *src, - struct sctp_keyhead *dest); -/* ref counts on shared keys, by key id */ -extern void sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t keyid); -extern void sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t keyid, - int so_locked); - -/* hmac list handling */ -extern sctp_hmaclist_t *sctp_alloc_hmaclist(uint16_t num_hmacs); -extern void sctp_free_hmaclist(sctp_hmaclist_t *list); -extern int sctp_auth_add_hmacid(sctp_hmaclist_t *list, uint16_t hmac_id); -extern sctp_hmaclist_t *sctp_copy_hmaclist(sctp_hmaclist_t *list); -extern sctp_hmaclist_t *sctp_default_supported_hmaclist(void); -extern uint16_t sctp_negotiate_hmacid(sctp_hmaclist_t *peer, - sctp_hmaclist_t *local); -extern int sctp_serialize_hmaclist(sctp_hmaclist_t *list, uint8_t *ptr); -extern int sctp_verify_hmac_param(struct sctp_auth_hmac_algo *hmacs, - uint32_t num_hmacs); - -extern sctp_authinfo_t *sctp_alloc_authinfo(void); -extern void sctp_free_authinfo(sctp_authinfo_t *authinfo); - -/* keyed-HMAC functions */ -extern uint32_t sctp_get_auth_chunk_len(uint16_t hmac_algo); -extern uint32_t sctp_get_hmac_digest_len(uint16_t hmac_algo); -extern uint32_t sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, - uint8_t *text, uint32_t textlen, uint8_t *digest); -extern uint32_t sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key, - uint8_t *text, uint32_t textlen, uint8_t *digest); -extern int sctp_auth_is_supported_hmac(sctp_hmaclist_t *list, uint16_t id); - -/* mbuf versions */ -extern uint32_t sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, - struct mbuf *m, uint32_t m_offset, uint8_t *digest, uint32_t trailer); -extern uint32_t sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t *key, - struct mbuf *m, uint32_t m_offset, uint8_t *digest); - -/* - * authentication routines - */ -extern void sctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid); -extern void sctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid); -extern int sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid); -extern int sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid); -extern int sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid); -extern int sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid); -extern int sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid); -extern int sctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid); - -extern void sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, - uint32_t offset, uint32_t length); -extern void sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset, - struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t key_id); -extern struct mbuf *sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end, - struct sctp_auth_chunk **auth_ret, uint32_t *offset, - struct sctp_tcb *stcb, uint8_t chunk); -extern int sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *ch, - struct mbuf *m, uint32_t offset); -extern void sctp_notify_authentication(struct sctp_tcb *stcb, - uint32_t indication, uint16_t keyid, uint16_t alt_keyid, int so_locked); -extern int sctp_validate_init_auth_params(struct mbuf *m, int offset, - int limit); -extern void sctp_initialize_auth_params(struct sctp_inpcb *inp, - struct sctp_tcb *stcb); - -/* test functions */ -#ifdef SCTP_HMAC_TEST -extern void sctp_test_hmac_sha1(void); -extern void sctp_test_authkey(void); -#endif -#endif /* __SCTP_AUTH_H__ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.c deleted file mode 100644 index 1635a46e..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.c +++ /dev/null @@ -1,989 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif - -/* Declare all of our malloc named types */ -MALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor"); -MALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array"); -MALLOC_DEFINE(SCTP_M_STRMO, "sctp_stro", "sctp stream out array"); -MALLOC_DEFINE(SCTP_M_ASC_ADDR, "sctp_aadr", "sctp asconf address"); -MALLOC_DEFINE(SCTP_M_ASC_IT, "sctp_a_it", "sctp asconf iterator"); -MALLOC_DEFINE(SCTP_M_AUTH_CL, "sctp_atcl", "sctp auth chunklist"); -MALLOC_DEFINE(SCTP_M_AUTH_KY, "sctp_atky", "sctp auth key"); -MALLOC_DEFINE(SCTP_M_AUTH_HL, "sctp_athm", "sctp auth hmac list"); -MALLOC_DEFINE(SCTP_M_AUTH_IF, "sctp_athi", "sctp auth info"); -MALLOC_DEFINE(SCTP_M_STRESET, "sctp_stre", "sctp stream reset"); -MALLOC_DEFINE(SCTP_M_CMSG, "sctp_cmsg", "sctp CMSG buffer"); -MALLOC_DEFINE(SCTP_M_COPYAL, "sctp_cpal", "sctp copy all"); -MALLOC_DEFINE(SCTP_M_VRF, "sctp_vrf", "sctp vrf struct"); -MALLOC_DEFINE(SCTP_M_IFA, "sctp_ifa", "sctp ifa struct"); -MALLOC_DEFINE(SCTP_M_IFN, "sctp_ifn", "sctp ifn struct"); -MALLOC_DEFINE(SCTP_M_TIMW, "sctp_timw", "sctp time block"); -MALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", "sctp mvrf pcb list"); -MALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control"); -MALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option"); -MALLOC_DEFINE(SCTP_M_MCORE, "sctp_mcore", "sctp mcore queue"); - -/* Global NON-VNET structure that controls the iterator */ -struct iterator_control sctp_it_ctl; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - -static void -sctp_cleanup_itqueue(void) -{ - struct sctp_iterator *it, *nit; - - TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { - if (it->function_atend != NULL) { - (*it->function_atend) (it->pointer, it->val); - } - TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); - SCTP_FREE(it, SCTP_M_ITER); - } -} -#endif -#if defined(__Userspace__) -/*__Userspace__ TODO if we use thread based iterator - * then the implementation of wakeup will need to change. - * Currently we are using timeo_cond for ident so_timeo - * but that is not sufficient if we need to use another ident - * like wakeup(&sctppcbinfo.iterator_running); - */ -#endif - -void -sctp_wakeup_iterator(void) -{ -#if defined(SCTP_PROCESS_LEVEL_LOCKS) -#if defined(_WIN32) - WakeAllConditionVariable(&sctp_it_ctl.iterator_wakeup); -#else - pthread_cond_broadcast(&sctp_it_ctl.iterator_wakeup); -#endif -#else - wakeup(&sctp_it_ctl.iterator_running); -#endif -} - -#if defined(__Userspace__) -static void * -#else -static void -#endif -sctp_iterator_thread(void *v SCTP_UNUSED) -{ -#if defined(__Userspace__) - sctp_userspace_set_threadname("SCTP iterator"); -#endif - SCTP_IPI_ITERATOR_WQ_LOCK(); - /* In FreeBSD this thread never terminates. */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - for (;;) { -#else - while ((sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) == 0) { -#endif -#if !defined(__Userspace__) - msleep(&sctp_it_ctl.iterator_running, -#if defined(__FreeBSD__) - &sctp_it_ctl.ipi_iterator_wq_mtx, -#elif defined(__APPLE__) - sctp_it_ctl.ipi_iterator_wq_mtx, -#endif - 0, "waiting_for_work", 0); -#else -#if defined(_WIN32) - SleepConditionVariableCS(&sctp_it_ctl.iterator_wakeup, &sctp_it_ctl.ipi_iterator_wq_mtx, INFINITE); -#else - pthread_cond_wait(&sctp_it_ctl.iterator_wakeup, &sctp_it_ctl.ipi_iterator_wq_mtx); -#endif -#endif -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) { - break; - } -#endif - sctp_iterator_worker(); - } -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - /* Now this thread needs to be terminated */ - sctp_cleanup_itqueue(); - sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_EXITED; - SCTP_IPI_ITERATOR_WQ_UNLOCK(); -#if defined(__Userspace__) - sctp_wakeup_iterator(); - return (NULL); -#else - wakeup(&sctp_it_ctl.iterator_flags); - thread_terminate(current_thread()); -#ifdef INVARIANTS - panic("Hmm. thread_terminate() continues..."); -#endif -#endif -#endif -} - -void -sctp_startup_iterator(void) -{ - if (sctp_it_ctl.thread_proc) { - /* You only get one */ - return; - } - /* Initialize global locks here, thus only once. */ - SCTP_ITERATOR_LOCK_INIT(); - SCTP_IPI_ITERATOR_WQ_INIT(); - TAILQ_INIT(&sctp_it_ctl.iteratorhead); -#if defined(__Userspace__) - if (sctp_userspace_thread_create(&sctp_it_ctl.thread_proc, &sctp_iterator_thread)) { - SCTP_PRINTF("ERROR: Creating sctp_iterator_thread failed.\n"); - } else { - SCTP_BASE_VAR(iterator_thread_started) = 1; - } -#elif defined(__FreeBSD__) - kproc_create(sctp_iterator_thread, - (void *)NULL, - &sctp_it_ctl.thread_proc, - 0, - SCTP_KTHREAD_PAGES, - SCTP_KTRHEAD_NAME); -#elif defined(__APPLE__) - kernel_thread_start((thread_continue_t)sctp_iterator_thread, NULL, &sctp_it_ctl.thread_proc); -#endif -} - -#ifdef INET6 - -#if defined(__Userspace__) -/* __Userspace__ TODO. struct in6_ifaddr is defined in sys/netinet6/in6_var.h - ip6_use_deprecated is defined as int ip6_use_deprecated = 1; in /src/sys/netinet6/in6_proto.c - */ -void -sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa) -{ - return; /* stub */ -} -#else -void -sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa) -{ - struct in6_ifaddr *ifa6; - - ifa6 = (struct in6_ifaddr *)ifa->ifa; - ifa->flags = ifa6->ia6_flags; - if (!MODULE_GLOBAL(ip6_use_deprecated)) { - if (ifa->flags & - IN6_IFF_DEPRECATED) { - ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; - } else { - ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; - } - } else { - ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; - } - if (ifa->flags & - (IN6_IFF_DETACHED | - IN6_IFF_ANYCAST | - IN6_IFF_NOTREADY)) { - ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; - } else { - ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; - } -} -#endif /* __Userspace__ */ -#endif /* INET6 */ - -#if !defined(__Userspace__) -static uint32_t -sctp_is_desired_interface_type(struct ifnet *ifn) -{ - int result; - - /* check the interface type to see if it's one we care about */ -#if defined(__APPLE__) && !defined(__Userspace__) - switch(ifnet_type(ifn)) { -#else - switch (ifn->if_type) { -#endif - case IFT_ETHER: - case IFT_ISO88023: - case IFT_ISO88024: - case IFT_ISO88025: - case IFT_ISO88026: - case IFT_STARLAN: - case IFT_P10: - case IFT_P80: - case IFT_HY: - case IFT_FDDI: - case IFT_XETHER: - case IFT_ISDNBASIC: - case IFT_ISDNPRIMARY: - case IFT_PTPSERIAL: - case IFT_OTHER: - case IFT_PPP: - case IFT_LOOP: - case IFT_SLIP: - case IFT_GIF: - case IFT_L2VLAN: - case IFT_STF: -#if !(defined(__APPLE__) && !defined(__Userspace__)) - case IFT_IP: - case IFT_IPOVERCDLC: - case IFT_IPOVERCLAW: - case IFT_PROPVIRTUAL: /* NetGraph Virtual too */ - case IFT_VIRTUALIPADDRESS: -#endif - result = 1; - break; - default: - result = 0; - } - - return (result); -} -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - -int -sctp_is_vmware_interface(struct ifnet *ifn) -{ - return (strncmp(ifnet_name(ifn), "vmnet", 5) == 0); -} - -#endif - -#if defined(_WIN32) && defined(__Userspace__) -#ifdef MALLOC -#undef MALLOC -#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) -#endif -#ifdef FREE -#undef FREE -#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) -#endif -static void -sctp_init_ifns_for_vrf(int vrfid) -{ -#if defined(INET) || defined(INET6) - struct sctp_ifa *sctp_ifa; - DWORD Err, AdapterAddrsSize; - PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt; - PIP_ADAPTER_UNICAST_ADDRESS pUnicast; -#endif - -#ifdef INET - AdapterAddrsSize = 0; - - if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { - if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { - SCTP_PRINTF("GetAdaptersV4Addresses() sizing failed with error code %d\n", Err); - SCTP_PRINTF("err = %d; AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); - return; - } - } - - /* Allocate memory from sizing information */ - if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { - SCTP_PRINTF("Memory allocation error!\n"); - return; - } - /* Get actual adapter information */ - if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { - SCTP_PRINTF("GetAdaptersV4Addresses() failed with error code %d\n", Err); - FREE(pAdapterAddrs); - return; - } - /* Enumerate through each returned adapter and save its information */ - for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { - if (pAdapt->IfType == IF_TYPE_IEEE80211 || pAdapt->IfType == IF_TYPE_ETHERNET_CSMACD) { - for (pUnicast = pAdapt->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { - if (IN4_ISLINKLOCAL_ADDRESS(&(((struct sockaddr_in *)(pUnicast->Address.lpSockaddr))->sin_addr))) { - continue; - } - sctp_ifa = sctp_add_addr_to_vrf(0, - NULL, - pAdapt->IfIndex, - (pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType, - pAdapt->AdapterName, - NULL, - pUnicast->Address.lpSockaddr, - pAdapt->Flags, - 0); - if (sctp_ifa) { - sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - } - } - } - FREE(pAdapterAddrs); -#endif -#ifdef INET6 - AdapterAddrsSize = 0; - - if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { - if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { - SCTP_PRINTF("GetAdaptersV6Addresses() sizing failed with error code %d\n", Err); - SCTP_PRINTF("err = %d; AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); - return; - } - } - /* Allocate memory from sizing information */ - if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { - SCTP_PRINTF("Memory allocation error!\n"); - return; - } - /* Get actual adapter information */ - if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { - SCTP_PRINTF("GetAdaptersV6Addresses() failed with error code %d\n", Err); - FREE(pAdapterAddrs); - return; - } - /* Enumerate through each returned adapter and save its information */ - for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { - if (pAdapt->IfType == IF_TYPE_IEEE80211 || pAdapt->IfType == IF_TYPE_ETHERNET_CSMACD) { - for (pUnicast = pAdapt->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { - sctp_ifa = sctp_add_addr_to_vrf(0, - NULL, - pAdapt->Ipv6IfIndex, - (pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType, - pAdapt->AdapterName, - NULL, - pUnicast->Address.lpSockaddr, - pAdapt->Flags, - 0); - if (sctp_ifa) { - sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - } - } - } - FREE(pAdapterAddrs); -#endif -} -#elif defined(__Userspace__) -static void -sctp_init_ifns_for_vrf(int vrfid) -{ -#if defined(INET) || defined(INET6) - int rc; - struct ifaddrs *ifa, *ifas; - struct sctp_ifa *sctp_ifa; - uint32_t ifa_flags; - - rc = getifaddrs(&ifas); - if (rc != 0) { - return; - } - for (ifa = ifas; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL) { - continue; - } -#if !defined(INET) - if (ifa->ifa_addr->sa_family != AF_INET6) { - /* non inet6 skip */ - continue; - } -#elif !defined(INET6) - if (ifa->ifa_addr->sa_family != AF_INET) { - /* non inet skip */ - continue; - } -#else - if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) { - /* non inet/inet6 skip */ - continue; - } -#endif -#if defined(INET6) - if ((ifa->ifa_addr->sa_family == AF_INET6) && - IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecified addresses */ - continue; - } -#endif -#if defined(INET) - if (ifa->ifa_addr->sa_family == AF_INET && - ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { - continue; - } -#endif - ifa_flags = 0; - sctp_ifa = sctp_add_addr_to_vrf(vrfid, - NULL, - if_nametoindex(ifa->ifa_name), - 0, - ifa->ifa_name, - NULL, - ifa->ifa_addr, - ifa_flags, - 0); - if (sctp_ifa) { - sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - } - freeifaddrs(ifas); -#endif -} -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -static void -sctp_init_ifns_for_vrf(int vrfid) -{ - /* Here we must apply ANY locks needed by the - * IFN we access and also make sure we lock - * any IFA that exists as we float through the - * list of IFA's - */ - struct ifnet **ifnetlist; - uint32_t i, j, count; - char name[SCTP_IFNAMSIZ]; - struct ifnet *ifn; - struct ifaddr **ifaddrlist; - struct ifaddr *ifa; - struct in6_ifaddr *ifa6; - struct sctp_ifa *sctp_ifa; - uint32_t ifa_flags; - - if (ifnet_list_get(IFNET_FAMILY_ANY, &ifnetlist, &count) != 0) { - return; - } - for (i = 0; i < count; i++) { - ifn = ifnetlist[i]; - if (SCTP_BASE_SYSCTL(sctp_ignore_vmware_interfaces) && sctp_is_vmware_interface(ifn)) { - continue; - } - if (sctp_is_desired_interface_type(ifn) == 0) { - /* non desired type */ - continue; - } - if (ifnet_get_address_list(ifn, &ifaddrlist) != 0) { - continue; - } - for (j = 0; ifaddrlist[j] != NULL; j++) { - ifa = ifaddrlist[j]; - if (ifa->ifa_addr == NULL) { - continue; - } - if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) { - /* non inet/inet6 skip */ - continue; - } - if (ifa->ifa_addr->sa_family == AF_INET6) { - if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecified addresses */ - continue; - } - } else { - if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == INADDR_ANY) { - continue; - } - } - if (ifa->ifa_addr->sa_family == AF_INET6) { - ifa6 = (struct in6_ifaddr *)ifa; - ifa_flags = ifa6->ia6_flags; - } else { - ifa_flags = 0; - } - SCTP_SNPRINTF(name, SCTP_IFNAMSIZ, "%s%d", ifnet_name(ifn), ifnet_unit(ifn)); - sctp_ifa = sctp_add_addr_to_vrf(vrfid, - (void *)ifn, /* XXX */ - ifnet_index(ifn), - ifnet_type(ifn), - name, - (void *)ifa, /* XXX */ - ifa->ifa_addr, - ifa_flags, - 0); - if (sctp_ifa) { - sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - } - ifnet_free_address_list(ifaddrlist); - } - ifnet_list_free(ifnetlist); -} -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -static void -sctp_init_ifns_for_vrf(int vrfid) -{ - /* Here we must apply ANY locks needed by the - * IFN we access and also make sure we lock - * any IFA that exists as we float through the - * list of IFA's - */ - struct epoch_tracker et; - struct ifnet *ifn; - struct ifaddr *ifa; - struct sctp_ifa *sctp_ifa; - uint32_t ifa_flags; -#ifdef INET6 - struct in6_ifaddr *ifa6; -#endif - - IFNET_RLOCK(); - NET_EPOCH_ENTER(et); - CK_STAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { - if (sctp_is_desired_interface_type(ifn) == 0) { - /* non desired type */ - continue; - } - CK_STAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { - if (ifa->ifa_addr == NULL) { - continue; - } - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecified addresses */ - continue; - } - break; -#endif - default: - continue; - } - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - ifa_flags = 0; - break; -#endif -#ifdef INET6 - case AF_INET6: - ifa6 = (struct in6_ifaddr *)ifa; - ifa_flags = ifa6->ia6_flags; - break; -#endif - default: - ifa_flags = 0; - break; - } - sctp_ifa = sctp_add_addr_to_vrf(vrfid, - (void *)ifn, - ifn->if_index, - ifn->if_type, - ifn->if_xname, - (void *)ifa, - ifa->ifa_addr, - ifa_flags, - 0); - if (sctp_ifa) { - sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - } - } - NET_EPOCH_EXIT(et); - IFNET_RUNLOCK(); -} -#endif - -void -sctp_init_vrf_list(int vrfid) -{ - if (vrfid > SCTP_MAX_VRF_ID) - /* can't do that */ - return; - - /* Don't care about return here */ - (void)sctp_allocate_vrf(vrfid); - - /* Now we need to build all the ifn's - * for this vrf and there addresses - */ - sctp_init_ifns_for_vrf(vrfid); -} - -void -sctp_addr_change(struct ifaddr *ifa, int cmd) -{ -#if defined(__Userspace__) - return; -#else - uint32_t ifa_flags = 0; - - if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { - return; - } - /* BSD only has one VRF, if this changes - * we will need to hook in the right - * things here to get the id to pass to - * the address management routine. - */ - if (SCTP_BASE_VAR(first_time) == 0) { - /* Special test to see if my ::1 will showup with this */ - SCTP_BASE_VAR(first_time) = 1; - sctp_init_ifns_for_vrf(SCTP_DEFAULT_VRFID); - } - - if ((cmd != RTM_ADD) && (cmd != RTM_DELETE)) { - /* don't know what to do with this */ - return; - } - - if (ifa->ifa_addr == NULL) { - return; - } - if (sctp_is_desired_interface_type(ifa->ifa_ifp) == 0) { - /* non desired type */ - return; - } - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { - return; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags; - if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - /* skip unspecified addresses */ - return; - } - break; -#endif - default: - /* non inet/inet6 skip */ - return; - } - if (cmd == RTM_ADD) { - (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp, -#if defined(__APPLE__) && !defined(__Userspace__) - ifnet_index(ifa->ifa_ifp), ifnet_type(ifa->ifa_ifp), ifnet_name(ifa->ifa_ifp), -#else - ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname, -#endif - (void *)ifa, ifa->ifa_addr, ifa_flags, 1); - } else { - sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, -#if defined(__APPLE__) && !defined(__Userspace__) - ifnet_index(ifa->ifa_ifp), - ifnet_name(ifa->ifa_ifp)); -#else - ifa->ifa_ifp->if_index, - ifa->ifa_ifp->if_xname); -#endif - - /* We don't bump refcount here so when it completes - * the final delete will happen. - */ - } -#endif -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -void -sctp_addr_change_event_handler(void *arg __unused, struct ifaddr *ifa, int cmd) { - sctp_addr_change(ifa, cmd); -} -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -void -sctp_add_or_del_interfaces(int (*pred)(struct ifnet *), int add) -{ - struct ifnet **ifnetlist; - struct ifaddr **ifaddrlist; - uint32_t i, j, count; - - if (ifnet_list_get(IFNET_FAMILY_ANY, &ifnetlist, &count) != 0) { - return; - } - for (i = 0; i < count; i++) { - if (!(*pred)(ifnetlist[i])) { - continue; - } - if (ifnet_get_address_list(ifnetlist[i], &ifaddrlist) != 0) { - continue; - } - for (j = 0; ifaddrlist[j] != NULL; j++) { - sctp_addr_change(ifaddrlist[j], add ? RTM_ADD : RTM_DELETE); - } - ifnet_free_address_list(ifaddrlist); - } - ifnet_list_free(ifnetlist); - return; -} -#endif - -struct mbuf * -sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, - int how, int allonebuf, int type) -{ - struct mbuf *m = NULL; -#if defined(__FreeBSD__) || defined(__Userspace__) -#if defined(__Userspace__) - m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0, allonebuf); -#else - m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); -#endif - if (m == NULL) { - /* bad, no memory */ - return (m); - } -#if !defined(__Userspace__) - if (allonebuf) { - if (SCTP_BUF_SIZE(m) < space_needed) { - m_freem(m); - return (NULL); - } - KASSERT(SCTP_BUF_NEXT(m) == NULL, ("%s: no chain allowed", __func__)); - } -#endif -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mb(m, SCTP_MBUF_IALLOC); - } -#endif -#else - int mbuf_threshold; - unsigned int size; - - if (want_header) { - MGETHDR(m, how, type); - size = MHLEN; - } else { - MGET(m, how, type); - size = MLEN; - } - if (m == NULL) { - return (NULL); - } - if (allonebuf == 0) { - mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count); - } else { - mbuf_threshold = 1; - } - - if (space_needed > (unsigned int)(((mbuf_threshold - 1) * MLEN) + MHLEN)) { - MCLGET(m, how); - if (m == NULL) { - return (NULL); - } - if (SCTP_BUF_IS_EXTENDED(m) == 0) { - sctp_m_freem(m); - return (NULL); - } - size = SCTP_BUF_EXTEND_SIZE(m); - } - if (allonebuf != 0 && size < space_needed) { - m_freem(m); - return (NULL); - } - SCTP_BUF_LEN(m) = 0; - SCTP_BUF_NEXT(m) = SCTP_BUF_NEXT_PKT(m) = NULL; -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mb(m, SCTP_MBUF_IALLOC); - } -#endif -#endif - return (m); -} - -#ifdef SCTP_PACKET_LOGGING -void -sctp_packet_log(struct mbuf *m) -{ - int *lenat, thisone; - void *copyto; - uint32_t *tick_tock; - int length; - int total_len; - int grabbed_lock = 0; - int value, newval, thisend, thisbegin; - /* - * Buffer layout. - * -sizeof this entry (total_len) - * -previous end (value) - * -ticks of log (ticks) - * o -ip packet - * o -as logged - * - where this started (thisbegin) - * x <--end points here - */ - length = SCTP_HEADER_LEN(m); - total_len = SCTP_SIZE32((length + (4 * sizeof(int)))); - /* Log a packet to the buffer. */ - if (total_len> SCTP_PACKET_LOG_SIZE) { - /* Can't log this packet I have not a buffer big enough */ - return; - } - if (length < (int)(SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))) { - return; - } - atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), 1); - try_again: - if (SCTP_BASE_VAR(packet_log_writers) > SCTP_PKTLOG_WRITERS_NEED_LOCK) { - SCTP_IP_PKTLOG_LOCK(); - grabbed_lock = 1; - again_locked: - value = SCTP_BASE_VAR(packet_log_end); - newval = SCTP_BASE_VAR(packet_log_end) + total_len; - if (newval >= SCTP_PACKET_LOG_SIZE) { - /* we wrapped */ - thisbegin = 0; - thisend = total_len; - } else { - thisbegin = SCTP_BASE_VAR(packet_log_end); - thisend = newval; - } - if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) { - goto again_locked; - } - } else { - value = SCTP_BASE_VAR(packet_log_end); - newval = SCTP_BASE_VAR(packet_log_end) + total_len; - if (newval >= SCTP_PACKET_LOG_SIZE) { - /* we wrapped */ - thisbegin = 0; - thisend = total_len; - } else { - thisbegin = SCTP_BASE_VAR(packet_log_end); - thisend = newval; - } - if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) { - goto try_again; - } - } - /* Sanity check */ - if (thisend >= SCTP_PACKET_LOG_SIZE) { - SCTP_PRINTF("Insanity stops a log thisbegin:%d thisend:%d writers:%d lock:%d end:%d\n", - thisbegin, - thisend, - SCTP_BASE_VAR(packet_log_writers), - grabbed_lock, - SCTP_BASE_VAR(packet_log_end)); - SCTP_BASE_VAR(packet_log_end) = 0; - goto no_log; - } - lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisbegin]; - *lenat = total_len; - lenat++; - *lenat = value; - lenat++; - tick_tock = (uint32_t *)lenat; - lenat++; - *tick_tock = sctp_get_tick_count(); - copyto = (void *)lenat; - thisone = thisend - sizeof(int); - lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisone]; - *lenat = thisbegin; - if (grabbed_lock) { - SCTP_IP_PKTLOG_UNLOCK(); - grabbed_lock = 0; - } - m_copydata(m, 0, length, (caddr_t)copyto); - no_log: - if (grabbed_lock) { - SCTP_IP_PKTLOG_UNLOCK(); - } - atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), 1); -} - -int -sctp_copy_out_packet_log(uint8_t *target, int length) -{ - /* We wind through the packet log starting at - * start copying up to length bytes out. - * We return the number of bytes copied. - */ - int this_copy; - int *lenat; - int did_delay = 0; - - if (length < (int)(2 * sizeof(int))) { - /* not enough room */ - return (0); - } - if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { - atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), SCTP_PKTLOG_WRITERS_NEED_LOCK); - again: - if ((did_delay == 0) && (SCTP_BASE_VAR(packet_log_writers) != SCTP_PKTLOG_WRITERS_NEED_LOCK)) { - /* we delay here for just a moment hoping the writer(s) that were - * present when we entered will have left and we only have - * locking ones that will contend with us for the lock. This - * does not assure 100% access, but its good enough for - * a logging facility like this. - */ - did_delay = 1; - DELAY(10); - goto again; - } - } - SCTP_IP_PKTLOG_LOCK(); - lenat = (int *)target; - *lenat = SCTP_BASE_VAR(packet_log_end); - lenat++; - this_copy = min((length - sizeof(int)), SCTP_PACKET_LOG_SIZE); - memcpy((void *)lenat, (void *)SCTP_BASE_VAR(packet_log_buffer), this_copy); - if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { - atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), - SCTP_PKTLOG_WRITERS_NEED_LOCK); - } - SCTP_IP_PKTLOG_UNLOCK(); - return (this_copy + sizeof(int)); -} - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.h deleted file mode 100644 index bbbc933a..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_bsd_addr.h +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_BSD_ADDR_H_ -#define _NETINET_SCTP_BSD_ADDR_H_ - -#include - -#if defined(_KERNEL) || defined(__Userspace__) - -extern struct iterator_control sctp_it_ctl; -void sctp_wakeup_iterator(void); - -void sctp_startup_iterator(void); - -#ifdef INET6 -void sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa); -#endif - -#ifdef SCTP_PACKET_LOGGING - -void sctp_packet_log(struct mbuf *m); -int sctp_copy_out_packet_log(uint8_t *target, int length); - -#endif - -void sctp_addr_change(struct ifaddr *ifa, int cmd); -#if defined(__FreeBSD__) && !defined(__Userspace__) - -void sctp_addr_change_event_handler(void *, struct ifaddr *, int); -#endif - -void sctp_add_or_del_interfaces(int (*pred)(struct ifnet *), int add); - -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.c deleted file mode 100644 index ee6cd4cd..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.c +++ /dev/null @@ -1,249 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__Userspace__) -#include -#if !defined(_WIN32) -#include -#include -#include -#endif -#if defined(__native_client__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#endif -#include - -/* - * Callout/Timer routines for OS that doesn't have them - */ -#if defined(__APPLE__) || defined(__Userspace__) -static uint32_t ticks = 0; -#else -extern int ticks; -#endif - -uint32_t sctp_get_tick_count(void) { - uint32_t ret; - - SCTP_TIMERQ_LOCK(); - ret = ticks; - SCTP_TIMERQ_UNLOCK(); - return ret; -} - -/* - * SCTP_TIMERQ_LOCK protects: - * - SCTP_BASE_INFO(callqueue) - * - sctp_os_timer_next: next timer to check - */ -static sctp_os_timer_t *sctp_os_timer_next = NULL; - -void -sctp_os_timer_init(sctp_os_timer_t *c) -{ - memset(c, 0, sizeof(*c)); -} - -int -sctp_os_timer_start(sctp_os_timer_t *c, uint32_t to_ticks, void (*ftn) (void *), - void *arg) -{ - int ret = 0; - - /* paranoia */ - if ((c == NULL) || (ftn == NULL)) - return (ret); - - SCTP_TIMERQ_LOCK(); - /* check to see if we're rescheduling a timer */ - if (c->c_flags & SCTP_CALLOUT_PENDING) { - ret = 1; - if (c == sctp_os_timer_next) { - sctp_os_timer_next = TAILQ_NEXT(c, tqe); - } - TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); - /* - * part of the normal "stop a pending callout" process - * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING - * flags. We don't bother since we are setting these - * below and we still hold the lock. - */ - } - - /* - * We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL, - * but there's no point since doing this setup doesn't take much time. - */ - if (to_ticks == 0) - to_ticks = 1; - - c->c_arg = arg; - c->c_flags = (SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING); - c->c_func = ftn; - c->c_time = ticks + to_ticks; - TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe); - SCTP_TIMERQ_UNLOCK(); - return (ret); -} - -int -sctp_os_timer_stop(sctp_os_timer_t *c) -{ - SCTP_TIMERQ_LOCK(); - /* - * Don't attempt to delete a callout that's not on the queue. - */ - if ((c->c_flags & SCTP_CALLOUT_PENDING) == 0) { - c->c_flags &= ~SCTP_CALLOUT_ACTIVE; - SCTP_TIMERQ_UNLOCK(); - return (0); - } - c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING); - if (c == sctp_os_timer_next) { - sctp_os_timer_next = TAILQ_NEXT(c, tqe); - } - TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); - SCTP_TIMERQ_UNLOCK(); - return (1); -} - -void -sctp_handle_tick(uint32_t elapsed_ticks) -{ - sctp_os_timer_t *c; - void (*c_func)(void *); - void *c_arg; - - SCTP_TIMERQ_LOCK(); - /* update our tick count */ - ticks += elapsed_ticks; - c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue)); - while (c) { - if (SCTP_UINT32_GE(ticks, c->c_time)) { - sctp_os_timer_next = TAILQ_NEXT(c, tqe); - TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); - c_func = c->c_func; - c_arg = c->c_arg; - c->c_flags &= ~SCTP_CALLOUT_PENDING; - SCTP_TIMERQ_UNLOCK(); - c_func(c_arg); - SCTP_TIMERQ_LOCK(); - c = sctp_os_timer_next; - } else { - c = TAILQ_NEXT(c, tqe); - } - } - sctp_os_timer_next = NULL; - SCTP_TIMERQ_UNLOCK(); -} - -#if defined(__APPLE__) && !defined(__Userspace__) -void -sctp_timeout(void *arg SCTP_UNUSED) -{ - sctp_handle_tick(SCTP_BASE_VAR(sctp_main_timer_ticks)); - sctp_start_main_timer(); -} -#endif - -#if defined(__Userspace__) -#define TIMEOUT_INTERVAL 10 - -void * -user_sctp_timer_iterate(void *arg) -{ - sctp_userspace_set_threadname("SCTP timer"); - for (;;) { -#if defined(_WIN32) - Sleep(TIMEOUT_INTERVAL); -#else - struct timespec amount, remaining; - - remaining.tv_sec = 0; - remaining.tv_nsec = TIMEOUT_INTERVAL * 1000 * 1000; - do { - amount = remaining; - } while (nanosleep(&amount, &remaining) == -1); -#endif - if (atomic_cmpset_int(&SCTP_BASE_VAR(timer_thread_should_exit), 1, 1)) { - break; - } - sctp_handle_tick(sctp_msecs_to_ticks(TIMEOUT_INTERVAL)); - } - return (NULL); -} - -void -sctp_start_timer_thread(void) -{ - /* - * No need to do SCTP_TIMERQ_LOCK_INIT(); - * here, it is being done in sctp_pcb_init() - */ - int rc; - - rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(timer_thread), user_sctp_timer_iterate); - if (rc) { - SCTP_PRINTF("ERROR; return code from sctp_thread_create() is %d\n", rc); - } else { - SCTP_BASE_VAR(timer_thread_started) = 1; - } -} - -void -sctp_stop_timer_thread(void) -{ - atomic_cmpset_int(&SCTP_BASE_VAR(timer_thread_should_exit), 0, 1); - if (SCTP_BASE_VAR(timer_thread_started)) { -#if defined(_WIN32) - WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE); - CloseHandle(SCTP_BASE_VAR(timer_thread)); -#else - pthread_join(SCTP_BASE_VAR(timer_thread), NULL); -#endif - } -} -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.h deleted file mode 100644 index 81fd8530..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_callout.h +++ /dev/null @@ -1,119 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_CALLOUT_ -#define _NETINET_SCTP_CALLOUT_ - -/* - * NOTE: the following MACROS are required for locking the callout - * queue along with a lock/mutex in the OS specific headers and - * implementation files:: - * - SCTP_TIMERQ_LOCK() - * - SCTP_TIMERQ_UNLOCK() - * - SCTP_TIMERQ_LOCK_INIT() - * - SCTP_TIMERQ_LOCK_DESTROY() - */ - -#define _SCTP_NEEDS_CALLOUT_ 1 - -#define SCTP_TICKS_PER_FASTTIMO 20 /* called about every 20ms */ - -#if defined(__Userspace__) -#if defined(_WIN32) -#define SCTP_TIMERQ_LOCK() EnterCriticalSection(&SCTP_BASE_VAR(timer_mtx)) -#define SCTP_TIMERQ_UNLOCK() LeaveCriticalSection(&SCTP_BASE_VAR(timer_mtx)) -#define SCTP_TIMERQ_LOCK_INIT() InitializeCriticalSection(&SCTP_BASE_VAR(timer_mtx)) -#define SCTP_TIMERQ_LOCK_DESTROY() DeleteCriticalSection(&SCTP_BASE_VAR(timer_mtx)) -#else -#ifdef INVARIANTS -#define SCTP_TIMERQ_LOCK() KASSERT(pthread_mutex_lock(&SCTP_BASE_VAR(timer_mtx)) == 0, ("%s: timer_mtx already locked", __func__)) -#define SCTP_TIMERQ_UNLOCK() KASSERT(pthread_mutex_unlock(&SCTP_BASE_VAR(timer_mtx)) == 0, ("%s: timer_mtx not locked", __func__)) -#else -#define SCTP_TIMERQ_LOCK() (void)pthread_mutex_lock(&SCTP_BASE_VAR(timer_mtx)) -#define SCTP_TIMERQ_UNLOCK() (void)pthread_mutex_unlock(&SCTP_BASE_VAR(timer_mtx)) -#endif -#define SCTP_TIMERQ_LOCK_INIT() (void)pthread_mutex_init(&SCTP_BASE_VAR(timer_mtx), &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_TIMERQ_LOCK_DESTROY() (void)pthread_mutex_destroy(&SCTP_BASE_VAR(timer_mtx)) -#endif -#endif - -uint32_t sctp_get_tick_count(void); - -TAILQ_HEAD(calloutlist, sctp_callout); - -struct sctp_callout { - TAILQ_ENTRY(sctp_callout) tqe; - uint32_t c_time; /* ticks to the event */ - void *c_arg; /* function argument */ - void (*c_func)(void *); /* function to call */ - int c_flags; /* state of this entry */ -}; -typedef struct sctp_callout sctp_os_timer_t; - -#define SCTP_CALLOUT_ACTIVE 0x0002 /* callout is currently active */ -#define SCTP_CALLOUT_PENDING 0x0004 /* callout is waiting for timeout */ - -void sctp_os_timer_init(sctp_os_timer_t *tmr); -/* Returns 1 if pending timer was rescheduled, 0 otherwise. */ -int sctp_os_timer_start(sctp_os_timer_t *, uint32_t, void (*)(void *), void *); -/* Returns 1 if pending timer was stopped, 0 otherwise. */ -int sctp_os_timer_stop(sctp_os_timer_t *); -void sctp_handle_tick(uint32_t); - -#define SCTP_OS_TIMER_INIT sctp_os_timer_init -/* - * NOTE: The next two shouldn't be called directly outside of sctp_timer_start() - * and sctp_timer_stop(), since they don't handle incrementing/decrementing - * relevant reference counts. - */ -#define SCTP_OS_TIMER_START sctp_os_timer_start -#define SCTP_OS_TIMER_STOP sctp_os_timer_stop -/* MT FIXME: Is the following correct? */ -#define SCTP_OS_TIMER_STOP_DRAIN SCTP_OS_TIMER_STOP -#define SCTP_OS_TIMER_PENDING(tmr) ((tmr)->c_flags & SCTP_CALLOUT_PENDING) -#define SCTP_OS_TIMER_ACTIVE(tmr) ((tmr)->c_flags & SCTP_CALLOUT_ACTIVE) -#define SCTP_OS_TIMER_DEACTIVATE(tmr) ((tmr)->c_flags &= ~SCTP_CALLOUT_ACTIVE) - -#if defined(__Userspace__) -void sctp_start_timer_thread(void); -void sctp_stop_timer_thread(void); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -void sctp_timeout(void *); -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_cc_functions.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_cc_functions.c deleted file mode 100644 index bf2ba8ab..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_cc_functions.c +++ /dev/null @@ -1,2493 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif - -#define SHIFT_MPTCP_MULTI_N 40 -#define SHIFT_MPTCP_MULTI_Z 16 -#define SHIFT_MPTCP_MULTI 8 - -static void -sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net) -{ - if ((assoc->max_cwnd > 0) && - (net->cwnd > assoc->max_cwnd) && - (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) { - net->cwnd = assoc->max_cwnd; - if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { - net->cwnd = net->mtu - sizeof(struct sctphdr); - } - } -} - -static void -sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - struct sctp_association *assoc; - uint32_t cwnd_in_mtu; - - assoc = &stcb->asoc; - cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); - if (cwnd_in_mtu == 0) { - /* Using 0 means that the value of RFC 4960 is used. */ - net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); - } else { - /* - * We take the minimum of the burst limit and the - * initial congestion window. - */ - if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst)) - cwnd_in_mtu = assoc->max_burst; - net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; - } - if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || - (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { - /* In case of resource pooling initialize appropriately */ - net->cwnd /= assoc->numnets; - if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { - net->cwnd = net->mtu - sizeof(struct sctphdr); - } - } - sctp_enforce_cwnd_limit(assoc, net); - net->ssthresh = assoc->peers_rwnd; -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, init, - stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, - 0, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & - (SCTP_CWND_MONITOR_ENABLE|SCTP_CWND_LOGGING_ENABLE)) { - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); - } -} - -static void -sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, - struct sctp_association *asoc) -{ - struct sctp_nets *net; - uint32_t t_ssthresh, t_cwnd; - uint64_t t_ucwnd_sbw; - - /* MT FIXME: Don't compute this over and over again */ - t_ssthresh = 0; - t_cwnd = 0; - t_ucwnd_sbw = 0; - if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || - (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - t_ssthresh += net->ssthresh; - t_cwnd += net->cwnd; - if (net->lastsa > 0) { - t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)net->lastsa; - } - } - if (t_ucwnd_sbw == 0) { - t_ucwnd_sbw = 1; - } - } - - /*- - * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && - * (net->fast_retran_loss_recovery == 0))) - */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((asoc->fast_retran_loss_recovery == 0) || - (asoc->sctp_cmt_on_off > 0)) { - /* out of a RFC2582 Fast recovery window? */ - if (net->net_ack > 0) { - /* - * per section 7.2.3, are there any - * destinations that had a fast retransmit - * to them. If so what we need to do is - * adjust ssthresh and cwnd. - */ - struct sctp_tmit_chunk *lchk; - int old_cwnd = net->cwnd; - - if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || - (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { - if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) { - net->ssthresh = (uint32_t)(((uint64_t)4 * - (uint64_t)net->mtu * - (uint64_t)net->ssthresh) / - (uint64_t)t_ssthresh); - } - if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) { - uint32_t srtt; - - srtt = net->lastsa; - /* lastsa>>3; we don't need to devide ...*/ - if (srtt == 0) { - srtt = 1; - } - /* Short Version => Equal to Contel Version MBe */ - net->ssthresh = (uint32_t) (((uint64_t)4 * - (uint64_t)net->mtu * - (uint64_t)net->cwnd) / - ((uint64_t)srtt * - t_ucwnd_sbw)); - /* INCREASE FACTOR */; - } - if ((net->cwnd > t_cwnd / 2) && - (net->ssthresh < net->cwnd - t_cwnd / 2)) { - net->ssthresh = net->cwnd - t_cwnd / 2; - } - if (net->ssthresh < net->mtu) { - net->ssthresh = net->mtu; - } - } else { - net->ssthresh = net->cwnd / 2; - if (net->ssthresh < (net->mtu * 2)) { - net->ssthresh = 2 * net->mtu; - } - } - net->cwnd = net->ssthresh; - sctp_enforce_cwnd_limit(asoc, net); -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, fr, - stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, - old_cwnd, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), - SCTP_CWND_LOG_FROM_FR); - } - lchk = TAILQ_FIRST(&asoc->send_queue); - - net->partial_bytes_acked = 0; - /* Turn on fast recovery window */ - asoc->fast_retran_loss_recovery = 1; - if (lchk == NULL) { - /* Mark end of the window */ - asoc->fast_recovery_tsn = asoc->sending_seq - 1; - } else { - asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; - } - - /* - * CMT fast recovery -- per destination - * recovery variable. - */ - net->fast_retran_loss_recovery = 1; - - if (lchk == NULL) { - /* Mark end of the window */ - net->fast_recovery_tsn = asoc->sending_seq - 1; - } else { - net->fast_recovery_tsn = lchk->rec.data.tsn - 1; - } - - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net); - } - } else if (net->net_ack > 0) { - /* - * Mark a peg that we WOULD have done a cwnd - * reduction but RFC2582 prevented this action. - */ - SCTP_STAT_INCR(sctps_fastretransinrtt); - } - } -} - -/* Defines for instantaneous bw decisions */ -#define SCTP_INST_LOOSING 1 /* Losing to other flows */ -#define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */ -#define SCTP_INST_GAINING 3 /* Gaining, step down possible */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static int -cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, - uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind) -#else -static int -cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nbw, - uint64_t rtt_offset, uint8_t inst_ind) -#endif -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t oth, probepoint; -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) - probepoint = (((uint64_t)net->cwnd) << 32); -#endif - if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { - /* - * rtt increased - * we don't update bw.. so we don't - * update the rtt either. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Probe point 5 */ - probepoint |= ((5 << 16) | 1); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { - if (net->cc_mod.rtcc.last_step_state == 5) - net->cc_mod.rtcc.step_cnt++; - else - net->cc_mod.rtcc.step_cnt = 1; - net->cc_mod.rtcc.last_step_state = 5; - if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || - ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && - ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { - /* Try a step down */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - oth = net->cc_mod.rtcc.vol_reduce; - oth <<= 16; - oth |= net->cc_mod.rtcc.step_cnt; - oth <<= 16; - oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); -#endif - if (net->cwnd > (4 * net->mtu)) { - net->cwnd -= net->mtu; - net->cc_mod.rtcc.vol_reduce++; - } else { - net->cc_mod.rtcc.step_cnt = 0; - } - } - } - return (1); - } - if (net->rtt < net->cc_mod.rtcc.lbw_rtt-rtt_offset) { - /* - * rtt decreased, there could be more room. - * we update both the bw and the rtt here to - * lock this in as a good step down. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Probe point 6 */ - probepoint |= ((6 << 16) | 0); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if (net->cc_mod.rtcc.steady_step) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - oth = net->cc_mod.rtcc.vol_reduce; - oth <<= 16; - oth |= net->cc_mod.rtcc.step_cnt; - oth <<= 16; - oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); -#endif - if ((net->cc_mod.rtcc.last_step_state == 5) && - (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) { - /* Step down worked */ - net->cc_mod.rtcc.step_cnt = 0; - return (1); - } else { - net->cc_mod.rtcc.last_step_state = 6; - net->cc_mod.rtcc.step_cnt = 0; - } - } - net->cc_mod.rtcc.lbw = nbw; - net->cc_mod.rtcc.lbw_rtt = net->rtt; - net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; - if (inst_ind == SCTP_INST_GAINING) - return (1); - else if (inst_ind == SCTP_INST_NEUTRAL) - return (1); - else - return (0); - } - /* Ok bw and rtt remained the same .. no update to any - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Probe point 7 */ - probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { - if (net->cc_mod.rtcc.last_step_state == 5) - net->cc_mod.rtcc.step_cnt++; - else - net->cc_mod.rtcc.step_cnt = 1; - net->cc_mod.rtcc.last_step_state = 5; - if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || - ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && - ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { - /* Try a step down */ - if (net->cwnd > (4 * net->mtu)) { - net->cwnd -= net->mtu; - net->cc_mod.rtcc.vol_reduce++; - return (1); - } else { - net->cc_mod.rtcc.step_cnt = 0; - } - } - } - if (inst_ind == SCTP_INST_GAINING) - return (1); - else if (inst_ind == SCTP_INST_NEUTRAL) - return (1); - else - return ((int)net->cc_mod.rtcc.ret_from_eq); -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static int -cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset, - uint64_t vtag, uint8_t inst_ind) -#else -static int -cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset, - uint8_t inst_ind) -#endif -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t oth, probepoint; -#endif - - /* Bandwidth decreased.*/ -#if defined(__FreeBSD__) && !defined(__Userspace__) - probepoint = (((uint64_t)net->cwnd) << 32); -#endif - if (net->rtt > net->cc_mod.rtcc.lbw_rtt+rtt_offset) { - /* rtt increased */ - /* Did we add more */ - if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) && - (inst_ind != SCTP_INST_LOOSING)) { - /* We caused it maybe.. back off? */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* PROBE POINT 1 */ - probepoint |= ((1 << 16) | 1); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if (net->cc_mod.rtcc.ret_from_eq) { - /* Switch over to CA if we are less aggressive */ - net->ssthresh = net->cwnd-1; - net->partial_bytes_acked = 0; - } - return (1); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Probe point 2 */ - probepoint |= ((2 << 16) | 0); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - /* Someone else - fight for more? */ - if (net->cc_mod.rtcc.steady_step) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - oth = net->cc_mod.rtcc.vol_reduce; - oth <<= 16; - oth |= net->cc_mod.rtcc.step_cnt; - oth <<= 16; - oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); -#endif - /* Did we voluntarily give up some? if so take - * one back please - */ - if ((net->cc_mod.rtcc.vol_reduce) && - (inst_ind != SCTP_INST_GAINING)) { - net->cwnd += net->mtu; - sctp_enforce_cwnd_limit(&stcb->asoc, net); - net->cc_mod.rtcc.vol_reduce--; - } - net->cc_mod.rtcc.last_step_state = 2; - net->cc_mod.rtcc.step_cnt = 0; - } - goto out_decision; - } else if (net->rtt < net->cc_mod.rtcc.lbw_rtt-rtt_offset) { - /* bw & rtt decreased */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Probe point 3 */ - probepoint |= ((3 << 16) | 0); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if (net->cc_mod.rtcc.steady_step) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - oth = net->cc_mod.rtcc.vol_reduce; - oth <<= 16; - oth |= net->cc_mod.rtcc.step_cnt; - oth <<= 16; - oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); -#endif - if ((net->cc_mod.rtcc.vol_reduce) && - (inst_ind != SCTP_INST_GAINING)) { - net->cwnd += net->mtu; - sctp_enforce_cwnd_limit(&stcb->asoc, net); - net->cc_mod.rtcc.vol_reduce--; - } - net->cc_mod.rtcc.last_step_state = 3; - net->cc_mod.rtcc.step_cnt = 0; - } - goto out_decision; - } - /* The bw decreased but rtt stayed the same */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Probe point 4 */ - probepoint |= ((4 << 16) | 0); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if (net->cc_mod.rtcc.steady_step) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - oth = net->cc_mod.rtcc.vol_reduce; - oth <<= 16; - oth |= net->cc_mod.rtcc.step_cnt; - oth <<= 16; - oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); -#endif - if ((net->cc_mod.rtcc.vol_reduce) && - (inst_ind != SCTP_INST_GAINING)) { - net->cwnd += net->mtu; - sctp_enforce_cwnd_limit(&stcb->asoc, net); - net->cc_mod.rtcc.vol_reduce--; - } - net->cc_mod.rtcc.last_step_state = 4; - net->cc_mod.rtcc.step_cnt = 0; - } -out_decision: - net->cc_mod.rtcc.lbw = nbw; - net->cc_mod.rtcc.lbw_rtt = net->rtt; - net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; - if (inst_ind == SCTP_INST_GAINING) { - return (1); - } else { - return (0); - } -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static int -cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag) -#else -static int -cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nbw) -#endif -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t oth, probepoint; - -#endif - /* BW increased, so update and - * return 0, since all actions in - * our table say to do the normal CC - * update. Note that we pay no attention to - * the inst_ind since our overall sum is increasing. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* PROBE POINT 0 */ - probepoint = (((uint64_t)net->cwnd) << 32); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - if (net->cc_mod.rtcc.steady_step) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - oth = net->cc_mod.rtcc.vol_reduce; - oth <<= 16; - oth |= net->cc_mod.rtcc.step_cnt; - oth <<= 16; - oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE5(sctp, cwnd, net, rttstep, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | nbw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - oth, - probepoint); -#endif - net->cc_mod.rtcc.last_step_state = 0; - net->cc_mod.rtcc.step_cnt = 0; - net->cc_mod.rtcc.vol_reduce = 0; - } - net->cc_mod.rtcc.lbw = nbw; - net->cc_mod.rtcc.lbw_rtt = net->rtt; - net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; - return (0); -} - -/* RTCC Algorithm to limit growth of cwnd, return - * true if you want to NOT allow cwnd growth - */ -static int -cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) -{ - uint64_t bw_offset, rtt_offset; -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t probepoint, rtt, vtag; -#endif - uint64_t bytes_for_this_rtt, inst_bw; - uint64_t div, inst_off; - int bw_shift; - uint8_t inst_ind; - int ret; - /*- - * Here we need to see if we want - * to limit cwnd growth due to increase - * in overall rtt but no increase in bw. - * We use the following table to figure - * out what we should do. When we return - * 0, cc update goes on as planned. If we - * return 1, then no cc update happens and cwnd - * stays where it is at. - * ---------------------------------- - * BW | RTT | Action - * ********************************* - * INC | INC | return 0 - * ---------------------------------- - * INC | SAME | return 0 - * ---------------------------------- - * INC | DECR | return 0 - * ---------------------------------- - * SAME | INC | return 1 - * ---------------------------------- - * SAME | SAME | return 1 - * ---------------------------------- - * SAME | DECR | return 0 - * ---------------------------------- - * DECR | INC | return 0 or 1 based on if we caused. - * ---------------------------------- - * DECR | SAME | return 0 - * ---------------------------------- - * DECR | DECR | return 0 - * ---------------------------------- - * - * We are a bit fuzz on what an increase or - * decrease is. For BW it is the same if - * it did not change within 1/64th. For - * RTT it stayed the same if it did not - * change within 1/32nd - */ - bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw); -#if defined(__FreeBSD__) && !defined(__Userspace__) - rtt = stcb->asoc.my_vtag; - vtag = (rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); - probepoint = (((uint64_t)net->cwnd) << 32); - rtt = net->rtt; -#endif - if (net->cc_mod.rtcc.rtt_set_this_sack) { - net->cc_mod.rtcc.rtt_set_this_sack = 0; - bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc; - net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; - if (net->rtt) { - div = net->rtt / 1000; - if (div) { - inst_bw = bytes_for_this_rtt / div; - inst_off = inst_bw >> bw_shift; - if (inst_bw > nbw) - inst_ind = SCTP_INST_GAINING; - else if ((inst_bw+inst_off) < nbw) - inst_ind = SCTP_INST_LOOSING; - else - inst_ind = SCTP_INST_NEUTRAL; -#if defined(__FreeBSD__) && !defined(__Userspace__) - probepoint |= ((0xb << 16) | inst_ind); -#endif - } else { - inst_ind = net->cc_mod.rtcc.last_inst_ind; -#if defined(__FreeBSD__) && !defined(__Userspace__) - inst_bw = bytes_for_this_rtt / (uint64_t)(net->rtt); - /* Can't determine do not change */ - probepoint |= ((0xc << 16) | inst_ind); -#endif - } - } else { - inst_ind = net->cc_mod.rtcc.last_inst_ind; -#if defined(__FreeBSD__) && !defined(__Userspace__) - inst_bw = bytes_for_this_rtt; - /* Can't determine do not change */ - probepoint |= ((0xd << 16) | inst_ind); -#endif - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((nbw << 32) | inst_bw), - ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), - net->flight_size, - probepoint); -#endif - } else { - /* No rtt measurement, use last one */ - inst_ind = net->cc_mod.rtcc.last_inst_ind; - } - bw_offset = net->cc_mod.rtcc.lbw >> bw_shift; - if (nbw > net->cc_mod.rtcc.lbw + bw_offset) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - ret = cc_bw_increase(stcb, net, nbw, vtag); -#else - ret = cc_bw_increase(stcb, net, nbw); -#endif - goto out; - } - rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt); - if (nbw < net->cc_mod.rtcc.lbw - bw_offset) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind); -#else - ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, inst_ind); -#endif - goto out; - } - /* If we reach here then - * we are in a situation where - * the bw stayed the same. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind); -#else - ret = cc_bw_same(stcb, net, nbw, rtt_offset, inst_ind); -#endif -out: - net->cc_mod.rtcc.last_inst_ind = inst_ind; - return (ret); -} - -static void -sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, - struct sctp_association *asoc, - int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc) -{ - struct sctp_nets *net; -#if defined(__FreeBSD__) && !defined(__Userspace__) - int old_cwnd; -#endif - uint32_t t_ssthresh, incr; - uint64_t t_ucwnd_sbw; - uint64_t t_path_mptcp; - uint64_t mptcp_like_alpha; - uint32_t srtt; - uint64_t max_path; - - /* MT FIXME: Don't compute this over and over again */ - t_ssthresh = 0; - t_ucwnd_sbw = 0; - t_path_mptcp = 0; - mptcp_like_alpha = 1; - if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || - (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) || - (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) { - max_path = 0; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - t_ssthresh += net->ssthresh; - /* lastsa>>3; we don't need to devide ...*/ - srtt = net->lastsa; - if (srtt > 0) { - uint64_t tmp; - - t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)srtt; - t_path_mptcp += (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_Z) / - (((uint64_t)net->mtu) * (uint64_t)srtt); - tmp = (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_N) / - ((uint64_t)net->mtu * (uint64_t)(srtt * srtt)); - if (tmp > max_path) { - max_path = tmp; - } - } - } - if (t_path_mptcp > 0) { - mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp); - } else { - mptcp_like_alpha = 1; - } - } - if (t_ssthresh == 0) { - t_ssthresh = 1; - } - if (t_ucwnd_sbw == 0) { - t_ucwnd_sbw = 1; - } - /******************************/ - /* update cwnd and Early FR */ - /******************************/ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { -#ifdef JANA_CMT_FAST_RECOVERY - /* - * CMT fast recovery code. Need to debug. - */ - if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { - if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || - SCTP_TSN_GE(net->pseudo_cumack,net->fast_recovery_tsn)) { - net->will_exit_fast_recovery = 1; - } - } -#endif - /* if nothing was acked on this destination skip it */ - if (net->net_ack == 0) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); - } - continue; - } -#ifdef JANA_CMT_FAST_RECOVERY - /* CMT fast recovery code - */ - /* - if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery && net->will_exit_fast_recovery == 0) { - @@@ Do something - } - else if (sctp_cmt_on_off == 0 && asoc->fast_retran_loss_recovery && will_exit == 0) { - */ -#endif - - if (asoc->fast_retran_loss_recovery && - (will_exit == 0) && - (asoc->sctp_cmt_on_off == 0)) { - /* - * If we are in loss recovery we skip any cwnd - * update - */ - return; - } - /* - * Did any measurements go on for this network? - */ - if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) { - uint64_t nbw; - /* - * At this point our bw_bytes has been updated - * by incoming sack information. - * - * But our bw may not yet be set. - * - */ - if ((net->cc_mod.rtcc.new_tot_time/1000) > 0) { - nbw = net->cc_mod.rtcc.bw_bytes/(net->cc_mod.rtcc.new_tot_time/1000); - } else { - nbw = net->cc_mod.rtcc.bw_bytes; - } - if (net->cc_mod.rtcc.lbw) { - if (cc_bw_limit(stcb, net, nbw)) { - /* Hold here, no update */ - continue; - } - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t vtag, probepoint; - - probepoint = (((uint64_t)net->cwnd) << 32); - probepoint |= ((0xa << 16) | 0); - vtag = (net->rtt << 32) | - (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | - (stcb->rport); - - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - nbw, - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - net->cc_mod.rtcc.lbw = nbw; - net->cc_mod.rtcc.lbw_rtt = net->rtt; - if (net->cc_mod.rtcc.rtt_set_this_sack) { - net->cc_mod.rtcc.rtt_set_this_sack = 0; - net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; - } - } - } - /* - * CMT: CUC algorithm. Update cwnd if pseudo-cumack has - * moved. - */ - if (accum_moved || - ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { - /* If the cumulative ack moved we can proceed */ - if (net->cwnd <= net->ssthresh) { - /* We are in slow start */ - if (net->flight_size + net->net_ack >= net->cwnd) { - uint32_t limit; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - old_cwnd = net->cwnd; -#endif - switch (asoc->sctp_cmt_on_off) { - case SCTP_CMT_RPV1: - limit = (uint32_t)(((uint64_t)net->mtu * - (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * - (uint64_t)net->ssthresh) / - (uint64_t)t_ssthresh); - incr = (uint32_t)(((uint64_t)net->net_ack * - (uint64_t)net->ssthresh) / - (uint64_t)t_ssthresh); - if (incr > limit) { - incr = limit; - } - if (incr == 0) { - incr = 1; - } - break; - case SCTP_CMT_RPV2: - /* lastsa>>3; we don't need to divide ...*/ - srtt = net->lastsa; - if (srtt == 0) { - srtt = 1; - } - limit = (uint32_t)(((uint64_t)net->mtu * - (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * - (uint64_t)net->cwnd) / - ((uint64_t)srtt * t_ucwnd_sbw)); - /* INCREASE FACTOR */ - incr = (uint32_t)(((uint64_t)net->net_ack * - (uint64_t)net->cwnd) / - ((uint64_t)srtt * t_ucwnd_sbw)); - /* INCREASE FACTOR */ - if (incr > limit) { - incr = limit; - } - if (incr == 0) { - incr = 1; - } - break; - case SCTP_CMT_MPTCP: - limit = (uint32_t)(((uint64_t)net->mtu * - mptcp_like_alpha * - (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >> - SHIFT_MPTCP_MULTI); - incr = (uint32_t)(((uint64_t)net->net_ack * - mptcp_like_alpha) >> - SHIFT_MPTCP_MULTI); - if (incr > limit) { - incr = limit; - } - if (incr > net->net_ack) { - incr = net->net_ack; - } - if (incr > net->mtu) { - incr = net->mtu; - } - break; - default: - incr = net->net_ack; - if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) { - incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable); - } - break; - } - net->cwnd += incr; - sctp_enforce_cwnd_limit(asoc, net); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, incr, - SCTP_CWND_LOG_FROM_SS); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, ack, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); -#endif - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_NOADV_SS); - } - } - } else { - /* We are in congestion avoidance */ - /* - * Add to pba - */ - net->partial_bytes_acked += net->net_ack; - - if ((net->flight_size + net->net_ack >= net->cwnd) && - (net->partial_bytes_acked >= net->cwnd)) { - net->partial_bytes_acked -= net->cwnd; -#if defined(__FreeBSD__) && !defined(__Userspace__) - old_cwnd = net->cwnd; -#endif - switch (asoc->sctp_cmt_on_off) { - case SCTP_CMT_RPV1: - incr = (uint32_t)(((uint64_t)net->mtu * - (uint64_t)net->ssthresh) / - (uint64_t)t_ssthresh); - if (incr == 0) { - incr = 1; - } - break; - case SCTP_CMT_RPV2: - /* lastsa>>3; we don't need to divide ... */ - srtt = net->lastsa; - if (srtt == 0) { - srtt = 1; - } - incr = (uint32_t)((uint64_t)net->mtu * - (uint64_t)net->cwnd / - ((uint64_t)srtt * - t_ucwnd_sbw)); - /* INCREASE FACTOR */ - if (incr == 0) { - incr = 1; - } - break; - case SCTP_CMT_MPTCP: - incr = (uint32_t)((mptcp_like_alpha * - (uint64_t) net->cwnd) >> - SHIFT_MPTCP_MULTI); - if (incr > net->mtu) { - incr = net->mtu; - } - break; - default: - incr = net->mtu; - break; - } - net->cwnd += incr; - sctp_enforce_cwnd_limit(asoc, net); -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, ack, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_FROM_CA); - } - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_NOADV_CA); - } - } - } - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_NO_CUMACK); - } - } - } -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static void -sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) -#else -static void -sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net) -#endif -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - int old_cwnd; - - old_cwnd = net->cwnd; -#endif - net->cwnd = net->mtu; -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, ack, - stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, - old_cwnd, net->cwnd); -#endif - SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", - (void *)net, net->cwnd); -} - -static void -sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - int old_cwnd = net->cwnd; - uint32_t t_ssthresh, t_cwnd; - uint64_t t_ucwnd_sbw; - - /* MT FIXME: Don't compute this over and over again */ - t_ssthresh = 0; - t_cwnd = 0; - if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || - (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { - struct sctp_nets *lnet; - uint32_t srtt; - - t_ucwnd_sbw = 0; - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - t_ssthresh += lnet->ssthresh; - t_cwnd += lnet->cwnd; - srtt = lnet->lastsa; - /* lastsa>>3; we don't need to divide ... */ - if (srtt > 0) { - t_ucwnd_sbw += (uint64_t)lnet->cwnd / (uint64_t)srtt; - } - } - if (t_ssthresh < 1) { - t_ssthresh = 1; - } - if (t_ucwnd_sbw < 1) { - t_ucwnd_sbw = 1; - } - if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) { - net->ssthresh = (uint32_t)(((uint64_t)4 * - (uint64_t)net->mtu * - (uint64_t)net->ssthresh) / - (uint64_t)t_ssthresh); - } else { - uint64_t cc_delta; - - srtt = net->lastsa; - /* lastsa>>3; we don't need to divide ... */ - if (srtt == 0) { - srtt = 1; - } - cc_delta = t_ucwnd_sbw * (uint64_t)srtt / 2; - if (cc_delta < t_cwnd) { - net->ssthresh = (uint32_t)((uint64_t)t_cwnd - cc_delta); - } else { - net->ssthresh = net->mtu; - } - } - if ((net->cwnd > t_cwnd / 2) && - (net->ssthresh < net->cwnd - t_cwnd / 2)) { - net->ssthresh = net->cwnd - t_cwnd / 2; - } - if (net->ssthresh < net->mtu) { - net->ssthresh = net->mtu; - } - } else { - net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); - } - net->cwnd = net->mtu; - net->partial_bytes_acked = 0; -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, to, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); - } -} - -static void -sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net, - int in_window, int num_pkt_lost, int use_rtcc) -{ - int old_cwnd = net->cwnd; - if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) { - /* Data center Congestion Control */ - if (in_window == 0) { - /* Go to CA with the cwnd at the point we sent - * the TSN that was marked with a CE. - */ - if (net->ecn_prev_cwnd < net->cwnd) { - /* Restore to prev cwnd */ - net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost); - } else { - /* Just cut in 1/2 */ - net->cwnd /= 2; - } - /* Drop to CA */ - net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); - } - } else { - /* Further tuning down required over the drastic original cut */ - net->ssthresh -= (net->mtu * num_pkt_lost); - net->cwnd -= (net->mtu * num_pkt_lost); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); - } - } - SCTP_STAT_INCR(sctps_ecnereducedcwnd); - } else { - if (in_window == 0) { - SCTP_STAT_INCR(sctps_ecnereducedcwnd); - net->ssthresh = net->cwnd / 2; - if (net->ssthresh < net->mtu) { - net->ssthresh = net->mtu; - /* here back off the timer as well, to slow us down */ - net->RTO <<= 1; - } - net->cwnd = net->ssthresh; -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, ecn, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); - } - } - } - -} - -static void -sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, - struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, - uint32_t *bottle_bw, uint32_t *on_queue) -{ - uint32_t bw_avail; - unsigned int incr; - int old_cwnd = net->cwnd; - - /* get bottle neck bw */ - *bottle_bw = ntohl(cp->bottle_bw); - /* and whats on queue */ - *on_queue = ntohl(cp->current_onq); - /* - * adjust the on-queue if our flight is more it could be - * that the router has not yet gotten data "in-flight" to it - */ - if (*on_queue < net->flight_size) { - *on_queue = net->flight_size; - } - /* rtt is measured in micro seconds, bottle_bw in bytes per second */ - bw_avail = (uint32_t)(((uint64_t)(*bottle_bw) * net->rtt) / (uint64_t)1000000); - if (bw_avail > *bottle_bw) { - /* - * Cap the growth to no more than the bottle neck. - * This can happen as RTT slides up due to queues. - * It also means if you have more than a 1 second - * RTT with a empty queue you will be limited to the - * bottle_bw per second no matter if other points - * have 1/2 the RTT and you could get more out... - */ - bw_avail = *bottle_bw; - } - if (*on_queue > bw_avail) { - /* - * No room for anything else don't allow anything - * else to be "added to the fire". - */ - int seg_inflight, seg_onqueue, my_portion; - - net->partial_bytes_acked = 0; - /* how much are we over queue size? */ - incr = *on_queue - bw_avail; - if (stcb->asoc.seen_a_sack_this_pkt) { - /* - * undo any cwnd adjustment that the sack - * might have made - */ - net->cwnd = net->prev_cwnd; - } - /* Now how much of that is mine? */ - seg_inflight = net->flight_size / net->mtu; - seg_onqueue = *on_queue / net->mtu; - my_portion = (incr * seg_inflight) / seg_onqueue; - - /* Have I made an adjustment already */ - if (net->cwnd > net->flight_size) { - /* - * for this flight I made an adjustment we - * need to decrease the portion by a share - * our previous adjustment. - */ - int diff_adj; - - diff_adj = net->cwnd - net->flight_size; - if (diff_adj > my_portion) - my_portion = 0; - else - my_portion -= diff_adj; - } - /* - * back down to the previous cwnd (assume we have - * had a sack before this packet). minus what ever - * portion of the overage is my fault. - */ - net->cwnd -= my_portion; - - /* we will NOT back down more than 1 MTU */ - if (net->cwnd <= net->mtu) { - net->cwnd = net->mtu; - } - /* force into CA */ - net->ssthresh = net->cwnd - 1; - } else { - /* - * Take 1/4 of the space left or max burst up .. - * whichever is less. - */ - incr = (bw_avail - *on_queue) >> 2; - if ((stcb->asoc.max_burst > 0) && - (stcb->asoc.max_burst * net->mtu < incr)) { - incr = stcb->asoc.max_burst * net->mtu; - } - net->cwnd += incr; - } - if (net->cwnd > bw_avail) { - /* We can't exceed the pipe size */ - net->cwnd = bw_avail; - } - if (net->cwnd < net->mtu) { - /* We always have 1 MTU */ - net->cwnd = net->mtu; - } - sctp_enforce_cwnd_limit(&stcb->asoc, net); - if (net->cwnd - old_cwnd != 0) { - /* log only changes */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, pd, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), - SCTP_CWND_LOG_FROM_SAT); - } - } -} - -static void -sctp_cwnd_update_after_output(struct sctp_tcb *stcb, - struct sctp_nets *net, int burst_limit) -{ - int old_cwnd = net->cwnd; - - if (net->ssthresh < net->cwnd) - net->ssthresh = net->cwnd; - if (burst_limit) { - net->cwnd = (net->flight_size + (burst_limit * net->mtu)); - sctp_enforce_cwnd_limit(&stcb->asoc, net); -#if defined(__FreeBSD__) && !defined(__Userspace__) - SDT_PROBE5(sctp, cwnd, net, bl, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); - } - } -} - -static void -sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, - struct sctp_association *asoc, - int accum_moved, int reneged_all, int will_exit) -{ - /* Passing a zero argument in last disables the rtcc algorithm */ - sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0); -} - -static void -sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, - int in_window, int num_pkt_lost) -{ - /* Passing a zero argument in last disables the rtcc algorithm */ - sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0); -} - -/* Here starts the RTCCVAR type CC invented by RRS which - * is a slight mod to RFC2581. We reuse a common routine or - * two since these algorithms are so close and need to - * remain the same. - */ -static void -sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, - int in_window, int num_pkt_lost) -{ - sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1); -} - -static void sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net, - struct sctp_tmit_chunk *tp1) -{ - net->cc_mod.rtcc.bw_bytes += tp1->send_size; -} - -static void -sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED, - struct sctp_nets *net) -{ - if (net->cc_mod.rtcc.tls_needs_set > 0) { - /* We had a bw measurement going on */ - struct timeval ltls; - SCTP_GETPTIME_TIMEVAL(<ls); - timevalsub(<ls, &net->cc_mod.rtcc.tls); - net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec; - } -} - -static void -sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, - struct sctp_nets *net) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t vtag, probepoint; - -#endif - if (net->cc_mod.rtcc.lbw) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Clear the old bw.. we went to 0 in-flight */ - vtag = (net->rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | - (stcb->rport); - probepoint = (((uint64_t)net->cwnd) << 32); - /* Probe point 8 */ - probepoint |= ((8 << 16) | 0); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - ((net->cc_mod.rtcc.lbw << 32) | 0), - ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), - net->flight_size, - probepoint); -#endif - net->cc_mod.rtcc.lbw_rtt = 0; - net->cc_mod.rtcc.cwnd_at_bw_set = 0; - net->cc_mod.rtcc.lbw = 0; - net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; - net->cc_mod.rtcc.vol_reduce = 0; - net->cc_mod.rtcc.bw_tot_time = 0; - net->cc_mod.rtcc.bw_bytes = 0; - net->cc_mod.rtcc.tls_needs_set = 0; - if (net->cc_mod.rtcc.steady_step) { - net->cc_mod.rtcc.vol_reduce = 0; - net->cc_mod.rtcc.step_cnt = 0; - net->cc_mod.rtcc.last_step_state = 0; - } - if (net->cc_mod.rtcc.ret_from_eq) { - /* less aggressive one - reset cwnd too */ - uint32_t cwnd_in_mtu, cwnd; - - cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); - if (cwnd_in_mtu == 0) { - /* Using 0 means that the value of RFC 4960 is used. */ - cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); - } else { - /* - * We take the minimum of the burst limit and the - * initial congestion window. - */ - if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst)) - cwnd_in_mtu = stcb->asoc.max_burst; - cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; - } - if (net->cwnd > cwnd) { - /* Only set if we are not a timeout (i.e. down to 1 mtu) */ - net->cwnd = cwnd; - } - } - } -} - -static void -sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, - struct sctp_nets *net) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint64_t vtag, probepoint; - -#endif - sctp_set_initial_cc_param(stcb, net); - stcb->asoc.use_precise_time = 1; -#if defined(__FreeBSD__) && !defined(__Userspace__) - probepoint = (((uint64_t)net->cwnd) << 32); - probepoint |= ((9 << 16) | 0); - vtag = (net->rtt << 32) | - (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | - (stcb->rport); - SDT_PROBE5(sctp, cwnd, net, rttvar, - vtag, - 0, - 0, - 0, - probepoint); -#endif - net->cc_mod.rtcc.lbw_rtt = 0; - net->cc_mod.rtcc.cwnd_at_bw_set = 0; - net->cc_mod.rtcc.vol_reduce = 0; - net->cc_mod.rtcc.lbw = 0; - net->cc_mod.rtcc.vol_reduce = 0; - net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; - net->cc_mod.rtcc.bw_tot_time = 0; - net->cc_mod.rtcc.bw_bytes = 0; - net->cc_mod.rtcc.tls_needs_set = 0; - net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret); - net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step); - net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn); - net->cc_mod.rtcc.step_cnt = 0; - net->cc_mod.rtcc.last_step_state = 0; -} - -static int -sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget, - struct sctp_cc_option *cc_opt) -{ - struct sctp_nets *net; - - if (setorget == 1) { - /* a set */ - if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { - if ((cc_opt->aid_value.assoc_value != 0) && - (cc_opt->aid_value.assoc_value != 1)) { - return (EINVAL); - } - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value; - } - } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { - if ((cc_opt->aid_value.assoc_value != 0) && - (cc_opt->aid_value.assoc_value != 1)) { - return (EINVAL); - } - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value; - } - } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value; - } - } else { - return (EINVAL); - } - } else { - /* a get */ - if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { - net = TAILQ_FIRST(&stcb->asoc.nets); - if (net == NULL) { - return (EFAULT); - } - cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq; - } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { - net = TAILQ_FIRST(&stcb->asoc.nets); - if (net == NULL) { - return (EFAULT); - } - cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn; - } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { - net = TAILQ_FIRST(&stcb->asoc.nets); - if (net == NULL) { - return (EFAULT); - } - cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step; - } else { - return (EINVAL); - } - } - return (0); -} - -static void -sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED, - struct sctp_nets *net) -{ - if (net->cc_mod.rtcc.tls_needs_set == 0) { - SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls); - net->cc_mod.rtcc.tls_needs_set = 2; - } -} - -static void -sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb, - struct sctp_association *asoc, - int accum_moved, int reneged_all, int will_exit) -{ - /* Passing a one argument at the last enables the rtcc algorithm */ - sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1); -} - -static void -sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED, - struct sctp_nets *net, - struct timeval *now SCTP_UNUSED) -{ - net->cc_mod.rtcc.rtt_set_this_sack = 1; -} - -/* Here starts Sally Floyds HS-TCP */ - -struct sctp_hs_raise_drop { - int32_t cwnd; - int8_t increase; - int8_t drop_percent; -}; - -#define SCTP_HS_TABLE_SIZE 73 - -static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { - {38, 1, 50}, /* 0 */ - {118, 2, 44}, /* 1 */ - {221, 3, 41}, /* 2 */ - {347, 4, 38}, /* 3 */ - {495, 5, 37}, /* 4 */ - {663, 6, 35}, /* 5 */ - {851, 7, 34}, /* 6 */ - {1058, 8, 33}, /* 7 */ - {1284, 9, 32}, /* 8 */ - {1529, 10, 31}, /* 9 */ - {1793, 11, 30}, /* 10 */ - {2076, 12, 29}, /* 11 */ - {2378, 13, 28}, /* 12 */ - {2699, 14, 28}, /* 13 */ - {3039, 15, 27}, /* 14 */ - {3399, 16, 27}, /* 15 */ - {3778, 17, 26}, /* 16 */ - {4177, 18, 26}, /* 17 */ - {4596, 19, 25}, /* 18 */ - {5036, 20, 25}, /* 19 */ - {5497, 21, 24}, /* 20 */ - {5979, 22, 24}, /* 21 */ - {6483, 23, 23}, /* 22 */ - {7009, 24, 23}, /* 23 */ - {7558, 25, 22}, /* 24 */ - {8130, 26, 22}, /* 25 */ - {8726, 27, 22}, /* 26 */ - {9346, 28, 21}, /* 27 */ - {9991, 29, 21}, /* 28 */ - {10661, 30, 21}, /* 29 */ - {11358, 31, 20}, /* 30 */ - {12082, 32, 20}, /* 31 */ - {12834, 33, 20}, /* 32 */ - {13614, 34, 19}, /* 33 */ - {14424, 35, 19}, /* 34 */ - {15265, 36, 19}, /* 35 */ - {16137, 37, 19}, /* 36 */ - {17042, 38, 18}, /* 37 */ - {17981, 39, 18}, /* 38 */ - {18955, 40, 18}, /* 39 */ - {19965, 41, 17}, /* 40 */ - {21013, 42, 17}, /* 41 */ - {22101, 43, 17}, /* 42 */ - {23230, 44, 17}, /* 43 */ - {24402, 45, 16}, /* 44 */ - {25618, 46, 16}, /* 45 */ - {26881, 47, 16}, /* 46 */ - {28193, 48, 16}, /* 47 */ - {29557, 49, 15}, /* 48 */ - {30975, 50, 15}, /* 49 */ - {32450, 51, 15}, /* 50 */ - {33986, 52, 15}, /* 51 */ - {35586, 53, 14}, /* 52 */ - {37253, 54, 14}, /* 53 */ - {38992, 55, 14}, /* 54 */ - {40808, 56, 14}, /* 55 */ - {42707, 57, 13}, /* 56 */ - {44694, 58, 13}, /* 57 */ - {46776, 59, 13}, /* 58 */ - {48961, 60, 13}, /* 59 */ - {51258, 61, 13}, /* 60 */ - {53677, 62, 12}, /* 61 */ - {56230, 63, 12}, /* 62 */ - {58932, 64, 12}, /* 63 */ - {61799, 65, 12}, /* 64 */ - {64851, 66, 11}, /* 65 */ - {68113, 67, 11}, /* 66 */ - {71617, 68, 11}, /* 67 */ - {75401, 69, 10}, /* 68 */ - {79517, 70, 10}, /* 69 */ - {84035, 71, 10}, /* 70 */ - {89053, 72, 10}, /* 71 */ - {94717, 73, 9} /* 72 */ -}; - -static void -sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - int cur_val, i, indx, incr; - int old_cwnd = net->cwnd; - - cur_val = net->cwnd >> 10; - indx = SCTP_HS_TABLE_SIZE - 1; - - if (cur_val < sctp_cwnd_adjust[0].cwnd) { - /* normal mode */ - if (net->net_ack > net->mtu) { - net->cwnd += net->mtu; - } else { - net->cwnd += net->net_ack; - } - } else { - for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { - if (cur_val < sctp_cwnd_adjust[i].cwnd) { - indx = i; - break; - } - } - net->last_hs_used = indx; - incr = (((int32_t)sctp_cwnd_adjust[indx].increase) << 10); - net->cwnd += incr; - } - sctp_enforce_cwnd_limit(&stcb->asoc, net); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS); - } -} - -static void -sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - int cur_val, i, indx; - int old_cwnd = net->cwnd; - - cur_val = net->cwnd >> 10; - if (cur_val < sctp_cwnd_adjust[0].cwnd) { - /* normal mode */ - net->ssthresh = net->cwnd / 2; - if (net->ssthresh < (net->mtu * 2)) { - net->ssthresh = 2 * net->mtu; - } - net->cwnd = net->ssthresh; - } else { - /* drop by the proper amount */ - net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * - (int32_t)sctp_cwnd_adjust[net->last_hs_used].drop_percent); - net->cwnd = net->ssthresh; - /* now where are we */ - indx = net->last_hs_used; - cur_val = net->cwnd >> 10; - /* reset where we are in the table */ - if (cur_val < sctp_cwnd_adjust[0].cwnd) { - /* feel out of hs */ - net->last_hs_used = 0; - } else { - for (i = indx; i >= 1; i--) { - if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { - break; - } - } - net->last_hs_used = indx; - } - } - sctp_enforce_cwnd_limit(&stcb->asoc, net); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); - } -} - -static void -sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, - struct sctp_association *asoc) -{ - struct sctp_nets *net; - /* - * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && - * (net->fast_retran_loss_recovery == 0))) - */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((asoc->fast_retran_loss_recovery == 0) || - (asoc->sctp_cmt_on_off > 0)) { - /* out of a RFC2582 Fast recovery window? */ - if (net->net_ack > 0) { - /* - * per section 7.2.3, are there any - * destinations that had a fast retransmit - * to them. If so what we need to do is - * adjust ssthresh and cwnd. - */ - struct sctp_tmit_chunk *lchk; - - sctp_hs_cwnd_decrease(stcb, net); - - lchk = TAILQ_FIRST(&asoc->send_queue); - - net->partial_bytes_acked = 0; - /* Turn on fast recovery window */ - asoc->fast_retran_loss_recovery = 1; - if (lchk == NULL) { - /* Mark end of the window */ - asoc->fast_recovery_tsn = asoc->sending_seq - 1; - } else { - asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; - } - - /* - * CMT fast recovery -- per destination - * recovery variable. - */ - net->fast_retran_loss_recovery = 1; - - if (lchk == NULL) { - /* Mark end of the window */ - net->fast_recovery_tsn = asoc->sending_seq - 1; - } else { - net->fast_recovery_tsn = lchk->rec.data.tsn - 1; - } - - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net); - } - } else if (net->net_ack > 0) { - /* - * Mark a peg that we WOULD have done a cwnd - * reduction but RFC2582 prevented this action. - */ - SCTP_STAT_INCR(sctps_fastretransinrtt); - } - } -} - -static void -sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, - struct sctp_association *asoc, - int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) -{ - struct sctp_nets *net; - /******************************/ - /* update cwnd and Early FR */ - /******************************/ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { -#ifdef JANA_CMT_FAST_RECOVERY - /* - * CMT fast recovery code. Need to debug. - */ - if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { - if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || - SCTP_TSN_GE(net->pseudo_cumack,net->fast_recovery_tsn)) { - net->will_exit_fast_recovery = 1; - } - } -#endif - /* if nothing was acked on this destination skip it */ - if (net->net_ack == 0) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); - } - continue; - } -#ifdef JANA_CMT_FAST_RECOVERY - /* CMT fast recovery code - */ - /* - if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery && net->will_exit_fast_recovery == 0) { - @@@ Do something - } - else if (sctp_cmt_on_off == 0 && asoc->fast_retran_loss_recovery && will_exit == 0) { - */ -#endif - - if (asoc->fast_retran_loss_recovery && - (will_exit == 0) && - (asoc->sctp_cmt_on_off == 0)) { - /* - * If we are in loss recovery we skip any cwnd - * update - */ - return; - } - /* - * CMT: CUC algorithm. Update cwnd if pseudo-cumack has - * moved. - */ - if (accum_moved || - ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { - /* If the cumulative ack moved we can proceed */ - if (net->cwnd <= net->ssthresh) { - /* We are in slow start */ - if (net->flight_size + net->net_ack >= net->cwnd) { - sctp_hs_cwnd_increase(stcb, net); - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_NOADV_SS); - } - } - } else { - /* We are in congestion avoidance */ - net->partial_bytes_acked += net->net_ack; - if ((net->flight_size + net->net_ack >= net->cwnd) && - (net->partial_bytes_acked >= net->cwnd)) { - net->partial_bytes_acked -= net->cwnd; - net->cwnd += net->mtu; - sctp_enforce_cwnd_limit(asoc, net); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_FROM_CA); - } - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_NOADV_CA); - } - } - } - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_NO_CUMACK); - } - } - } -} - -/* - * H-TCP congestion control. The algorithm is detailed in: - * R.N.Shorten, D.J.Leith: - * "H-TCP: TCP for high-speed and long-distance networks" - * Proc. PFLDnet, Argonne, 2004. - * http://www.hamilton.ie/net/htcp3.pdf - */ - -static int use_rtt_scaling = 1; -static int use_bandwidth_switch = 1; - -static inline int -between(uint32_t seq1, uint32_t seq2, uint32_t seq3) -{ - return (seq3 - seq2 >= seq1 - seq2); -} - -static inline uint32_t -htcp_cong_time(struct htcp *ca) -{ - return (sctp_get_tick_count() - ca->last_cong); -} - -static inline uint32_t -htcp_ccount(struct htcp *ca) -{ - return (ca->minRTT == 0 ? htcp_cong_time(ca) : htcp_cong_time(ca)/ca->minRTT); -} - -static inline void -htcp_reset(struct htcp *ca) -{ - ca->undo_last_cong = ca->last_cong; - ca->undo_maxRTT = ca->maxRTT; - ca->undo_old_maxB = ca->old_maxB; - ca->last_cong = sctp_get_tick_count(); -} - -#ifdef SCTP_NOT_USED - -static uint32_t -htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong; - net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT; - net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB; - return (max(net->cwnd, ((net->ssthresh/net->mtu<<7)/net->cc_mod.htcp_ca.beta)*net->mtu)); -} - -#endif - -static inline void -measure_rtt(struct sctp_nets *net) -{ - uint32_t srtt = net->lastsa>>SCTP_RTT_SHIFT; - - /* keep track of minimum RTT seen so far, minRTT is zero at first */ - if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT) - net->cc_mod.htcp_ca.minRTT = srtt; - - /* max RTT */ - if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) { - if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT) - net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT; - if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT+sctp_msecs_to_ticks(20)) - net->cc_mod.htcp_ca.maxRTT = srtt; - } -} - -static void -measure_achieved_throughput(struct sctp_nets *net) -{ - uint32_t now = sctp_get_tick_count(); - - if (net->fast_retran_ip == 0) - net->cc_mod.htcp_ca.bytes_acked = net->net_ack; - - if (!use_bandwidth_switch) - return; - - /* achieved throughput calculations */ - /* JRS - not 100% sure of this statement */ - if (net->fast_retran_ip == 1) { - net->cc_mod.htcp_ca.bytecount = 0; - net->cc_mod.htcp_ca.lasttime = now; - return; - } - - net->cc_mod.htcp_ca.bytecount += net->net_ack; - if ((net->cc_mod.htcp_ca.bytecount >= net->cwnd - (((net->cc_mod.htcp_ca.alpha >> 7) ? (net->cc_mod.htcp_ca.alpha >> 7) : 1) * net->mtu)) && - (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) && - (net->cc_mod.htcp_ca.minRTT > 0)) { - uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount/net->mtu*hz/(now - net->cc_mod.htcp_ca.lasttime); - - if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) { - /* just after backoff */ - net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi; - } else { - net->cc_mod.htcp_ca.Bi = (3*net->cc_mod.htcp_ca.Bi + cur_Bi)/4; - if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB) - net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi; - if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB) - net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB; - } - net->cc_mod.htcp_ca.bytecount = 0; - net->cc_mod.htcp_ca.lasttime = now; - } -} - -static inline void -htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) -{ - if (use_bandwidth_switch) { - uint32_t maxB = ca->maxB; - uint32_t old_maxB = ca->old_maxB; - ca->old_maxB = ca->maxB; - - if (!between(5*maxB, 4*old_maxB, 6*old_maxB)) { - ca->beta = BETA_MIN; - ca->modeswitch = 0; - return; - } - } - - if (ca->modeswitch && minRTT > sctp_msecs_to_ticks(10) && maxRTT) { - ca->beta = (minRTT<<7)/maxRTT; - if (ca->beta < BETA_MIN) - ca->beta = BETA_MIN; - else if (ca->beta > BETA_MAX) - ca->beta = BETA_MAX; - } else { - ca->beta = BETA_MIN; - ca->modeswitch = 1; - } -} - -static inline void -htcp_alpha_update(struct htcp *ca) -{ - uint32_t minRTT = ca->minRTT; - uint32_t factor = 1; - uint32_t diff = htcp_cong_time(ca); - - if (diff > (uint32_t)hz) { - diff -= hz; - factor = 1+ (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; - } - - if (use_rtt_scaling && minRTT) { - uint32_t scale = (hz << 3) / (10 * minRTT); - scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to interval [0.5,10]<<3 */ - factor = (factor << 3) / scale; - if (factor != 0) - factor = 1; - } - - ca->alpha = 2 * factor * ((1 << 7) - ca->beta); - if (ca->alpha != 0) - ca->alpha = ALPHA_BASE; -} - -/* After we have the rtt data to calculate beta, we'd still prefer to wait one - * rtt before we adjust our beta to ensure we are working from a consistent - * data. - * - * This function should be called when we hit a congestion event since only at - * that point do we really have a real sense of maxRTT (the queues en route - * were getting just too full now). - */ -static void -htcp_param_update(struct sctp_nets *net) -{ - uint32_t minRTT = net->cc_mod.htcp_ca.minRTT; - uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT; - - htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT); - htcp_alpha_update(&net->cc_mod.htcp_ca); - - /* add slowly fading memory for maxRTT to accommodate routing changes etc */ - if (minRTT > 0 && maxRTT > minRTT) - net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT-minRTT)*95)/100; -} - -static uint32_t -htcp_recalc_ssthresh(struct sctp_nets *net) -{ - htcp_param_update(net); - return (max(((net->cwnd/net->mtu * net->cc_mod.htcp_ca.beta) >> 7)*net->mtu, 2U*net->mtu)); -} - -static void -htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - /*- - * How to handle these functions? - * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. - * return; - */ - if (net->cwnd <= net->ssthresh) { - /* We are in slow start */ - if (net->flight_size + net->net_ack >= net->cwnd) { - if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { - net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_FROM_SS); - } - - } else { - net->cwnd += net->net_ack; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_FROM_SS); - } - } - sctp_enforce_cwnd_limit(&stcb->asoc, net); - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_NOADV_SS); - } - } - } else { - measure_rtt(net); - - /* In dangerous area, increase slowly. - * In theory this is net->cwnd += alpha / net->cwnd - */ - /* What is snd_cwnd_cnt?? */ - if (((net->partial_bytes_acked/net->mtu * net->cc_mod.htcp_ca.alpha) >> 7)*net->mtu >= net->cwnd) { - /*- - * Does SCTP have a cwnd clamp? - * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). - */ - net->cwnd += net->mtu; - net->partial_bytes_acked = 0; - sctp_enforce_cwnd_limit(&stcb->asoc, net); - htcp_alpha_update(&net->cc_mod.htcp_ca); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_FROM_CA); - } - } else { - net->partial_bytes_acked += net->net_ack; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->net_ack, - SCTP_CWND_LOG_NOADV_CA); - } - } - - net->cc_mod.htcp_ca.bytes_acked = net->mtu; - } -} - -#ifdef SCTP_NOT_USED -/* Lower bound on congestion window. */ -static uint32_t -htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - return (net->ssthresh); -} -#endif - -static void -htcp_init(struct sctp_nets *net) -{ - memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp)); - net->cc_mod.htcp_ca.alpha = ALPHA_BASE; - net->cc_mod.htcp_ca.beta = BETA_MIN; - net->cc_mod.htcp_ca.bytes_acked = net->mtu; - net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count(); -} - -static void -sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - /* - * We take the max of the burst limit times a MTU or the - * INITIAL_CWND. We then limit this to 4 MTU's of sending. - */ - net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); - net->ssthresh = stcb->asoc.peers_rwnd; - sctp_enforce_cwnd_limit(&stcb->asoc, net); - htcp_init(net); - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE|SCTP_CWND_LOGGING_ENABLE)) { - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); - } -} - -static void -sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, - struct sctp_association *asoc, - int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) -{ - struct sctp_nets *net; - - /******************************/ - /* update cwnd and Early FR */ - /******************************/ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { -#ifdef JANA_CMT_FAST_RECOVERY - /* - * CMT fast recovery code. Need to debug. - */ - if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { - if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || - SCTP_TSN_GE(net->pseudo_cumack,net->fast_recovery_tsn)) { - net->will_exit_fast_recovery = 1; - } - } -#endif - /* if nothing was acked on this destination skip it */ - if (net->net_ack == 0) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); - } - continue; - } -#ifdef JANA_CMT_FAST_RECOVERY - /* CMT fast recovery code - */ - /* - if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery && net->will_exit_fast_recovery == 0) { - @@@ Do something - } - else if (sctp_cmt_on_off == 0 && asoc->fast_retran_loss_recovery && will_exit == 0) { - */ -#endif - - if (asoc->fast_retran_loss_recovery && - will_exit == 0 && - (asoc->sctp_cmt_on_off == 0)) { - /* - * If we are in loss recovery we skip any cwnd - * update - */ - return; - } - /* - * CMT: CUC algorithm. Update cwnd if pseudo-cumack has - * moved. - */ - if (accum_moved || - ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { - htcp_cong_avoid(stcb, net); - measure_achieved_throughput(net); - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, net->mtu, - SCTP_CWND_LOG_NO_CUMACK); - } - } - } -} - -static void -sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, - struct sctp_association *asoc) -{ - struct sctp_nets *net; - /* - * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && - * (net->fast_retran_loss_recovery == 0))) - */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((asoc->fast_retran_loss_recovery == 0) || - (asoc->sctp_cmt_on_off > 0)) { - /* out of a RFC2582 Fast recovery window? */ - if (net->net_ack > 0) { - /* - * per section 7.2.3, are there any - * destinations that had a fast retransmit - * to them. If so what we need to do is - * adjust ssthresh and cwnd. - */ - struct sctp_tmit_chunk *lchk; - int old_cwnd = net->cwnd; - - /* JRS - reset as if state were changed */ - htcp_reset(&net->cc_mod.htcp_ca); - net->ssthresh = htcp_recalc_ssthresh(net); - net->cwnd = net->ssthresh; - sctp_enforce_cwnd_limit(asoc, net); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), - SCTP_CWND_LOG_FROM_FR); - } - lchk = TAILQ_FIRST(&asoc->send_queue); - - net->partial_bytes_acked = 0; - /* Turn on fast recovery window */ - asoc->fast_retran_loss_recovery = 1; - if (lchk == NULL) { - /* Mark end of the window */ - asoc->fast_recovery_tsn = asoc->sending_seq - 1; - } else { - asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; - } - - /* - * CMT fast recovery -- per destination - * recovery variable. - */ - net->fast_retran_loss_recovery = 1; - - if (lchk == NULL) { - /* Mark end of the window */ - net->fast_recovery_tsn = asoc->sending_seq - 1; - } else { - net->fast_recovery_tsn = lchk->rec.data.tsn - 1; - } - - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net); - } - } else if (net->net_ack > 0) { - /* - * Mark a peg that we WOULD have done a cwnd - * reduction but RFC2582 prevented this action. - */ - SCTP_STAT_INCR(sctps_fastretransinrtt); - } - } -} - -static void -sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - int old_cwnd = net->cwnd; - - /* JRS - reset as if the state were being changed to timeout */ - htcp_reset(&net->cc_mod.htcp_ca); - net->ssthresh = htcp_recalc_ssthresh(net); - net->cwnd = net->mtu; - net->partial_bytes_acked = 0; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); - } -} - -static void -sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, - struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED) -{ - int old_cwnd; - old_cwnd = net->cwnd; - - /* JRS - reset hctp as if state changed */ - if (in_window == 0) { - htcp_reset(&net->cc_mod.htcp_ca); - SCTP_STAT_INCR(sctps_ecnereducedcwnd); - net->ssthresh = htcp_recalc_ssthresh(net); - if (net->ssthresh < net->mtu) { - net->ssthresh = net->mtu; - /* here back off the timer as well, to slow us down */ - net->RTO <<= 1; - } - net->cwnd = net->ssthresh; - sctp_enforce_cwnd_limit(&stcb->asoc, net); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); - } - } -} - -const struct sctp_cc_functions sctp_cc_functions[] = { -{ -#if defined(_WIN32) && !defined(__MINGW32__) - sctp_set_initial_cc_param, - sctp_cwnd_update_after_sack, - sctp_cwnd_update_exit_pf_common, - sctp_cwnd_update_after_fr, - sctp_cwnd_update_after_timeout, - sctp_cwnd_update_after_ecn_echo, - sctp_cwnd_update_after_packet_dropped, - sctp_cwnd_update_after_output, -#else - .sctp_set_initial_cc_param = sctp_set_initial_cc_param, - .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, - .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, - .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, - .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, - .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, - .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, - .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, -#endif -}, -{ -#if defined(_WIN32) && !defined(__MINGW32__) - sctp_set_initial_cc_param, - sctp_hs_cwnd_update_after_sack, - sctp_cwnd_update_exit_pf_common, - sctp_hs_cwnd_update_after_fr, - sctp_cwnd_update_after_timeout, - sctp_cwnd_update_after_ecn_echo, - sctp_cwnd_update_after_packet_dropped, - sctp_cwnd_update_after_output, -#else - .sctp_set_initial_cc_param = sctp_set_initial_cc_param, - .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, - .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, - .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr, - .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, - .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, - .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, - .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, -#endif -}, -{ -#if defined(_WIN32) && !defined(__MINGW32__) - sctp_htcp_set_initial_cc_param, - sctp_htcp_cwnd_update_after_sack, - sctp_cwnd_update_exit_pf_common, - sctp_htcp_cwnd_update_after_fr, - sctp_htcp_cwnd_update_after_timeout, - sctp_htcp_cwnd_update_after_ecn_echo, - sctp_cwnd_update_after_packet_dropped, - sctp_cwnd_update_after_output, -#else - .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param, - .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, - .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, - .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr, - .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, - .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo, - .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, - .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, -#endif -}, -{ -#if defined(_WIN32) && !defined(__MINGW32__) - sctp_set_rtcc_initial_cc_param, - sctp_cwnd_update_rtcc_after_sack, - sctp_cwnd_update_exit_pf_common, - sctp_cwnd_update_after_fr, - sctp_cwnd_update_after_timeout, - sctp_cwnd_update_rtcc_after_ecn_echo, - sctp_cwnd_update_after_packet_dropped, - sctp_cwnd_update_after_output, - sctp_cwnd_update_rtcc_packet_transmitted, - sctp_cwnd_update_rtcc_tsn_acknowledged, - sctp_cwnd_new_rtcc_transmission_begins, - sctp_cwnd_prepare_rtcc_net_for_sack, - sctp_cwnd_rtcc_socket_option, - sctp_rtt_rtcc_calculated -#else - .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param, - .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, - .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, - .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, - .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, - .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo, - .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, - .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, - .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted, - .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, - .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, - .sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack, - .sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option, - .sctp_rtt_calculated = sctp_rtt_rtcc_calculated -#endif -} -}; diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_constants.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_constants.h deleted file mode 100644 index ca2ed70b..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_constants.h +++ /dev/null @@ -1,1068 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_CONSTANTS_H_ -#define _NETINET_SCTP_CONSTANTS_H_ - -#if defined(_WIN32) && defined(__Userspace__) -extern void getwintimeofday(struct timeval *tv); - -#endif -/* IANA assigned port number for SCTP over UDP encapsulation */ -#define SCTP_OVER_UDP_TUNNELING_PORT 9899 - -/* Number of packets to get before sack sent by default */ -#define SCTP_DEFAULT_SACK_FREQ 2 - -/* Address limit - This variable is calculated - * based on an 65535 byte max ip packet. We take out 100 bytes - * for the cookie, 40 bytes for a v6 header and 32 - * bytes for the init structure. A second init structure - * for the init-ack and then finally a third one for the - * imbedded init. This yeilds 100+40+(3 * 32) = 236 bytes. - * This leaves 65299 bytes for addresses. We throw out the 299 bytes. - * Now whatever we send in the INIT() we need to allow to get back in the - * INIT-ACK plus all the values from INIT and INIT-ACK - * listed in the cookie. Plus we need some overhead for - * maybe copied parameters in the COOKIE. If we - * allow 1080 addresses, and each side has 1080 V6 addresses - * that will be 21600 bytes. In the INIT-ACK we will - * see the INIT-ACK 21600 + 43200 in the cookie. This leaves - * about 500 bytes slack for misc things in the cookie. - */ -#define SCTP_ADDRESS_LIMIT 1080 - -/* We need at least 2k of space for us, inits - * larger than that lets abort. - */ -#define SCTP_LARGEST_INIT_ACCEPTED (65535 - 2048) - -/* Largest length of a chunk */ -#define SCTP_MAX_CHUNK_LENGTH 0xffff -/* Largest length of an error cause */ -#define SCTP_MAX_CAUSE_LENGTH 0xffff -/* Number of addresses where we just skip the counting */ -#define SCTP_COUNT_LIMIT 40 - -#define SCTP_ZERO_COPY_TICK_DELAY (((100 * hz) + 999) / 1000) -#define SCTP_ZERO_COPY_SENDQ_TICK_DELAY (((100 * hz) + 999) / 1000) - -/* Number of ticks to delay before running - * iterator on an address change. - */ -#define SCTP_ADDRESS_TICK_DELAY 2 - -#define SCTP_VERSION_STRING "KAME-BSD 1.1" -/* #define SCTP_AUDITING_ENABLED 1 used for debug/auditing */ -#define SCTP_AUDIT_SIZE 256 - -#define SCTP_KTRHEAD_NAME "sctp_iterator" -#define SCTP_KTHREAD_PAGES 0 - -#define SCTP_MCORE_NAME "sctp_core_worker" - -/* If you support Multi-VRF how big to - * make the initial array of VRF's to. - */ -#define SCTP_DEFAULT_VRF_SIZE 4 - -/* JRS - Values defined for the HTCP algorithm */ -#define ALPHA_BASE (1<<7) /* 1.0 with shift << 7 */ -#define BETA_MIN (1<<6) /* 0.5 with shift << 7 */ -#define BETA_MAX 102 /* 0.8 with shift << 7 */ - -/* Places that CWND log can happen from */ -#define SCTP_CWND_LOG_FROM_FR 1 -#define SCTP_CWND_LOG_FROM_RTX 2 -#define SCTP_CWND_LOG_FROM_BRST 3 -#define SCTP_CWND_LOG_FROM_SS 4 -#define SCTP_CWND_LOG_FROM_CA 5 -#define SCTP_CWND_LOG_FROM_SAT 6 -#define SCTP_BLOCK_LOG_INTO_BLK 7 -#define SCTP_BLOCK_LOG_OUTOF_BLK 8 -#define SCTP_BLOCK_LOG_CHECK 9 -#define SCTP_STR_LOG_FROM_INTO_STRD 10 -#define SCTP_STR_LOG_FROM_IMMED_DEL 11 -#define SCTP_STR_LOG_FROM_INSERT_HD 12 -#define SCTP_STR_LOG_FROM_INSERT_MD 13 -#define SCTP_STR_LOG_FROM_INSERT_TL 14 -#define SCTP_STR_LOG_FROM_MARK_TSN 15 -#define SCTP_STR_LOG_FROM_EXPRS_DEL 16 -#define SCTP_FR_LOG_BIGGEST_TSNS 17 -#define SCTP_FR_LOG_STRIKE_TEST 18 -#define SCTP_FR_LOG_STRIKE_CHUNK 19 -#define SCTP_FR_T3_TIMEOUT 20 -#define SCTP_MAP_PREPARE_SLIDE 21 -#define SCTP_MAP_SLIDE_FROM 22 -#define SCTP_MAP_SLIDE_RESULT 23 -#define SCTP_MAP_SLIDE_CLEARED 24 -#define SCTP_MAP_SLIDE_NONE 25 -#define SCTP_FR_T3_MARK_TIME 26 -#define SCTP_FR_T3_MARKED 27 -#define SCTP_FR_T3_STOPPED 28 -#define SCTP_FR_MARKED 30 -#define SCTP_CWND_LOG_NOADV_SS 31 -#define SCTP_CWND_LOG_NOADV_CA 32 -#define SCTP_MAX_BURST_APPLIED 33 -#define SCTP_MAX_IFP_APPLIED 34 -#define SCTP_MAX_BURST_ERROR_STOP 35 -#define SCTP_INCREASE_PEER_RWND 36 -#define SCTP_DECREASE_PEER_RWND 37 -#define SCTP_SET_PEER_RWND_VIA_SACK 38 -#define SCTP_LOG_MBCNT_INCREASE 39 -#define SCTP_LOG_MBCNT_DECREASE 40 -#define SCTP_LOG_MBCNT_CHKSET 41 -#define SCTP_LOG_NEW_SACK 42 -#define SCTP_LOG_TSN_ACKED 43 -#define SCTP_LOG_TSN_REVOKED 44 -#define SCTP_LOG_LOCK_TCB 45 -#define SCTP_LOG_LOCK_INP 46 -#define SCTP_LOG_LOCK_SOCK 47 -#define SCTP_LOG_LOCK_SOCKBUF_R 48 -#define SCTP_LOG_LOCK_SOCKBUF_S 49 -#define SCTP_LOG_LOCK_CREATE 50 -#define SCTP_LOG_INITIAL_RTT 51 -#define SCTP_LOG_RTTVAR 52 -#define SCTP_LOG_SBALLOC 53 -#define SCTP_LOG_SBFREE 54 -#define SCTP_LOG_SBRESULT 55 -#define SCTP_FR_DUPED 56 -#define SCTP_FR_MARKED_EARLY 57 -#define SCTP_FR_CWND_REPORT 58 -#define SCTP_FR_CWND_REPORT_START 59 -#define SCTP_FR_CWND_REPORT_STOP 60 -#define SCTP_CWND_LOG_FROM_SEND 61 -#define SCTP_CWND_INITIALIZATION 62 -#define SCTP_CWND_LOG_FROM_T3 63 -#define SCTP_CWND_LOG_FROM_SACK 64 -#define SCTP_CWND_LOG_NO_CUMACK 65 -#define SCTP_CWND_LOG_FROM_RESEND 66 -#define SCTP_FR_LOG_CHECK_STRIKE 67 -#define SCTP_SEND_NOW_COMPLETES 68 -#define SCTP_CWND_LOG_FILL_OUTQ_CALLED 69 -#define SCTP_CWND_LOG_FILL_OUTQ_FILLS 70 -#define SCTP_LOG_FREE_SENT 71 -#define SCTP_NAGLE_APPLIED 72 -#define SCTP_NAGLE_SKIPPED 73 -#define SCTP_WAKESND_FROM_SACK 74 -#define SCTP_WAKESND_FROM_FWDTSN 75 -#define SCTP_NOWAKE_FROM_SACK 76 -#define SCTP_CWNDLOG_PRESEND 77 -#define SCTP_CWNDLOG_ENDSEND 78 -#define SCTP_AT_END_OF_SACK 79 -#define SCTP_REASON_FOR_SC 80 -#define SCTP_BLOCK_LOG_INTO_BLKA 81 -#define SCTP_ENTER_USER_RECV 82 -#define SCTP_USER_RECV_SACKS 83 -#define SCTP_SORECV_BLOCKSA 84 -#define SCTP_SORECV_BLOCKSB 85 -#define SCTP_SORECV_DONE 86 -#define SCTP_SACK_RWND_UPDATE 87 -#define SCTP_SORECV_ENTER 88 -#define SCTP_SORECV_ENTERPL 89 -#define SCTP_MBUF_INPUT 90 -#define SCTP_MBUF_IALLOC 91 -#define SCTP_MBUF_IFREE 92 -#define SCTP_MBUF_ICOPY 93 -#define SCTP_MBUF_SPLIT 94 -#define SCTP_SORCV_FREECTL 95 -#define SCTP_SORCV_DOESCPY 96 -#define SCTP_SORCV_DOESLCK 97 -#define SCTP_SORCV_DOESADJ 98 -#define SCTP_SORCV_BOTWHILE 99 -#define SCTP_SORCV_PASSBF 100 -#define SCTP_SORCV_ADJD 101 -#define SCTP_UNKNOWN_MAX 102 -#define SCTP_RANDY_STUFF 103 -#define SCTP_RANDY_STUFF1 104 -#define SCTP_STRMOUT_LOG_ASSIGN 105 -#define SCTP_STRMOUT_LOG_SEND 106 -#define SCTP_FLIGHT_LOG_DOWN_CA 107 -#define SCTP_FLIGHT_LOG_UP 108 -#define SCTP_FLIGHT_LOG_DOWN_GAP 109 -#define SCTP_FLIGHT_LOG_DOWN_RSND 110 -#define SCTP_FLIGHT_LOG_UP_RSND 111 -#define SCTP_FLIGHT_LOG_DOWN_RSND_TO 112 -#define SCTP_FLIGHT_LOG_DOWN_WP 113 -#define SCTP_FLIGHT_LOG_UP_REVOKE 114 -#define SCTP_FLIGHT_LOG_DOWN_PDRP 115 -#define SCTP_FLIGHT_LOG_DOWN_PMTU 116 -#define SCTP_SACK_LOG_NORMAL 117 -#define SCTP_SACK_LOG_EXPRESS 118 -#define SCTP_MAP_TSN_ENTERS 119 -#define SCTP_THRESHOLD_CLEAR 120 -#define SCTP_THRESHOLD_INCR 121 -#define SCTP_FLIGHT_LOG_DWN_WP_FWD 122 -#define SCTP_FWD_TSN_CHECK 123 -#define SCTP_LOG_MAX_TYPES 124 -/* - * To turn on various logging, you must first enable 'options KTR' and - * you might want to bump the entires 'options KTR_ENTRIES=80000'. - * To get something to log you define one of the logging defines. - * (see LINT). - * - * This gets the compile in place, but you still need to turn the - * logging flag on too in the sysctl (see in sctp.h). - */ - -#define SCTP_LOG_EVENT_UNKNOWN 0 -#define SCTP_LOG_EVENT_CWND 1 -#define SCTP_LOG_EVENT_BLOCK 2 -#define SCTP_LOG_EVENT_STRM 3 -#define SCTP_LOG_EVENT_FR 4 -#define SCTP_LOG_EVENT_MAP 5 -#define SCTP_LOG_EVENT_MAXBURST 6 -#define SCTP_LOG_EVENT_RWND 7 -#define SCTP_LOG_EVENT_MBCNT 8 -#define SCTP_LOG_EVENT_SACK 9 -#define SCTP_LOG_LOCK_EVENT 10 -#define SCTP_LOG_EVENT_RTT 11 -#define SCTP_LOG_EVENT_SB 12 -#define SCTP_LOG_EVENT_NAGLE 13 -#define SCTP_LOG_EVENT_WAKE 14 -#define SCTP_LOG_MISC_EVENT 15 -#define SCTP_LOG_EVENT_CLOSE 16 -#define SCTP_LOG_EVENT_MBUF 17 -#define SCTP_LOG_CHUNK_PROC 18 -#define SCTP_LOG_ERROR_RET 19 - -#define SCTP_LOG_MAX_EVENT 20 - -#define SCTP_LOCK_UNKNOWN 2 - -/* number of associations by default for zone allocation */ -#define SCTP_MAX_NUM_OF_ASOC 40000 -/* how many addresses per assoc remote and local */ -#define SCTP_SCALE_FOR_ADDR 2 - -/* default MULTIPLE_ASCONF mode enable(1)/disable(0) value (sysctl) */ -#define SCTP_DEFAULT_MULTIPLE_ASCONFS 0 - -/* - * Threshold for rwnd updates, we have to read (sb_hiwat >> - * SCTP_RWND_HIWAT_SHIFT) before we will look to see if we need to send a - * window update sack. When we look, we compare the last rwnd we sent vs the - * current rwnd. It too must be greater than this value. Using 3 divdes the - * hiwat by 8, so for 200k rwnd we need to read 24k. For a 64k rwnd we need - * to read 8k. This seems about right.. I hope :-D.. we do set a - * min of a MTU on it so if the rwnd is real small we will insist - * on a full MTU of 1500 bytes. - */ -#define SCTP_RWND_HIWAT_SHIFT 3 - -/* How much of the rwnd must the - * message be taking up to start partial delivery. - * We calculate this by shifing the hi_water (recv_win) - * left the following .. set to 1, when a message holds - * 1/2 the rwnd. If we set it to 2 when a message holds - * 1/4 the rwnd...etc.. - */ - -#define SCTP_PARTIAL_DELIVERY_SHIFT 1 - -/* - * default HMAC for cookies, etc... use one of the AUTH HMAC id's - * SCTP_HMAC is the HMAC_ID to use - * SCTP_SIGNATURE_SIZE is the digest length - */ -#define SCTP_HMAC SCTP_AUTH_HMAC_ID_SHA1 -#define SCTP_SIGNATURE_SIZE SCTP_AUTH_DIGEST_LEN_SHA1 -#define SCTP_SIGNATURE_ALOC_SIZE SCTP_SIGNATURE_SIZE - -/* - * the SCTP protocol signature this includes the version number encoded in - * the last 4 bits of the signature. - */ -#define PROTO_SIGNATURE_A 0x30000000 -#define SCTP_VERSION_NUMBER 0x3 - -#define MAX_TSN 0xffffffff - -/* how many executions every N tick's */ -#define SCTP_ITERATOR_MAX_AT_ONCE 20 - -/* number of clock ticks between iterator executions */ -#define SCTP_ITERATOR_TICKS 1 - -/* - * option: If you comment out the following you will receive the old behavior - * of obeying cwnd for the fast retransmit algorithm. With this defined a FR - * happens right away with-out waiting for the flightsize to drop below the - * cwnd value (which is reduced by the FR to 1/2 the inflight packets). - */ -#define SCTP_IGNORE_CWND_ON_FR 1 - -/* - * Adds implementors guide behavior to only use newest highest update in SACK - * gap ack's to figure out if you need to stroke a chunk for FR. - */ -#define SCTP_NO_FR_UNLESS_SEGMENT_SMALLER 1 - -/* default max I can burst out after a fast retransmit, 0 disables it */ -#define SCTP_DEF_MAX_BURST 4 -#define SCTP_DEF_HBMAX_BURST 4 -#define SCTP_DEF_FRMAX_BURST 4 - -/* RTO calculation flag to say if it - * is safe to determine local lan or not. - */ -#define SCTP_RTT_FROM_NON_DATA 0 -#define SCTP_RTT_FROM_DATA 1 - -#define PR_SCTP_UNORDERED_FLAG 0x0001 - -/* IP hdr (20/40) + 12+2+2 (enet) + sctp common 12 */ -#define SCTP_FIRST_MBUF_RESV 68 -/* Packet transmit states in the sent field */ -#define SCTP_DATAGRAM_UNSENT 0 -#define SCTP_DATAGRAM_SENT 1 -#define SCTP_DATAGRAM_RESEND1 2 /* not used (in code, but may - * hit this value) */ -#define SCTP_DATAGRAM_RESEND2 3 /* not used (in code, but may - * hit this value) */ -#define SCTP_DATAGRAM_RESEND 4 -#define SCTP_DATAGRAM_ACKED 10010 -#define SCTP_DATAGRAM_MARKED 20010 -#define SCTP_FORWARD_TSN_SKIP 30010 -#define SCTP_DATAGRAM_NR_ACKED 40010 - -/* chunk output send from locations */ -#define SCTP_OUTPUT_FROM_USR_SEND 0 -#define SCTP_OUTPUT_FROM_T3 1 -#define SCTP_OUTPUT_FROM_INPUT_ERROR 2 -#define SCTP_OUTPUT_FROM_CONTROL_PROC 3 -#define SCTP_OUTPUT_FROM_SACK_TMR 4 -#define SCTP_OUTPUT_FROM_SHUT_TMR 5 -#define SCTP_OUTPUT_FROM_HB_TMR 6 -#define SCTP_OUTPUT_FROM_SHUT_ACK_TMR 7 -#define SCTP_OUTPUT_FROM_ASCONF_TMR 8 -#define SCTP_OUTPUT_FROM_STRRST_TMR 9 -#define SCTP_OUTPUT_FROM_AUTOCLOSE_TMR 10 -#define SCTP_OUTPUT_FROM_EARLY_FR_TMR 11 -#define SCTP_OUTPUT_FROM_STRRST_REQ 12 -#define SCTP_OUTPUT_FROM_USR_RCVD 13 -#define SCTP_OUTPUT_FROM_COOKIE_ACK 14 -#define SCTP_OUTPUT_FROM_DRAIN 15 -#define SCTP_OUTPUT_FROM_CLOSING 16 -#define SCTP_OUTPUT_FROM_SOCKOPT 17 - -/* SCTP chunk types are moved sctp.h for application (NAT, FW) use */ - -/* align to 32-bit sizes */ -#define SCTP_SIZE32(x) ((((x) + 3) >> 2) << 2) - -#define IS_SCTP_CONTROL(a) (((a)->chunk_type != SCTP_DATA) && ((a)->chunk_type != SCTP_IDATA)) -#define IS_SCTP_DATA(a) (((a)->chunk_type == SCTP_DATA) || ((a)->chunk_type == SCTP_IDATA)) - -/* SCTP parameter types */ -/*************0x0000 series*************/ -#define SCTP_HEARTBEAT_INFO 0x0001 -#if defined(__Userspace__) -#define SCTP_CONN_ADDRESS 0x0004 -#endif -#define SCTP_IPV4_ADDRESS 0x0005 -#define SCTP_IPV6_ADDRESS 0x0006 -#define SCTP_STATE_COOKIE 0x0007 -#define SCTP_UNRECOG_PARAM 0x0008 -#define SCTP_COOKIE_PRESERVE 0x0009 -#define SCTP_HOSTNAME_ADDRESS 0x000b -#define SCTP_SUPPORTED_ADDRTYPE 0x000c - -/* RFC 6525 */ -#define SCTP_STR_RESET_OUT_REQUEST 0x000d -#define SCTP_STR_RESET_IN_REQUEST 0x000e -#define SCTP_STR_RESET_TSN_REQUEST 0x000f -#define SCTP_STR_RESET_RESPONSE 0x0010 -#define SCTP_STR_RESET_ADD_OUT_STREAMS 0x0011 -#define SCTP_STR_RESET_ADD_IN_STREAMS 0x0012 - -#define SCTP_MAX_RESET_PARAMS 2 -#define SCTP_STREAM_RESET_TSN_DELTA 0x1000 - -/*************0x4000 series*************/ - -/*************0x8000 series*************/ -#define SCTP_ECN_CAPABLE 0x8000 -#define SCTP_ZERO_CHECKSUM_ACCEPTABLE 0x8001 -/* RFC 4895 */ -#define SCTP_RANDOM 0x8002 -#define SCTP_CHUNK_LIST 0x8003 -#define SCTP_HMAC_LIST 0x8004 -/* RFC 4820 */ -#define SCTP_PAD 0x8005 -/* RFC 5061 */ -#define SCTP_SUPPORTED_CHUNK_EXT 0x8008 - -/*************0xC000 series*************/ -#define SCTP_PRSCTP_SUPPORTED 0xc000 -/* RFC 5061 */ -#define SCTP_ADD_IP_ADDRESS 0xc001 -#define SCTP_DEL_IP_ADDRESS 0xc002 -#define SCTP_ERROR_CAUSE_IND 0xc003 -#define SCTP_SET_PRIM_ADDR 0xc004 -#define SCTP_SUCCESS_REPORT 0xc005 -#define SCTP_ULP_ADAPTATION 0xc006 -/* behave-nat-draft */ -#define SCTP_HAS_NAT_SUPPORT 0xc007 -#define SCTP_NAT_VTAGS 0xc008 - -/* bits for TOS field */ -#define SCTP_ECT0_BIT 0x02 -#define SCTP_ECT1_BIT 0x01 -#define SCTP_CE_BITS 0x03 - -/* below turns off above */ -#define SCTP_FLEXIBLE_ADDRESS 0x20 -#define SCTP_NO_HEARTBEAT 0x40 - -/* mask to get sticky */ -#define SCTP_STICKY_OPTIONS_MASK 0x0c - -/* - * SCTP states for internal state machine - */ -#define SCTP_STATE_EMPTY 0x0000 -#define SCTP_STATE_INUSE 0x0001 -#define SCTP_STATE_COOKIE_WAIT 0x0002 -#define SCTP_STATE_COOKIE_ECHOED 0x0004 -#define SCTP_STATE_OPEN 0x0008 -#define SCTP_STATE_SHUTDOWN_SENT 0x0010 -#define SCTP_STATE_SHUTDOWN_RECEIVED 0x0020 -#define SCTP_STATE_SHUTDOWN_ACK_SENT 0x0040 -#define SCTP_STATE_SHUTDOWN_PENDING 0x0080 -#define SCTP_STATE_CLOSED_SOCKET 0x0100 -#define SCTP_STATE_ABOUT_TO_BE_FREED 0x0200 -#define SCTP_STATE_PARTIAL_MSG_LEFT 0x0400 -#define SCTP_STATE_WAS_ABORTED 0x0800 -#define SCTP_STATE_IN_ACCEPT_QUEUE 0x1000 -#define SCTP_STATE_MASK 0x007f - -#define SCTP_GET_STATE(_stcb) \ - ((_stcb)->asoc.state & SCTP_STATE_MASK) -#define SCTP_SET_STATE(_stcb, _state) \ - sctp_set_state(_stcb, _state) -#define SCTP_CLEAR_SUBSTATE(_stcb, _substate) \ - (_stcb)->asoc.state &= ~(_substate) -#define SCTP_ADD_SUBSTATE(_stcb, _substate) \ - sctp_add_substate(_stcb, _substate) - -/* SCTP reachability state for each address */ -#define SCTP_ADDR_REACHABLE 0x001 -#define SCTP_ADDR_NO_PMTUD 0x002 -#define SCTP_ADDR_NOHB 0x004 -#define SCTP_ADDR_BEING_DELETED 0x008 -#define SCTP_ADDR_NOT_IN_ASSOC 0x010 -#define SCTP_ADDR_OUT_OF_SCOPE 0x080 -#define SCTP_ADDR_UNCONFIRMED 0x200 -#define SCTP_ADDR_REQ_PRIMARY 0x400 -/* JRS 5/13/07 - Added potentially failed state for CMT PF */ -#define SCTP_ADDR_PF 0x800 - -/* bound address types (e.g. valid address types to allow) */ -#define SCTP_BOUND_V6 0x01 -#define SCTP_BOUND_V4 0x02 - -/* - * what is the default number of mbufs in a chain I allow before switching to - * a cluster - */ -#define SCTP_DEFAULT_MBUFS_IN_CHAIN 5 - -/* How long a cookie lives in milli-seconds */ -#define SCTP_DEFAULT_COOKIE_LIFE 60000 - -/* Maximum the mapping array will grow to (TSN mapping array) */ -#define SCTP_MAPPING_ARRAY 512 - -/* size of the initial malloc on the mapping array */ -#define SCTP_INITIAL_MAPPING_ARRAY 16 -/* how much we grow the mapping array each call */ -#define SCTP_MAPPING_ARRAY_INCR 32 - -/* - * Here we define the timer types used by the implementation as arguments in - * the set/get timer type calls. - */ -#define SCTP_TIMER_INIT 0 -#define SCTP_TIMER_RECV 1 -#define SCTP_TIMER_SEND 2 -#define SCTP_TIMER_HEARTBEAT 3 -#define SCTP_TIMER_PMTU 4 -#define SCTP_TIMER_MAXSHUTDOWN 5 -#define SCTP_TIMER_SIGNATURE 6 -/* - * number of timer types in the base SCTP structure used in the set/get and - * has the base default. - */ -#define SCTP_NUM_TMRS 7 - -/* timer types */ -#define SCTP_TIMER_TYPE_NONE 0 -#define SCTP_TIMER_TYPE_SEND 1 -#define SCTP_TIMER_TYPE_INIT 2 -#define SCTP_TIMER_TYPE_RECV 3 -#define SCTP_TIMER_TYPE_SHUTDOWN 4 -#define SCTP_TIMER_TYPE_HEARTBEAT 5 -#define SCTP_TIMER_TYPE_COOKIE 6 -#define SCTP_TIMER_TYPE_NEWCOOKIE 7 -#define SCTP_TIMER_TYPE_PATHMTURAISE 8 -#define SCTP_TIMER_TYPE_SHUTDOWNACK 9 -#define SCTP_TIMER_TYPE_ASCONF 10 -#define SCTP_TIMER_TYPE_SHUTDOWNGUARD 11 -#define SCTP_TIMER_TYPE_AUTOCLOSE 12 -#define SCTP_TIMER_TYPE_STRRESET 13 -#define SCTP_TIMER_TYPE_INPKILL 14 -#define SCTP_TIMER_TYPE_ASOCKILL 15 -#define SCTP_TIMER_TYPE_ADDR_WQ 16 -#define SCTP_TIMER_TYPE_PRIM_DELETED 17 -/* add new timers here - and increment LAST */ -#define SCTP_TIMER_TYPE_LAST 18 - -#define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \ - ((t) < SCTP_TIMER_TYPE_LAST)) - -#if defined(__APPLE__) && !defined(__Userspace__) -/* Number of ticks to run the main timer at in msec */ -#define SCTP_MAIN_TIMER_DEFAULT 10 - -#endif -/* max number of TSN's dup'd that I will hold */ -#define SCTP_MAX_DUP_TSNS 20 - -/* - * Here we define the types used when setting the retry amounts. - */ -/* How many drop re-attempts we make on INIT/COOKIE-ECHO */ -#define SCTP_RETRY_DROPPED_THRESH 4 - -/* - * Maxmium number of chunks a single association can have on it. Note that - * this is a squishy number since the count can run over this if the user - * sends a large message down .. the fragmented chunks don't count until - * AFTER the message is on queue.. it would be the next send that blocks - * things. This number will get tuned up at boot in the sctp_init and use the - * number of clusters as a base. This way high bandwidth environments will - * not get impacted by the lower bandwidth sending a bunch of 1 byte chunks - */ -#define SCTP_ASOC_MAX_CHUNKS_ON_QUEUE 512 - -/* - * Basically the minimum amount of time before I do a early FR. Making this - * value to low will cause duplicate retransmissions. - */ -#define SCTP_MINFR_MSEC_TIMER 250 -/* The floor this value is allowed to fall to when starting a timer. */ -#define SCTP_MINFR_MSEC_FLOOR 20 - -/* init timer def = 1 sec */ -#define SCTP_INIT_SEC 1 - -/* send timer def = 1 seconds */ -#define SCTP_SEND_SEC 1 - -/* recv timer def = 200ms */ -#define SCTP_RECV_MSEC 200 - -/* 30 seconds + RTO (in ms) */ -#define SCTP_HB_DEFAULT_MSEC 30000 - -/* - * This is how long a secret lives, NOT how long a cookie lives how many - * ticks the current secret will live. - */ -#define SCTP_DEFAULT_SECRET_LIFE_SEC 3600 - -#define SCTP_RTO_UPPER_BOUND (60000) /* 60 sec in ms */ -#define SCTP_RTO_LOWER_BOUND (1000) /* 1 sec is ms */ -#define SCTP_RTO_INITIAL (1000) /* 1 sec in ms */ - -#define SCTP_INP_KILL_TIMEOUT 20 /* number of ms to retry kill of inpcb */ -#define SCTP_ASOC_KILL_TIMEOUT 10 /* number of ms to retry kill of inpcb */ - -#define SCTP_DEF_MAX_INIT 8 -#define SCTP_DEF_MAX_SEND 10 -#define SCTP_DEF_MAX_PATH_RTX 5 -#define SCTP_DEF_PATH_PF_THRESHOLD SCTP_DEF_MAX_PATH_RTX - -#define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */ - -/* How many streams I request initially by default */ -#define SCTP_OSTREAM_INITIAL 10 -#define SCTP_ISTREAM_INITIAL 2048 - -/* - * How many smallest_mtu's need to increase before a window update sack is - * sent (should be a power of 2). - */ -/* Send window update (incr * this > hiwat). Should be a power of 2 */ -#define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */ - -#define SCTP_ADDRMAX 16 - -/* SCTP DEBUG Switch parameters */ -#define SCTP_DEBUG_TIMER1 0x00000001 -#define SCTP_DEBUG_TIMER2 0x00000002 /* unused */ -#define SCTP_DEBUG_TIMER3 0x00000004 /* unused */ -#define SCTP_DEBUG_TIMER4 0x00000008 -#define SCTP_DEBUG_OUTPUT1 0x00000010 -#define SCTP_DEBUG_OUTPUT2 0x00000020 -#define SCTP_DEBUG_OUTPUT3 0x00000040 -#define SCTP_DEBUG_OUTPUT4 0x00000080 -#define SCTP_DEBUG_UTIL1 0x00000100 -#define SCTP_DEBUG_UTIL2 0x00000200 /* unused */ -#define SCTP_DEBUG_AUTH1 0x00000400 -#define SCTP_DEBUG_AUTH2 0x00000800 /* unused */ -#define SCTP_DEBUG_INPUT1 0x00001000 -#define SCTP_DEBUG_INPUT2 0x00002000 -#define SCTP_DEBUG_INPUT3 0x00004000 -#define SCTP_DEBUG_INPUT4 0x00008000 /* unused */ -#define SCTP_DEBUG_ASCONF1 0x00010000 -#define SCTP_DEBUG_ASCONF2 0x00020000 -#define SCTP_DEBUG_OUTPUT5 0x00040000 /* unused */ -#define SCTP_DEBUG_XXX 0x00080000 /* unused */ -#define SCTP_DEBUG_PCB1 0x00100000 -#define SCTP_DEBUG_PCB2 0x00200000 /* unused */ -#define SCTP_DEBUG_PCB3 0x00400000 -#define SCTP_DEBUG_PCB4 0x00800000 -#define SCTP_DEBUG_INDATA1 0x01000000 -#define SCTP_DEBUG_INDATA2 0x02000000 /* unused */ -#define SCTP_DEBUG_INDATA3 0x04000000 /* unused */ -#define SCTP_DEBUG_CRCOFFLOAD 0x08000000 /* unused */ -#define SCTP_DEBUG_USRREQ1 0x10000000 /* unused */ -#define SCTP_DEBUG_USRREQ2 0x20000000 /* unused */ -#define SCTP_DEBUG_PEEL1 0x40000000 -#if defined(__Userspace__) -#define SCTP_DEBUG_USR 0x80000000 -#else -#define SCTP_DEBUG_XXXXX 0x80000000 /* unused */ -#endif -#define SCTP_DEBUG_ALL 0x7ff3ffff -#define SCTP_DEBUG_NOISY 0x00040000 - -/* What sender needs to see to avoid SWS or we consider peers rwnd 0 */ -#define SCTP_SWS_SENDER_DEF 1420 - -/* - * SWS is scaled to the sb_hiwat of the socket. A value of 2 is hiwat/4, 1 - * would be hiwat/2 etc. - */ -/* What receiver needs to see in sockbuf or we tell peer its 1 */ -#define SCTP_SWS_RECEIVER_DEF 3000 - -#define SCTP_INITIAL_CWND 4380 - -#define SCTP_DEFAULT_MTU 1500 /* emergency default MTU */ -/* amount peer is obligated to have in rwnd or I will abort */ -#define SCTP_MIN_RWND 1500 - -#define SCTP_CHUNK_BUFFER_SIZE 512 -#define SCTP_PARAM_BUFFER_SIZE 512 - -/* small chunk store for looking at chunk_list in auth */ -#define SCTP_SMALL_CHUNK_STORE 260 - -#define SCTP_HOW_MANY_SECRETS 2 /* how many secrets I keep */ - -#define SCTP_NUMBER_OF_SECRETS 8 /* or 8 * 4 = 32 octets */ -#define SCTP_SECRET_SIZE 32 /* number of octets in a 256 bits */ - -/* - * SCTP upper layer notifications - */ -#define SCTP_NOTIFY_ASSOC_UP 1 -#define SCTP_NOTIFY_ASSOC_DOWN 2 -#define SCTP_NOTIFY_INTERFACE_DOWN 3 -#define SCTP_NOTIFY_INTERFACE_UP 4 -#define SCTP_NOTIFY_SENT_DG_FAIL 5 -#define SCTP_NOTIFY_UNSENT_DG_FAIL 6 -#define SCTP_NOTIFY_SPECIAL_SP_FAIL 7 -#define SCTP_NOTIFY_ASSOC_LOC_ABORTED 8 -#define SCTP_NOTIFY_ASSOC_REM_ABORTED 9 -#define SCTP_NOTIFY_ASSOC_RESTART 10 -#define SCTP_NOTIFY_PEER_SHUTDOWN 11 -#define SCTP_NOTIFY_ASCONF_ADD_IP 12 -#define SCTP_NOTIFY_ASCONF_DELETE_IP 13 -#define SCTP_NOTIFY_ASCONF_SET_PRIMARY 14 -#define SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION 15 -#define SCTP_NOTIFY_INTERFACE_CONFIRMED 16 -#define SCTP_NOTIFY_STR_RESET_RECV 17 -#define SCTP_NOTIFY_STR_RESET_SEND 18 -#define SCTP_NOTIFY_STR_RESET_FAILED_OUT 19 -#define SCTP_NOTIFY_STR_RESET_FAILED_IN 20 -#define SCTP_NOTIFY_STR_RESET_DENIED_OUT 21 -#define SCTP_NOTIFY_STR_RESET_DENIED_IN 22 -#define SCTP_NOTIFY_AUTH_NEW_KEY 23 -#define SCTP_NOTIFY_AUTH_FREE_KEY 24 -#define SCTP_NOTIFY_NO_PEER_AUTH 25 -#define SCTP_NOTIFY_SENDER_DRY 26 -#define SCTP_NOTIFY_REMOTE_ERROR 27 -#define SCTP_NOTIFY_ASSOC_TIMEDOUT 28 - -/* This is the value for messages that are NOT completely - * copied down where we will start to split the message. - * So, with our default, we split only if the piece we - * want to take will fill up a full MTU (assuming - * a 1500 byte MTU). - */ -#define SCTP_DEFAULT_SPLIT_POINT_MIN 2904 - -/* Maximum length of diagnostic information in error causes */ -#if defined(__Userspace__) -#define SCTP_DIAG_INFO_LEN 256 -#else -#define SCTP_DIAG_INFO_LEN 128 -#endif - -/* ABORT CODES and other tell-tale location - * codes are generated by adding the below - * to the instance id. - */ - -/* File defines */ -#define SCTP_FROM_SCTP_INPUT 0x10000000 -#define SCTP_FROM_SCTP_PCB 0x20000000 -#define SCTP_FROM_SCTP_INDATA 0x30000000 -#define SCTP_FROM_SCTP_TIMER 0x40000000 -#define SCTP_FROM_SCTP_USRREQ 0x50000000 -#define SCTP_FROM_SCTPUTIL 0x60000000 -#define SCTP_FROM_SCTP6_USRREQ 0x70000000 -#define SCTP_FROM_SCTP_ASCONF 0x80000000 -#define SCTP_FROM_SCTP_OUTPUT 0x90000000 -#define SCTP_FROM_SCTP_PEELOFF 0xa0000000 -#define SCTP_FROM_SCTP_SYSCTL 0xb0000000 -#define SCTP_FROM_SCTP_CC_FUNCTIONS 0xc0000000 - -/* Location ID's */ -#define SCTP_LOC_1 0x00000001 -#define SCTP_LOC_2 0x00000002 -#define SCTP_LOC_3 0x00000003 -#define SCTP_LOC_4 0x00000004 -#define SCTP_LOC_5 0x00000005 -#define SCTP_LOC_6 0x00000006 -#define SCTP_LOC_7 0x00000007 -#define SCTP_LOC_8 0x00000008 -#define SCTP_LOC_9 0x00000009 -#define SCTP_LOC_10 0x0000000a -#define SCTP_LOC_11 0x0000000b -#define SCTP_LOC_12 0x0000000c -#define SCTP_LOC_13 0x0000000d -#define SCTP_LOC_14 0x0000000e -#define SCTP_LOC_15 0x0000000f -#define SCTP_LOC_16 0x00000010 -#define SCTP_LOC_17 0x00000011 -#define SCTP_LOC_18 0x00000012 -#define SCTP_LOC_19 0x00000013 -#define SCTP_LOC_20 0x00000014 -#define SCTP_LOC_21 0x00000015 -#define SCTP_LOC_22 0x00000016 -#define SCTP_LOC_23 0x00000017 -#define SCTP_LOC_24 0x00000018 -#define SCTP_LOC_25 0x00000019 -#define SCTP_LOC_26 0x0000001a -#define SCTP_LOC_27 0x0000001b -#define SCTP_LOC_28 0x0000001c -#define SCTP_LOC_29 0x0000001d -#define SCTP_LOC_30 0x0000001e -#define SCTP_LOC_31 0x0000001f -#define SCTP_LOC_32 0x00000020 -#define SCTP_LOC_33 0x00000021 -#define SCTP_LOC_34 0x00000022 -#define SCTP_LOC_35 0x00000023 -#define SCTP_LOC_36 0x00000024 -#define SCTP_LOC_37 0x00000025 - -/* Free assoc codes */ -#define SCTP_NORMAL_PROC 0 -#define SCTP_PCBFREE_NOFORCE 1 -#define SCTP_PCBFREE_FORCE 2 - -/* From codes for adding addresses */ -#define SCTP_ADDR_IS_CONFIRMED 8 -#define SCTP_ADDR_DYNAMIC_ADDED 6 -#define SCTP_IN_COOKIE_PROC 100 -#define SCTP_ALLOC_ASOC 1 -#define SCTP_LOAD_ADDR_2 2 -#define SCTP_LOAD_ADDR_3 3 -#define SCTP_LOAD_ADDR_4 4 -#define SCTP_LOAD_ADDR_5 5 - -#define SCTP_DONOT_SETSCOPE 0 -#define SCTP_DO_SETSCOPE 1 - -/* This value determines the default for when - * we try to add more on the send queue., if - * there is room. This prevents us from cycling - * into the copy_resume routine to often if - * we have not got enough space to add a decent - * enough size message. Note that if we have enough - * space to complete the message copy we will always - * add to the message, no matter what the size. Its - * only when we reach the point that we have some left - * to add, there is only room for part of it that we - * will use this threshold. Its also a sysctl. - */ -#define SCTP_DEFAULT_ADD_MORE 1452 - -#ifndef SCTP_PCBHASHSIZE -/* default number of association hash buckets in each endpoint */ -#define SCTP_PCBHASHSIZE 256 -#endif -#ifndef SCTP_TCBHASHSIZE -#define SCTP_TCBHASHSIZE 1024 -#endif - -#ifndef SCTP_CHUNKQUEUE_SCALE -#define SCTP_CHUNKQUEUE_SCALE 10 -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -/* clock variance is 1 ms */ -#define SCTP_CLOCK_GRANULARITY 1 -#else -/* clock variance is 10 ms */ -#define SCTP_CLOCK_GRANULARITY 10 -#endif -#define IP_HDR_SIZE 40 /* we use the size of a IP6 header here this - * detracts a small amount for ipv4 but it - * simplifies the ipv6 addition */ - -/* Argument magic number for sctp_inpcb_free() */ - -/* third argument */ -#define SCTP_CALLED_DIRECTLY_NOCMPSET 0 -#define SCTP_CALLED_AFTER_CMPSET_OFCLOSE 1 -#define SCTP_CALLED_FROM_INPKILL_TIMER 2 -/* second argument */ -#define SCTP_FREE_SHOULD_USE_ABORT 1 -#define SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE 0 - -#ifndef IPPROTO_SCTP -#define IPPROTO_SCTP 132 /* the Official IANA number :-) */ -#endif /* !IPPROTO_SCTP */ - -#define SCTP_MAX_DATA_BUNDLING 256 - -/* modular comparison */ -/* See RFC 1982 for details. */ -#define SCTP_UINT16_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \ - ((a > b) && ((uint16_t)(a - b) < (1U<<15)))) -#define SCTP_UINT16_GE(a, b) (SCTP_UINT16_GT(a, b) || (a == b)) -#define SCTP_UINT32_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \ - ((a > b) && ((uint32_t)(a - b) < (1U<<31)))) -#define SCTP_UINT32_GE(a, b) (SCTP_UINT32_GT(a, b) || (a == b)) - -#define SCTP_SSN_GT(a, b) SCTP_UINT16_GT(a, b) -#define SCTP_SSN_GE(a, b) SCTP_UINT16_GE(a, b) -#define SCTP_TSN_GT(a, b) SCTP_UINT32_GT(a, b) -#define SCTP_TSN_GE(a, b) SCTP_UINT32_GE(a, b) -#define SCTP_MID_GT(i, a, b) (((i) == 1) ? SCTP_UINT32_GT(a, b) : SCTP_UINT16_GT((uint16_t)a, (uint16_t)b)) -#define SCTP_MID_GE(i, a, b) (((i) == 1) ? SCTP_UINT32_GE(a, b) : SCTP_UINT16_GE((uint16_t)a, (uint16_t)b)) -#define SCTP_MID_EQ(i, a, b) (((i) == 1) ? a == b : (uint16_t)a == (uint16_t)b) - -/* Mapping array manipulation routines */ -#define SCTP_IS_TSN_PRESENT(arry, gap) ((arry[(gap >> 3)] >> (gap & 0x07)) & 0x01) -#define SCTP_SET_TSN_PRESENT(arry, gap) (arry[(gap >> 3)] |= (0x01 << ((gap & 0x07)))) -#define SCTP_UNSET_TSN_PRESENT(arry, gap) (arry[(gap >> 3)] &= ((~(0x01 << ((gap & 0x07)))) & 0xff)) -#define SCTP_CALC_TSN_TO_GAP(gap, tsn, mapping_tsn) do { \ - if (tsn >= mapping_tsn) { \ - gap = tsn - mapping_tsn; \ - } else { \ - gap = (MAX_TSN - mapping_tsn) + tsn + 1; \ - } \ - } while (0) - -#define SCTP_RETRAN_DONE -1 -#define SCTP_RETRAN_EXIT -2 - -/* - * This value defines the number of vtag block time wait entry's per list - * element. Each entry will take 2 4 byte ints (and of course the overhead - * of the next pointer as well). Using 15 as an example will yield * ((8 * - * 15) + 8) or 128 bytes of overhead for each timewait block that gets - * initialized. Increasing it to 31 would yield 256 bytes per block. - */ -#define SCTP_NUMBER_IN_VTAG_BLOCK 15 -/* - * If we use the STACK option, we have an array of this size head pointers. - * This array is mod'd the with the size to find which bucket and then all - * entries must be searched to see if the tag is in timed wait. If so we - * reject it. - */ -#define SCTP_STACK_VTAG_HASH_SIZE 32 - -/* - * Number of seconds of time wait for a vtag. - */ -#define SCTP_TIME_WAIT 60 - -/* How many micro seconds is the cutoff from - * local lan type rtt's - */ - /* - * We allow 900us for the rtt. - */ -#define SCTP_LOCAL_LAN_RTT 900 -#define SCTP_LAN_UNKNOWN 0 -#define SCTP_LAN_LOCAL 1 -#define SCTP_LAN_INTERNET 2 - -#define SCTP_SEND_BUFFER_SPLITTING 0x00000001 -#define SCTP_RECV_BUFFER_SPLITTING 0x00000002 - -/* The system retains a cache of free chunks such to - * cut down on calls the memory allocation system. There - * is a per association limit of free items and a overall - * system limit. If either one gets hit then the resource - * stops being cached. - */ - -#define SCTP_DEF_ASOC_RESC_LIMIT 10 -#define SCTP_DEF_SYSTEM_RESC_LIMIT 1000 - -/*- - * defines for socket lock states. - * Used by __APPLE__ - */ -#define SCTP_SO_LOCKED 1 -#define SCTP_SO_NOT_LOCKED 0 - -/*- - * For address locks, do we hold the lock? - */ -#define SCTP_ADDR_LOCKED 1 -#define SCTP_ADDR_NOT_LOCKED 0 - -#define IN4_ISPRIVATE_ADDRESS(a) \ - ((((uint8_t *)&(a)->s_addr)[0] == 10) || \ - ((((uint8_t *)&(a)->s_addr)[0] == 172) && \ - (((uint8_t *)&(a)->s_addr)[1] >= 16) && \ - (((uint8_t *)&(a)->s_addr)[1] <= 32)) || \ - ((((uint8_t *)&(a)->s_addr)[0] == 192) && \ - (((uint8_t *)&(a)->s_addr)[1] == 168))) - -#define IN4_ISLOOPBACK_ADDRESS(a) \ - (((uint8_t *)&(a)->s_addr)[0] == 127) - -#define IN4_ISLINKLOCAL_ADDRESS(a) \ - ((((uint8_t *)&(a)->s_addr)[0] == 169) && \ - (((uint8_t *)&(a)->s_addr)[1] == 254)) - -/* Maximum size of optval for IPPROTO_SCTP level socket options. */ -#define SCTP_SOCKET_OPTION_LIMIT (64 * 1024) - -#if defined(__Userspace__) -#if defined(_WIN32) -#define SCTP_GETTIME_TIMEVAL(x) getwintimeofday(x) -#define SCTP_GETPTIME_TIMEVAL(x) getwintimeofday(x) /* this doesn't seem to ever be used.. */ -#else -#define SCTP_GETTIME_TIMEVAL(x) gettimeofday(x, NULL) -#define SCTP_GETPTIME_TIMEVAL(x) gettimeofday(x, NULL) -#endif -#endif -#if defined(_KERNEL) -#define SCTP_GETTIME_TIMEVAL(x) (getmicrouptime(x)) -#define SCTP_GETPTIME_TIMEVAL(x) (microuptime(x)) -#endif - -#if defined(_KERNEL) || defined(__Userspace__) -#define sctp_sowwakeup(inp, so) \ -do { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEOUTPUT); \ - } else { \ - sowwakeup(so); \ - } \ -} while (0) - -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -#define sctp_sowwakeup_locked(inp, so) \ -do { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEOUTPUT); \ - SOCKBUF_UNLOCK(&((so)->so_snd)); \ - } else { \ - sowwakeup_locked(so); \ - } \ -} while (0) -#else -#define sctp_sowwakeup_locked(inp, so) \ -do { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEOUTPUT); \ - SOCKBUF_UNLOCK(&((so)->so_snd)); \ - } else { \ - sowwakeup(so); \ - } \ -} while (0) -#endif - -#define sctp_sorwakeup(inp, so) \ -do { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEINPUT); \ - } else { \ - sorwakeup(so); \ - } \ -} while (0) - -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -#define sctp_sorwakeup_locked(inp, so) \ -do { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEINPUT); \ - SOCKBUF_UNLOCK(&((so)->so_rcv)); \ - } else { \ - sorwakeup_locked(so); \ - } \ -} while (0) -#else - -#define sctp_sorwakeup_locked(inp, so) \ -do { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \ - sctp_pcb_add_flags(inp, SCTP_PCB_FLAGS_WAKEINPUT); \ - SOCKBUF_UNLOCK(&((so)->so_rcv)); \ - } else { \ - sorwakeup(so); \ - } \ -} while (0) -#endif - -#endif /* _KERNEL || __Userspace__*/ -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.c deleted file mode 100644 index 51b4e49d..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.c +++ /dev/null @@ -1,821 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); - -#include "opt_sctp.h" - -#include -#include -#include -#include - -#include -#include -#if defined(SCTP) || defined(SCTP_SUPPORT) -#include -#include -#endif -#else -#include -#include -#include -#include -#endif - -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) -/** - * - * Routine Description: - * - * Computes the CRC32c checksum for the specified buffer using the slicing by 8 - * algorithm over 64 bit quantities. - * - * Arguments: - * - * p_running_crc - pointer to the initial or final remainder value - * used in CRC computations. It should be set to - * non-NULL if the mode argument is equal to CONT or END - * p_buf - the packet buffer where crc computations are being performed - * length - the length of p_buf in bytes - * init_bytes - the number of initial bytes that need to be procesed before - * aligning p_buf to multiples of 4 bytes - * mode - can be any of the following: BEGIN, CONT, END, BODY, ALIGN - * - * Return value: - * - * The computed CRC32c value - */ - - -/* - * Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved - * - * - * This software program is licensed subject to the BSD License, available at - * http://www.opensource.org/licenses/bsd-license.html. - * - * Abstract: - * - * Tables for software CRC generation - */ - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o32[256] = -{ - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 -}; - -/* - * end of the CRC lookup table crc_tableil8_o32 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o40[256] = -{ - 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, - 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, - 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, - 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, - 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, - 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, - 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, - 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, - 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, - 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, - 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, - 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, - 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, - 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, - 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, - 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, - 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, - 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, - 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, - 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, - 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, - 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, - 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, - 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, - 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, - 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, - 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, - 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, - 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, - 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, - 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, - 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 -}; - -/* - * end of the CRC lookup table crc_tableil8_o40 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o48[256] = -{ - 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, - 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, - 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, - 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, - 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, - 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, - 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, - 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, - 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, - 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, - 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, - 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, - 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, - 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, - 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, - 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, - 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, - 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, - 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, - 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, - 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, - 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, - 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, - 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, - 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, - 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, - 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, - 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, - 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, - 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, - 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, - 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 -}; - -/* - * end of the CRC lookup table crc_tableil8_o48 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o56[256] = -{ - 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, - 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, - 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, - 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, - 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, - 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, - 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, - 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, - 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, - 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, - 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, - 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, - 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, - 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, - 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, - 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, - 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, - 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, - 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, - 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, - 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, - 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, - 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, - 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, - 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, - 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, - 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, - 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, - 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, - 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, - 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, - 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 -}; - -/* - * end of the CRC lookup table crc_tableil8_o56 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o64[256] = -{ - 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, - 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, - 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, - 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, - 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, - 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, - 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, - 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, - 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, - 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, - 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, - 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, - 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, - 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, - 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, - 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, - 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, - 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, - 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, - 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, - 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, - 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, - 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, - 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, - 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, - 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, - 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, - 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, - 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, - 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, - 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, - 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 -}; - -/* - * end of the CRC lookup table crc_tableil8_o64 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o72[256] = -{ - 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, - 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, - 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, - 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, - 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, - 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, - 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, - 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, - 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, - 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, - 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, - 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, - 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, - 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, - 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, - 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, - 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, - 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, - 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, - 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, - 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, - 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, - 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, - 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, - 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, - 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, - 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, - 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, - 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, - 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, - 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, - 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C -}; - -/* - * end of the CRC lookup table crc_tableil8_o72 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o80[256] = -{ - 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, - 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, - 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, - 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, - 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, - 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, - 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, - 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, - 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, - 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, - 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, - 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, - 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, - 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, - 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, - 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, - 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, - 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, - 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, - 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, - 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, - 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, - 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, - 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, - 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, - 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, - 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, - 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, - 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, - 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, - 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, - 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F -}; - -/* - * end of the CRC lookup table crc_tableil8_o80 - */ - - - -/* - * The following CRC lookup table was generated automagically using the - * following model parameters: - * - * Generator Polynomial = ................. 0x1EDC6F41 - * Generator Polynomial Length = .......... 32 bits - * Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits - * Number of Slices = ..................... 8 slices - * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 - * Directory Name = ....................... .\ - * File Name = ............................ 8x256_tables.c - */ - -static const uint32_t sctp_crc_tableil8_o88[256] = -{ - 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, - 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, - 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, - 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, - 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, - 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, - 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, - 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, - 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, - 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, - 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, - 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, - 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, - 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, - 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, - 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, - 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, - 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, - 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, - 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, - 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, - 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, - 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, - 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, - 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, - 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, - 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, - 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, - 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, - 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, - 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, - 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 -}; - -/* - * end of the CRC lookup table crc_tableil8_o88 - */ - - -static uint32_t -sctp_crc32c_sb8_64_bit(uint32_t crc, - const unsigned char *p_buf, - uint32_t length, - uint32_t init_bytes) -{ - uint32_t li; - uint32_t term1, term2; - uint32_t running_length; - uint32_t end_bytes; - - running_length = ((length - init_bytes) / 8) * 8; - end_bytes = length - init_bytes - running_length; - - for (li = 0; li < init_bytes; li++) - crc = sctp_crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ - (crc >> 8); - for (li = 0; li < running_length / 8; li++) { -#if BYTE_ORDER == BIG_ENDIAN - crc ^= *p_buf++; - crc ^= (*p_buf++) << 8; - crc ^= (*p_buf++) << 16; - crc ^= (*p_buf++) << 24; -#else - crc ^= *(const uint32_t *) p_buf; - p_buf += 4; -#endif - term1 = sctp_crc_tableil8_o88[crc & 0x000000FF] ^ - sctp_crc_tableil8_o80[(crc >> 8) & 0x000000FF]; - term2 = crc >> 16; - crc = term1 ^ - sctp_crc_tableil8_o72[term2 & 0x000000FF] ^ - sctp_crc_tableil8_o64[(term2 >> 8) & 0x000000FF]; - -#if BYTE_ORDER == BIG_ENDIAN - crc ^= sctp_crc_tableil8_o56[*p_buf++]; - crc ^= sctp_crc_tableil8_o48[*p_buf++]; - crc ^= sctp_crc_tableil8_o40[*p_buf++]; - crc ^= sctp_crc_tableil8_o32[*p_buf++]; -#else - term1 = sctp_crc_tableil8_o56[(*(const uint32_t *) p_buf) & 0x000000FF] ^ - sctp_crc_tableil8_o48[((*(const uint32_t *) p_buf) >> 8) & 0x000000FF]; - - term2 = (*(const uint32_t *) p_buf) >> 16; - crc = crc ^ - term1 ^ - sctp_crc_tableil8_o40[term2 & 0x000000FF] ^ - sctp_crc_tableil8_o32[(term2 >> 8) & 0x000000FF]; - p_buf += 4; -#endif - } - for (li = 0; li < end_bytes; li++) - crc = sctp_crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ - (crc >> 8); - return (crc); -} - - -/** - * - * Routine Description: - * - * warms the tables - * - * Arguments: - * - * none - * - * Return value: - * - * none - */ -static uint32_t -multitable_crc32c(uint32_t crc32c, - const unsigned char *buffer, - unsigned int length) -{ - uint32_t to_even_word; - - if (length == 0) { - return (crc32c); - } - to_even_word = (4 - (((uintptr_t) buffer) & 0x3)); - return (sctp_crc32c_sb8_64_bit(crc32c, buffer, length, to_even_word)); -} - -static const uint32_t sctp_crc_c[256] = { - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, - 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, - 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, - 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, - 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, - 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, - 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, - 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, - 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, - 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, - 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, - 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, - 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, - 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, - 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, - 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, - 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, - 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, - 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, - 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, - 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, - 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, - 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, - 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, - 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, - 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, - 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, - 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, - 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, - 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, - 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, - 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, - 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, -}; - - -#define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF]) - -static uint32_t -singletable_crc32c(uint32_t crc32c, - const unsigned char *buffer, - unsigned int length) -{ - unsigned int i; - - for (i = 0; i < length; i++) { - SCTP_CRC32C(crc32c, buffer[i]); - } - return (crc32c); -} - -#if defined(__Userspace__) -uint32_t -#else -static uint32_t -#endif -calculate_crc32c(uint32_t crc32c, - const unsigned char *buffer, - unsigned int length) -{ - if (length < 4) { - return (singletable_crc32c(crc32c, buffer, length)); - } else { - return (multitable_crc32c(crc32c, buffer, length)); - } -} - -#endif -#if defined(__Userspace__) -uint32_t -#else -static uint32_t -#endif -sctp_finalize_crc32c(uint32_t crc32c) -{ -#if BYTE_ORDER == BIG_ENDIAN - uint32_t byte0, byte1, byte2, byte3; -#endif - -#if BYTE_ORDER == BIG_ENDIAN - /* - * For BIG-ENDIAN platforms, the result is in LITTLE-ENDIAN byte order. - * For LITTLE-ENDIAN platforms, the result is in in BIG-ENDIAN byte - * order. So for BIG-ENDIAN platforms the bytes must be swapped to - * return the result always in network byte order (aka BIG-ENDIAN). - */ - byte0 = crc32c & 0x000000ff; - byte1 = (crc32c >> 8) & 0x000000ff; - byte2 = (crc32c >> 16) & 0x000000ff; - byte3 = (crc32c >> 24) & 0x000000ff; - crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); -#endif - return (~crc32c); -} - -static int -sctp_calculate_cksum_cb(void *arg, void *data, u_int len) -{ - uint32_t *basep; - - basep = arg; - *basep = calculate_crc32c(*basep, data, len); - return (0); -} - -/* - * Compute the SCTP checksum in network byte order for a given mbuf chain m - * which contains an SCTP packet starting at offset. - * Since this function is also called by ipfw, don't assume that - * it is compiled on a kernel with SCTP support. - */ -uint32_t -sctp_calculate_cksum(struct mbuf *m, int32_t offset) -{ - uint32_t base; - int len; - - M_ASSERTPKTHDR(m); - KASSERT(offset < m->m_pkthdr.len, - ("%s: invalid offset %u into mbuf %p", __func__, offset, m)); - - base = 0xffffffff; - len = m->m_pkthdr.len - offset; - (void)m_apply(m, offset, len, sctp_calculate_cksum_cb, &base); - return (sctp_finalize_crc32c(base)); -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP) || defined(SCTP_SUPPORT) - -VNET_DEFINE(struct sctp_base_info, system_base_info); - -/* - * Compute and insert the SCTP checksum in network byte order for a given - * mbuf chain m which contains an SCTP packet starting at offset. - */ -void -sctp_delayed_cksum(struct mbuf *m, uint32_t offset) -{ - uint32_t checksum; - - checksum = sctp_calculate_cksum(m, offset); - SCTP_STAT_DECR(sctps_sendhwcrc); - SCTP_STAT_INCR(sctps_sendswcrc); - offset += offsetof(struct sctphdr, checksum); - - if (offset + sizeof(uint32_t) > (uint32_t)(m->m_pkthdr.len)) { -#ifdef INVARIANTS - panic("sctp_delayed_cksum(): m->m_pkthdr.len: %d, offset: %u.", - m->m_pkthdr.len, offset); -#else - SCTP_PRINTF("sctp_delayed_cksum(): m->m_pkthdr.len: %d, offset: %u.\n", - m->m_pkthdr.len, offset); -#endif - return; - } - m_copyback(m, (int)offset, (int)sizeof(uint32_t), (caddr_t)&checksum); -} -#endif -#endif - diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.h deleted file mode 100644 index 18be779d..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_crc32.h +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_CRC32_H_ -#define _NETINET_SCTP_CRC32_H_ - -#if defined(_KERNEL) -uint32_t sctp_calculate_cksum(struct mbuf *, int32_t); -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP) || defined(SCTP_SUPPORT) -void sctp_delayed_cksum(struct mbuf *, uint32_t offset); -#endif -#endif -#endif /* _KERNEL */ -#if defined(__Userspace__) -uint32_t calculate_crc32c(uint32_t, const unsigned char *, unsigned int); -uint32_t sctp_finalize_crc32c(uint32_t); -uint32_t sctp_calculate_cksum(struct mbuf *, int32_t); -#endif -#endif /* __crc32c_h__ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_header.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_header.h deleted file mode 100644 index f4767f6b..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_header.h +++ /dev/null @@ -1,603 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_HEADER_H_ -#define _NETINET_SCTP_HEADER_H_ - -#if defined(_WIN32) && !defined(__Userspace__) -#include -#endif -#if !defined(_WIN32) -#include -#endif -#include -#include - -#if !defined(_WIN32) -#define SCTP_PACKED __attribute__((packed)) -#else -#pragma pack (push, 1) -#define SCTP_PACKED -#endif - -/* - * Parameter structures - */ -struct sctp_ipv4addr_param { - struct sctp_paramhdr ph;/* type=SCTP_IPV4_PARAM_TYPE, len=8 */ - uint32_t addr; /* IPV4 address */ -} SCTP_PACKED; - -#define SCTP_V6_ADDR_BYTES 16 - -struct sctp_ipv6addr_param { - struct sctp_paramhdr ph;/* type=SCTP_IPV6_PARAM_TYPE, len=20 */ - uint8_t addr[SCTP_V6_ADDR_BYTES]; /* IPV6 address */ -} SCTP_PACKED; - -/* Cookie Preservative */ -struct sctp_cookie_perserve_param { - struct sctp_paramhdr ph;/* type=SCTP_COOKIE_PRESERVE, len=8 */ - uint32_t time; /* time in ms to extend cookie */ -} SCTP_PACKED; - -#define SCTP_ARRAY_MIN_LEN 1 -/* Host Name Address */ -struct sctp_host_name_param { - struct sctp_paramhdr ph;/* type=SCTP_HOSTNAME_ADDRESS */ - char name[SCTP_ARRAY_MIN_LEN]; /* host name */ -} SCTP_PACKED; - -/* - * This is the maximum padded size of a s-a-p - * so paramheadr + 3 address types (6 bytes) + 2 byte pad = 12 - */ -#define SCTP_MAX_ADDR_PARAMS_SIZE 12 -/* supported address type */ -struct sctp_supported_addr_param { - struct sctp_paramhdr ph;/* type=SCTP_SUPPORTED_ADDRTYPE */ - uint16_t addr_type[2]; /* array of supported address types */ -} SCTP_PACKED; - -/* heartbeat info parameter */ -struct sctp_heartbeat_info_param { - struct sctp_paramhdr ph; - uint32_t time_value_1; - uint32_t time_value_2; - uint32_t random_value1; - uint32_t random_value2; - uint8_t addr_family; - uint8_t addr_len; - /* make sure that this structure is 4 byte aligned */ - uint8_t padding[2]; - char address[SCTP_ADDRMAX]; -} SCTP_PACKED; - -/* draft-ietf-tsvwg-prsctp */ -/* PR-SCTP supported parameter */ -struct sctp_prsctp_supported_param { - struct sctp_paramhdr ph; -} SCTP_PACKED; - -/* draft-ietf-tsvwg-addip-sctp */ -struct sctp_asconf_paramhdr { /* an ASCONF "parameter" */ - struct sctp_paramhdr ph;/* a SCTP parameter header */ - uint32_t correlation_id;/* correlation id for this param */ -} SCTP_PACKED; - -struct sctp_asconf_addr_param { /* an ASCONF address parameter */ - struct sctp_asconf_paramhdr aph; /* asconf "parameter" */ - struct sctp_ipv6addr_param addrp; /* max storage size */ -} SCTP_PACKED; - -struct sctp_asconf_tag_param { /* an ASCONF NAT-Vtag parameter */ - struct sctp_asconf_paramhdr aph; /* asconf "parameter" */ - uint32_t local_vtag; - uint32_t remote_vtag; -} SCTP_PACKED; - -struct sctp_asconf_addrv4_param { /* an ASCONF address (v4) parameter */ - struct sctp_asconf_paramhdr aph; /* asconf "parameter" */ - struct sctp_ipv4addr_param addrp; /* max storage size */ -} SCTP_PACKED; - -#define SCTP_MAX_SUPPORTED_EXT 256 - -struct sctp_supported_chunk_types_param { - struct sctp_paramhdr ph;/* type = 0x8008 len = x */ - uint8_t chunk_types[]; -} SCTP_PACKED; - -/* - * Structures for DATA chunks - */ -struct sctp_data { - uint32_t tsn; - uint16_t sid; - uint16_t ssn; - uint32_t ppid; - /* user data follows */ -} SCTP_PACKED; - -struct sctp_data_chunk { - struct sctp_chunkhdr ch; - struct sctp_data dp; -} SCTP_PACKED; - -struct sctp_idata { - uint32_t tsn; - uint16_t sid; - uint16_t reserved; /* Where does the SSN go? */ - uint32_t mid; - union { - uint32_t ppid; - uint32_t fsn; /* Fragment Sequence Number */ - } ppid_fsn; - /* user data follows */ -} SCTP_PACKED; - -struct sctp_idata_chunk { - struct sctp_chunkhdr ch; - struct sctp_idata dp; -} SCTP_PACKED; - -/* - * Structures for the control chunks - */ - -/* Initiate (INIT)/Initiate Ack (INIT ACK) */ -struct sctp_init { - uint32_t initiate_tag; /* initiate tag */ - uint32_t a_rwnd; /* a_rwnd */ - uint16_t num_outbound_streams; /* OS */ - uint16_t num_inbound_streams; /* MIS */ - uint32_t initial_tsn; /* I-TSN */ - /* optional param's follow */ -} SCTP_PACKED; -#define SCTP_IDENTIFICATION_SIZE 16 -#define SCTP_ADDRESS_SIZE 4 -#if defined(__Userspace__) -#define SCTP_RESERVE_SPACE 4 -#else -#define SCTP_RESERVE_SPACE 5 -#endif -/* state cookie header */ -struct sctp_state_cookie { /* this is our definition... */ - uint8_t identification[SCTP_IDENTIFICATION_SIZE];/* id of who we are */ - struct timeval time_entered; /* the time I built cookie */ - uint32_t cookie_life; /* life I will award this cookie */ - uint32_t tie_tag_my_vtag; /* my tag in old association */ - - uint32_t tie_tag_peer_vtag; /* peers tag in old association */ - uint32_t peers_vtag; /* peers tag in INIT (for quick ref) */ - - uint32_t my_vtag; /* my tag in INIT-ACK (for quick ref) */ - uint32_t address[SCTP_ADDRESS_SIZE]; /* 4 ints/128 bits */ - uint32_t addr_type; /* address type */ - uint32_t laddress[SCTP_ADDRESS_SIZE]; /* my local from address */ - uint32_t laddr_type; /* my local from address type */ - uint32_t scope_id; /* v6 scope id for link-locals */ - - uint16_t peerport; /* port address of the peer in the INIT */ - uint16_t myport; /* my port address used in the INIT */ - uint8_t ipv4_addr_legal;/* Are V4 addr legal? */ - uint8_t ipv6_addr_legal;/* Are V6 addr legal? */ -#if defined(__Userspace__) - uint8_t conn_addr_legal; -#endif - uint8_t local_scope; /* IPv6 local scope flag */ - uint8_t site_scope; /* IPv6 site scope flag */ - - uint8_t ipv4_scope; /* IPv4 private addr scope */ - uint8_t loopback_scope; /* loopback scope information */ - uint8_t rcv_edmid; /* copy of the inp value */ - uint8_t reserved[SCTP_RESERVE_SPACE]; /* Align to 64 bits */ - /* - * at the end is tacked on the INIT chunk and the INIT-ACK chunk - * (minus the cookie). - */ -} SCTP_PACKED; - -/* state cookie parameter */ -struct sctp_state_cookie_param { - struct sctp_paramhdr ph; - struct sctp_state_cookie cookie; -} SCTP_PACKED; - -struct sctp_init_chunk { - struct sctp_chunkhdr ch; - struct sctp_init init; -} SCTP_PACKED; - -struct sctp_init_msg { - struct sctphdr sh; - struct sctp_init_chunk msg; -} SCTP_PACKED; - -/* ... used for both INIT and INIT ACK */ -#define sctp_init_ack sctp_init -#define sctp_init_ack_chunk sctp_init_chunk -#define sctp_init_ack_msg sctp_init_msg - -/* Selective Ack (SACK) */ -struct sctp_gap_ack_block { - uint16_t start; /* Gap Ack block start */ - uint16_t end; /* Gap Ack block end */ -} SCTP_PACKED; - -struct sctp_sack { - uint32_t cum_tsn_ack; /* cumulative TSN Ack */ - uint32_t a_rwnd; /* updated a_rwnd of sender */ - uint16_t num_gap_ack_blks; /* number of Gap Ack blocks */ - uint16_t num_dup_tsns; /* number of duplicate TSNs */ - /* struct sctp_gap_ack_block's follow */ - /* uint32_t duplicate_tsn's follow */ -} SCTP_PACKED; - -struct sctp_sack_chunk { - struct sctp_chunkhdr ch; - struct sctp_sack sack; -} SCTP_PACKED; - -struct sctp_nr_sack { - uint32_t cum_tsn_ack; /* cumulative TSN Ack */ - uint32_t a_rwnd; /* updated a_rwnd of sender */ - uint16_t num_gap_ack_blks; /* number of Gap Ack blocks */ - uint16_t num_nr_gap_ack_blks; /* number of NR Gap Ack blocks */ - uint16_t num_dup_tsns; /* number of duplicate TSNs */ - uint16_t reserved; /* not currently used*/ - /* struct sctp_gap_ack_block's follow */ - /* uint32_t duplicate_tsn's follow */ -} SCTP_PACKED; - -struct sctp_nr_sack_chunk { - struct sctp_chunkhdr ch; - struct sctp_nr_sack nr_sack; -} SCTP_PACKED; - -/* Heartbeat Request (HEARTBEAT) */ -struct sctp_heartbeat { - struct sctp_heartbeat_info_param hb_info; -} SCTP_PACKED; - -struct sctp_heartbeat_chunk { - struct sctp_chunkhdr ch; - struct sctp_heartbeat heartbeat; -} SCTP_PACKED; - -/* ... used for Heartbeat Ack (HEARTBEAT ACK) */ -#define sctp_heartbeat_ack sctp_heartbeat -#define sctp_heartbeat_ack_chunk sctp_heartbeat_chunk - -/* Abort Asssociation (ABORT) */ -struct sctp_abort_chunk { - struct sctp_chunkhdr ch; - /* optional error cause may follow */ -} SCTP_PACKED; - -struct sctp_abort_msg { - struct sctphdr sh; - struct sctp_abort_chunk msg; -} SCTP_PACKED; - -/* Shutdown Association (SHUTDOWN) */ -struct sctp_shutdown_chunk { - struct sctp_chunkhdr ch; - uint32_t cumulative_tsn_ack; -} SCTP_PACKED; - -/* Shutdown Acknowledgment (SHUTDOWN ACK) */ -struct sctp_shutdown_ack_chunk { - struct sctp_chunkhdr ch; -} SCTP_PACKED; - -/* Operation Error (ERROR) */ -struct sctp_error_chunk { - struct sctp_chunkhdr ch; - /* optional error causes follow */ -} SCTP_PACKED; - -/* Cookie Echo (COOKIE ECHO) */ -struct sctp_cookie_echo_chunk { - struct sctp_chunkhdr ch; - struct sctp_state_cookie cookie; -} SCTP_PACKED; - -/* Cookie Acknowledgment (COOKIE ACK) */ -struct sctp_cookie_ack_chunk { - struct sctp_chunkhdr ch; -} SCTP_PACKED; - -/* Explicit Congestion Notification Echo (ECNE) */ -struct old_sctp_ecne_chunk { - struct sctp_chunkhdr ch; - uint32_t tsn; -} SCTP_PACKED; - -struct sctp_ecne_chunk { - struct sctp_chunkhdr ch; - uint32_t tsn; - uint32_t num_pkts_since_cwr; -} SCTP_PACKED; - -/* Congestion Window Reduced (CWR) */ -struct sctp_cwr_chunk { - struct sctp_chunkhdr ch; - uint32_t tsn; -} SCTP_PACKED; - -/* Shutdown Complete (SHUTDOWN COMPLETE) */ -struct sctp_shutdown_complete_chunk { - struct sctp_chunkhdr ch; -} SCTP_PACKED; - -struct sctp_adaptation_layer_indication { - struct sctp_paramhdr ph; - uint32_t indication; -} SCTP_PACKED; - -/* - * draft-ietf-tsvwg-addip-sctp - */ -/* Address/Stream Configuration Change (ASCONF) */ -struct sctp_asconf_chunk { - struct sctp_chunkhdr ch; - uint32_t serial_number; - /* lookup address parameter (mandatory) */ - /* asconf parameters follow */ -} SCTP_PACKED; - -/* Address/Stream Configuration Acknowledge (ASCONF ACK) */ -struct sctp_asconf_ack_chunk { - struct sctp_chunkhdr ch; - uint32_t serial_number; - /* asconf parameters follow */ -} SCTP_PACKED; - -/* draft-ietf-tsvwg-prsctp */ -/* Forward Cumulative TSN (FORWARD TSN) */ -struct sctp_forward_tsn_chunk { - struct sctp_chunkhdr ch; - uint32_t new_cumulative_tsn; - /* stream/sequence pairs (sctp_strseq) follow */ -} SCTP_PACKED; - -struct sctp_strseq { - uint16_t sid; - uint16_t ssn; -} SCTP_PACKED; - -struct sctp_strseq_mid { - uint16_t sid; - uint16_t flags; - uint32_t mid; -}; - -struct sctp_forward_tsn_msg { - struct sctphdr sh; - struct sctp_forward_tsn_chunk msg; -} SCTP_PACKED; - -/* should be a multiple of 4 - 1 aka 3/7/11 etc. */ - -#define SCTP_NUM_DB_TO_VERIFY 31 - -struct sctp_chunk_desc { - uint8_t chunk_type; - uint8_t data_bytes[SCTP_NUM_DB_TO_VERIFY]; - uint32_t tsn_ifany; -} SCTP_PACKED; - -struct sctp_pktdrop_chunk { - struct sctp_chunkhdr ch; - uint32_t bottle_bw; - uint32_t current_onq; - uint16_t trunc_len; - uint16_t reserved; - uint8_t data[]; -} SCTP_PACKED; - -/**********STREAM RESET STUFF ******************/ - -struct sctp_stream_reset_request { - struct sctp_paramhdr ph; - uint32_t request_seq; -} SCTP_PACKED; - -struct sctp_stream_reset_out_request { - struct sctp_paramhdr ph; - uint32_t request_seq; /* monotonically increasing seq no */ - uint32_t response_seq; /* if a response, the resp seq no */ - uint32_t send_reset_at_tsn; /* last TSN I assigned outbound */ - uint16_t list_of_streams[]; /* if not all list of streams */ -} SCTP_PACKED; - -struct sctp_stream_reset_in_request { - struct sctp_paramhdr ph; - uint32_t request_seq; - uint16_t list_of_streams[]; /* if not all list of streams */ -} SCTP_PACKED; - -struct sctp_stream_reset_tsn_request { - struct sctp_paramhdr ph; - uint32_t request_seq; -} SCTP_PACKED; - -struct sctp_stream_reset_response { - struct sctp_paramhdr ph; - uint32_t response_seq; /* if a response, the resp seq no */ - uint32_t result; -} SCTP_PACKED; - -struct sctp_stream_reset_response_tsn { - struct sctp_paramhdr ph; - uint32_t response_seq; /* if a response, the resp seq no */ - uint32_t result; - uint32_t senders_next_tsn; - uint32_t receivers_next_tsn; -} SCTP_PACKED; - -struct sctp_stream_reset_add_strm { - struct sctp_paramhdr ph; - uint32_t request_seq; - uint16_t number_of_streams; - uint16_t reserved; -} SCTP_PACKED; - -#define SCTP_STREAM_RESET_RESULT_NOTHING_TO_DO 0x00000000 /* XXX: unused */ -#define SCTP_STREAM_RESET_RESULT_PERFORMED 0x00000001 -#define SCTP_STREAM_RESET_RESULT_DENIED 0x00000002 -#define SCTP_STREAM_RESET_RESULT_ERR__WRONG_SSN 0x00000003 /* XXX: unused */ -#define SCTP_STREAM_RESET_RESULT_ERR_IN_PROGRESS 0x00000004 -#define SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO 0x00000005 -#define SCTP_STREAM_RESET_RESULT_IN_PROGRESS 0x00000006 /* XXX: unused */ - -/* - * convience structures, note that if you are making a request for specific - * streams then the request will need to be an overlay structure. - */ - -struct sctp_stream_reset_tsn_req { - struct sctp_chunkhdr ch; - struct sctp_stream_reset_tsn_request sr_req; -} SCTP_PACKED; - -struct sctp_stream_reset_resp { - struct sctp_chunkhdr ch; - struct sctp_stream_reset_response sr_resp; -} SCTP_PACKED; - -/* respone only valid with a TSN request */ -struct sctp_stream_reset_resp_tsn { - struct sctp_chunkhdr ch; - struct sctp_stream_reset_response_tsn sr_resp; -} SCTP_PACKED; - -/****************************************************/ - -/* - * Authenticated chunks support draft-ietf-tsvwg-sctp-auth - */ - -/* Should we make the max be 32? */ -#define SCTP_RANDOM_MAX_SIZE 256 -struct sctp_auth_random { - struct sctp_paramhdr ph;/* type = 0x8002 */ - uint8_t random_data[]; -} SCTP_PACKED; - -struct sctp_auth_chunk_list { - struct sctp_paramhdr ph;/* type = 0x8003 */ - uint8_t chunk_types[]; -} SCTP_PACKED; - -struct sctp_auth_hmac_algo { - struct sctp_paramhdr ph;/* type = 0x8004 */ - uint16_t hmac_ids[]; -} SCTP_PACKED; - -struct sctp_auth_chunk { - struct sctp_chunkhdr ch; - uint16_t shared_key_id; - uint16_t hmac_id; - uint8_t hmac[]; -} SCTP_PACKED; - -/* Zero checksum support draft-ietf-tsvwg-sctp-zero-checksum */ - -struct sctp_zero_checksum_acceptable { - struct sctp_paramhdr ph; - uint32_t edmid; -} SCTP_PACKED; - -/* - * we pre-reserve enough room for a ECNE or CWR AND a SACK with no missing - * pieces. If ENCE is missing we could have a couple of blocks. This way we - * optimize so we MOST likely can bundle a SACK/ECN with the smallest size - * data chunk I will split into. We could increase throughput slightly by - * taking out these two but the 24-sack/8-CWR i.e. 32 bytes I pre-reserve I - * feel is worth it for now. - */ -#ifndef SCTP_MAX_OVERHEAD -#ifdef INET6 -#define SCTP_MAX_OVERHEAD (sizeof(struct sctp_data_chunk) + \ - sizeof(struct sctphdr) + \ - sizeof(struct sctp_ecne_chunk) + \ - sizeof(struct sctp_sack_chunk) + \ - sizeof(struct ip6_hdr)) - -#define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \ - sizeof(struct sctphdr) + \ - sizeof(struct ip6_hdr)) - -#define SCTP_MIN_OVERHEAD (sizeof(struct ip6_hdr) + \ - sizeof(struct sctphdr)) - -#else -#define SCTP_MAX_OVERHEAD (sizeof(struct sctp_data_chunk) + \ - sizeof(struct sctphdr) + \ - sizeof(struct sctp_ecne_chunk) + \ - sizeof(struct sctp_sack_chunk) + \ - sizeof(struct ip)) - -#define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \ - sizeof(struct sctphdr) + \ - sizeof(struct ip)) - -#define SCTP_MIN_OVERHEAD (sizeof(struct ip) + \ - sizeof(struct sctphdr)) - -#endif /* INET6 */ -#endif /* !SCTP_MAX_OVERHEAD */ - -#define SCTP_MED_V4_OVERHEAD (sizeof(struct sctp_data_chunk) + \ - sizeof(struct sctphdr) + \ - sizeof(struct ip)) - -#define SCTP_MIN_V4_OVERHEAD (sizeof(struct ip) + \ - sizeof(struct sctphdr)) - -#if defined(_WIN32) && !defined(__Userspace__) -#include -#endif -#if defined(_WIN32) && defined(__Userspace__) -#pragma pack(pop) -#endif -#undef SCTP_PACKED -#endif /* !__sctp_header_h__ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.c deleted file mode 100644 index d084e7dd..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.c +++ /dev/null @@ -1,5793 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -/* - * NOTES: On the outbound side of things I need to check the sack timer to - * see if I should generate a sack into the chunk queue (if I have data to - * send that is and will be sending it .. for bundling. - * - * The callback in sctp_usrreq.c will get called when the socket is read from. - * This will cause sctp_service_queues() to get called on the top entry in - * the list. - */ -static uint32_t -sctp_add_chk_to_control(struct sctp_queued_to_read *control, - struct sctp_stream_in *strm, - struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_tmit_chunk *chk, int hold_rlock); - -void -sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) -{ - asoc->my_rwnd = sctp_calc_rwnd(stcb, asoc); -} - -/* Calculate what the rwnd would be */ -uint32_t -sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) -{ - uint32_t calc = 0; - - /* - * This is really set wrong with respect to a 1-2-m socket. Since - * the sb_cc is the count that everyone as put up. When we re-write - * sctp_soreceive then we will fix this so that ONLY this - * associations data is taken into account. - */ - if (stcb->sctp_socket == NULL) { - return (calc); - } - - KASSERT(asoc->cnt_on_reasm_queue > 0 || asoc->size_on_reasm_queue == 0, - ("size_on_reasm_queue is %u", asoc->size_on_reasm_queue)); - KASSERT(asoc->cnt_on_all_streams > 0 || asoc->size_on_all_streams == 0, - ("size_on_all_streams is %u", asoc->size_on_all_streams)); - if (stcb->asoc.sb_cc == 0 && - asoc->cnt_on_reasm_queue == 0 && - asoc->cnt_on_all_streams == 0) { - /* Full rwnd granted */ - calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND); - return (calc); - } - /* get actual space */ - calc = (uint32_t) sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv); - /* - * take out what has NOT been put on socket queue and we yet hold - * for putting up. - */ - calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_reasm_queue + - asoc->cnt_on_reasm_queue * MSIZE)); - calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_all_streams + - asoc->cnt_on_all_streams * MSIZE)); - if (calc == 0) { - /* out of space */ - return (calc); - } - - /* what is the overhead of all these rwnd's */ - calc = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len); - /* If the window gets too small due to ctrl-stuff, reduce it - * to 1, even it is 0. SWS engaged - */ - if (calc < stcb->asoc.my_rwnd_control_len) { - calc = 1; - } - return (calc); -} - -/* - * Build out our readq entry based on the incoming packet. - */ -struct sctp_queued_to_read * -sctp_build_readq_entry(struct sctp_tcb *stcb, - struct sctp_nets *net, - uint32_t tsn, uint32_t ppid, - uint32_t context, uint16_t sid, - uint32_t mid, uint8_t flags, - struct mbuf *dm) -{ - struct sctp_queued_to_read *read_queue_e = NULL; - - sctp_alloc_a_readq(stcb, read_queue_e); - if (read_queue_e == NULL) { - goto failed_build; - } - memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read)); - read_queue_e->sinfo_stream = sid; - read_queue_e->sinfo_flags = (flags << 8); - read_queue_e->sinfo_ppid = ppid; - read_queue_e->sinfo_context = context; - read_queue_e->sinfo_tsn = tsn; - read_queue_e->sinfo_cumtsn = tsn; - read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb); - read_queue_e->mid = mid; - read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff; - TAILQ_INIT(&read_queue_e->reasm); - read_queue_e->whoFrom = net; - atomic_add_int(&net->ref_count, 1); - read_queue_e->data = dm; - read_queue_e->stcb = stcb; - read_queue_e->port_from = stcb->rport; - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - read_queue_e->do_not_ref_stcb = 1; - } -failed_build: - return (read_queue_e); -} - -struct mbuf * -sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo) -{ - struct sctp_extrcvinfo *seinfo; - struct sctp_sndrcvinfo *outinfo; - struct sctp_rcvinfo *rcvinfo; - struct sctp_nxtinfo *nxtinfo; -#if defined(_WIN32) - WSACMSGHDR *cmh; -#else - struct cmsghdr *cmh; -#endif - struct mbuf *ret; - int len; - int use_extended; - int provide_nxt; - - if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && - sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && - sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { - /* user does not want any ancillary data */ - return (NULL); - } - - len = 0; - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) { - len += CMSG_SPACE(sizeof(struct sctp_rcvinfo)); - } - seinfo = (struct sctp_extrcvinfo *)sinfo; - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) && - (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) { - provide_nxt = 1; - len += CMSG_SPACE(sizeof(struct sctp_nxtinfo)); - } else { - provide_nxt = 0; - } - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) { - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) { - use_extended = 1; - len += CMSG_SPACE(sizeof(struct sctp_extrcvinfo)); - } else { - use_extended = 0; - len += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); - } - } else { - use_extended = 0; - } - - ret = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); - if (ret == NULL) { - /* No space */ - return (ret); - } - SCTP_BUF_LEN(ret) = 0; - - /* We need a CMSG header followed by the struct */ -#if defined(_WIN32) - cmh = mtod(ret, WSACMSGHDR *); -#else - cmh = mtod(ret, struct cmsghdr *); -#endif - /* - * Make sure that there is no un-initialized padding between - * the cmsg header and cmsg data and after the cmsg data. - */ - memset(cmh, 0, len); - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) { - cmh->cmsg_level = IPPROTO_SCTP; - cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_rcvinfo)); - cmh->cmsg_type = SCTP_RCVINFO; - rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmh); - rcvinfo->rcv_sid = sinfo->sinfo_stream; - rcvinfo->rcv_ssn = sinfo->sinfo_ssn; - rcvinfo->rcv_flags = sinfo->sinfo_flags; - rcvinfo->rcv_ppid = sinfo->sinfo_ppid; - rcvinfo->rcv_tsn = sinfo->sinfo_tsn; - rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn; - rcvinfo->rcv_context = sinfo->sinfo_context; - rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id; -#if defined(_WIN32) - cmh = (WSACMSGHDR *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo))); -#else - cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo))); -#endif - SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_rcvinfo)); - } - if (provide_nxt) { - cmh->cmsg_level = IPPROTO_SCTP; - cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo)); - cmh->cmsg_type = SCTP_NXTINFO; - nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh); - nxtinfo->nxt_sid = seinfo->serinfo_next_stream; - nxtinfo->nxt_flags = 0; - if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) { - nxtinfo->nxt_flags |= SCTP_UNORDERED; - } - if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) { - nxtinfo->nxt_flags |= SCTP_NOTIFICATION; - } - if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) { - nxtinfo->nxt_flags |= SCTP_COMPLETE; - } - nxtinfo->nxt_ppid = seinfo->serinfo_next_ppid; - nxtinfo->nxt_length = seinfo->serinfo_next_length; - nxtinfo->nxt_assoc_id = seinfo->serinfo_next_aid; -#if defined(_WIN32) - cmh = (WSACMSGHDR *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo))); -#else - cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo))); -#endif - SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo)); - } - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) { - cmh->cmsg_level = IPPROTO_SCTP; - outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh); - if (use_extended) { - cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_extrcvinfo)); - cmh->cmsg_type = SCTP_EXTRCV; - memcpy(outinfo, sinfo, sizeof(struct sctp_extrcvinfo)); - SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_extrcvinfo)); - } else { - cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); - cmh->cmsg_type = SCTP_SNDRCV; - *outinfo = *sinfo; - SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); - } - } - return (ret); -} - -static void -sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn) -{ - uint32_t gap, i; - int in_r, in_nr; - - if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { - return; - } - if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) { - /* - * This tsn is behind the cum ack and thus we don't - * need to worry about it being moved from one to the other. - */ - return; - } - SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); - in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap); - in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap); - KASSERT(in_r || in_nr, ("%s: Things are really messed up now", __func__)); - if (!in_nr) { - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = tsn; - } - } - if (in_r) { - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - if (tsn == asoc->highest_tsn_inside_map) { - /* We must back down to see what the new highest is. */ - for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) { - SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn); - if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { - asoc->highest_tsn_inside_map = i; - break; - } - } - if (!SCTP_TSN_GE(i, asoc->mapping_array_base_tsn)) { - asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1; - } - } - } -} - -static int -sctp_place_control_in_stream(struct sctp_stream_in *strm, - struct sctp_association *asoc, - struct sctp_queued_to_read *control) -{ - struct sctp_queued_to_read *at; - struct sctp_readhead *q; - uint8_t flags, unordered; - - flags = (control->sinfo_flags >> 8); - unordered = flags & SCTP_DATA_UNORDERED; - if (unordered) { - q = &strm->uno_inqueue; - if (asoc->idata_supported == 0) { - if (!TAILQ_EMPTY(q)) { - /* Only one stream can be here in old style -- abort */ - return (-1); - } - TAILQ_INSERT_TAIL(q, control, next_instrm); - control->on_strm_q = SCTP_ON_UNORDERED; - return (0); - } - } else { - q = &strm->inqueue; - } - if ((flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { - control->end_added = 1; - control->first_frag_seen = 1; - control->last_frag_seen = 1; - } - if (TAILQ_EMPTY(q)) { - /* Empty queue */ - TAILQ_INSERT_HEAD(q, control, next_instrm); - if (unordered) { - control->on_strm_q = SCTP_ON_UNORDERED; - } else { - control->on_strm_q = SCTP_ON_ORDERED; - } - return (0); - } else { - TAILQ_FOREACH(at, q, next_instrm) { - if (SCTP_MID_GT(asoc->idata_supported, at->mid, control->mid)) { - /* - * one in queue is bigger than the - * new one, insert before this one - */ - TAILQ_INSERT_BEFORE(at, control, next_instrm); - if (unordered) { - control->on_strm_q = SCTP_ON_UNORDERED; - } else { - control->on_strm_q = SCTP_ON_ORDERED; - } - break; - } else if (SCTP_MID_EQ(asoc->idata_supported, at->mid, control->mid)) { - /* - * Gak, He sent me a duplicate msg - * id number?? return -1 to abort. - */ - return (-1); - } else { - if (TAILQ_NEXT(at, next_instrm) == NULL) { - /* - * We are at the end, insert - * it after this one - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, at, - SCTP_STR_LOG_FROM_INSERT_TL); - } - TAILQ_INSERT_AFTER(q, at, control, next_instrm); - if (unordered) { - control->on_strm_q = SCTP_ON_UNORDERED; - } else { - control->on_strm_q = SCTP_ON_ORDERED; - } - break; - } - } - } - } - return (0); -} - -static void -sctp_abort_in_reasm(struct sctp_tcb *stcb, - struct sctp_queued_to_read *control, - struct sctp_tmit_chunk *chk, - int *abort_flag, int opspot) -{ - char msg[SCTP_DIAG_INFO_LEN]; - struct mbuf *oper; - - if (stcb->asoc.idata_supported) { - SCTP_SNPRINTF(msg, sizeof(msg), - "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x", - opspot, - control->fsn_included, - chk->rec.data.tsn, - chk->rec.data.sid, - chk->rec.data.fsn, chk->rec.data.mid); - } else { - SCTP_SNPRINTF(msg, sizeof(msg), - "Reass %x,CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x,SSN:%4.4x", - opspot, - control->fsn_included, - chk->rec.data.tsn, - chk->rec.data.sid, - chk->rec.data.fsn, - (uint16_t)chk->rec.data.mid); - } - oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - sctp_m_freem(chk->data); - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; - sctp_abort_an_association(stcb->sctp_ep, stcb, oper, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; -} - -static void -sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control) -{ - /* - * The control could not be placed and must be cleaned. - */ - struct sctp_tmit_chunk *chk, *nchk; - TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - if (chk->data) - sctp_m_freem(chk->data); - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - sctp_free_remote_addr(control->whoFrom); - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_free_a_readq(stcb, control); -} - -/* - * Queue the chunk either right into the socket buffer if it is the next one - * to go OR put it in the correct place in the delivery queue. If we do - * append to the so_buf, keep doing so until we are out of order as - * long as the control's entered are non-fragmented. - */ -static void -sctp_queue_data_to_stream(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm) -{ - /* - * FIX-ME maybe? What happens when the ssn wraps? If we are getting - * all the data in one stream this could happen quite rapidly. One - * could use the TSN to keep track of things, but this scheme breaks - * down in the other type of stream usage that could occur. Send a - * single msg to stream 0, send 4Billion messages to stream 1, now - * send a message to stream 0. You have a situation where the TSN - * has wrapped but not in the stream. Is this worth worrying about - * or should we just change our queue sort at the bottom to be by - * TSN. - * - * Could it also be legal for a peer to send ssn 1 with TSN 2 and ssn 2 - * with TSN 1? If the peer is doing some sort of funky TSN/SSN - * assignment this could happen... and I don't see how this would be - * a violation. So for now I am undecided an will leave the sort by - * SSN alone. Maybe a hybrid approach is the answer - * - */ - struct sctp_queued_to_read *at; - int queue_needed; - uint32_t nxt_todel; - struct mbuf *op_err; - struct sctp_stream_in *strm; - char msg[SCTP_DIAG_INFO_LEN]; - - strm = &asoc->strmin[control->sinfo_stream]; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD); - } - if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) { - /* The incoming sseq is behind where we last delivered? */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n", - strm->last_mid_delivered, control->mid); - /* - * throw it in the stream so it gets cleaned up in - * association destruction - */ - TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm); - if (asoc->idata_supported) { - SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x", - strm->last_mid_delivered, control->sinfo_tsn, - control->sinfo_stream, control->mid); - } else { - SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - (uint16_t)strm->last_mid_delivered, - control->sinfo_tsn, - control->sinfo_stream, - (uint16_t)control->mid); - } - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - queue_needed = 1; - asoc->size_on_all_streams += control->length; - sctp_ucount_incr(asoc->cnt_on_all_streams); - nxt_todel = strm->last_mid_delivered + 1; - if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - /* can be delivered right away? */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL); - } - /* EY it wont be queued if it could be delivered directly */ - queue_needed = 0; - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - strm->last_mid_delivered++; - sctp_mark_non_revokable(asoc, control->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED); - TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) { - /* all delivered */ - nxt_todel = strm->last_mid_delivered + 1; - if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) && - (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) { - if (control->on_strm_q == SCTP_ON_ORDERED) { - TAILQ_REMOVE(&strm->inqueue, control, next_instrm); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); -#ifdef INVARIANTS - } else { - panic("Huh control: %p is on_strm_q: %d", - control, control->on_strm_q); -#endif - } - control->on_strm_q = 0; - strm->last_mid_delivered++; - /* - * We ignore the return of deliver_data here - * since we always can hold the chunk on the - * d-queue. And we have a finite number that - * can be delivered from the strq. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, NULL, - SCTP_STR_LOG_FROM_IMMED_DEL); - } - sctp_mark_non_revokable(asoc, control->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, - SCTP_SO_LOCKED); - continue; - } else if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) { - *need_reasm = 1; - } - break; - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - if (queue_needed) { - /* - * Ok, we did not deliver this guy, find the correct place - * to put it on the queue. - */ - if (sctp_place_control_in_stream(strm, asoc, control)) { - SCTP_SNPRINTF(msg, sizeof(msg), - "Queue to str MID: %u duplicate", control->mid); - sctp_clean_up_control(stcb, control); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - } - } -} - -static void -sctp_setup_tail_pointer(struct sctp_queued_to_read *control) -{ - struct mbuf *m, *prev = NULL; - struct sctp_tcb *stcb; - - stcb = control->stcb; - control->held_length = 0; - control->length = 0; - m = control->data; - while (m) { - if (SCTP_BUF_LEN(m) == 0) { - /* Skip mbufs with NO length */ - if (prev == NULL) { - /* First one */ - control->data = sctp_m_free(m); - m = control->data; - } else { - SCTP_BUF_NEXT(prev) = sctp_m_free(m); - m = SCTP_BUF_NEXT(prev); - } - if (m == NULL) { - control->tail_mbuf = prev; - } - continue; - } - prev = m; - atomic_add_int(&control->length, SCTP_BUF_LEN(m)); - if (control->on_read_q) { - /* - * On read queue so we must increment the - * SB stuff, we assume caller has done any locks of SB. - */ - sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); - } - m = SCTP_BUF_NEXT(m); - } - if (prev) { - control->tail_mbuf = prev; - } -} - -static void -sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added) -{ - struct mbuf *prev=NULL; - struct sctp_tcb *stcb; - - stcb = control->stcb; - if (stcb == NULL) { -#ifdef INVARIANTS - panic("Control broken"); -#else - return; -#endif - } - if (control->tail_mbuf == NULL) { - /* TSNH */ - sctp_m_freem(control->data); - control->data = m; - sctp_setup_tail_pointer(control); - return; - } - control->tail_mbuf->m_next = m; - while (m) { - if (SCTP_BUF_LEN(m) == 0) { - /* Skip mbufs with NO length */ - if (prev == NULL) { - /* First one */ - control->tail_mbuf->m_next = sctp_m_free(m); - m = control->tail_mbuf->m_next; - } else { - SCTP_BUF_NEXT(prev) = sctp_m_free(m); - m = SCTP_BUF_NEXT(prev); - } - if (m == NULL) { - control->tail_mbuf = prev; - } - continue; - } - prev = m; - if (control->on_read_q) { - /* - * On read queue so we must increment the - * SB stuff, we assume caller has done any locks of SB. - */ - sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); - } - *added += SCTP_BUF_LEN(m); - atomic_add_int(&control->length, SCTP_BUF_LEN(m)); - m = SCTP_BUF_NEXT(m); - } - if (prev) { - control->tail_mbuf = prev; - } -} - -static void -sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control) -{ - memset(nc, 0, sizeof(struct sctp_queued_to_read)); - nc->sinfo_stream = control->sinfo_stream; - nc->mid = control->mid; - TAILQ_INIT(&nc->reasm); - nc->top_fsn = control->top_fsn; - nc->mid = control->mid; - nc->sinfo_flags = control->sinfo_flags; - nc->sinfo_ppid = control->sinfo_ppid; - nc->sinfo_context = control->sinfo_context; - nc->fsn_included = 0xffffffff; - nc->sinfo_tsn = control->sinfo_tsn; - nc->sinfo_cumtsn = control->sinfo_cumtsn; - nc->sinfo_assoc_id = control->sinfo_assoc_id; - nc->whoFrom = control->whoFrom; - atomic_add_int(&nc->whoFrom->ref_count, 1); - nc->stcb = control->stcb; - nc->port_from = control->port_from; - nc->do_not_ref_stcb = control->do_not_ref_stcb; -} - -static void -sctp_reset_a_control(struct sctp_queued_to_read *control, - struct sctp_inpcb *inp, uint32_t tsn) -{ - control->fsn_included = tsn; - if (control->on_read_q) { - /* - * We have to purge it from there, - * hopefully this will work :-) - */ - TAILQ_REMOVE(&inp->read_queue, control, next); - control->on_read_q = 0; - } -} - -static int -sctp_handle_old_unordered_data(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_stream_in *strm, - struct sctp_queued_to_read *control, - uint32_t pd_point, - int inp_read_lock_held) -{ - /* Special handling for the old un-ordered data chunk. - * All the chunks/TSN's go to mid 0. So - * we have to do the old style watching to see - * if we have it all. If you return one, no other - * control entries on the un-ordered queue will - * be looked at. In theory there should be no others - * entries in reality, unless the guy is sending both - * unordered NDATA and unordered DATA... - */ - struct sctp_tmit_chunk *chk, *lchk, *tchk; - uint32_t fsn; - struct sctp_queued_to_read *nc; - int cnt_added; - - if (control->first_frag_seen == 0) { - /* Nothing we can do, we have not seen the first piece yet */ - return (1); - } - /* Collapse any we can */ - cnt_added = 0; -restart: - fsn = control->fsn_included + 1; - /* Now what can we add? */ - TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) { - if (chk->rec.data.fsn == fsn) { - /* Ok lets add it */ - sctp_alloc_a_readq(stcb, nc); - if (nc == NULL) { - break; - } - memset(nc, 0, sizeof(struct sctp_queued_to_read)); - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - sctp_add_chk_to_control(control, strm, stcb, asoc, chk, inp_read_lock_held); - fsn++; - cnt_added++; - chk = NULL; - if (control->end_added) { - /* We are done */ - if (!TAILQ_EMPTY(&control->reasm)) { - /* - * Ok we have to move anything left on - * the control queue to a new control. - */ - sctp_build_readq_entry_from_ctl(nc, control); - tchk = TAILQ_FIRST(&control->reasm); - if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - TAILQ_REMOVE(&control->reasm, tchk, sctp_next); - if (asoc->size_on_reasm_queue >= tchk->send_size) { - asoc->size_on_reasm_queue -= tchk->send_size; - } else { -#ifdef INVARIANTS - panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size); -#else - asoc->size_on_reasm_queue = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - nc->first_frag_seen = 1; - nc->fsn_included = tchk->rec.data.fsn; - nc->data = tchk->data; - nc->sinfo_ppid = tchk->rec.data.ppid; - nc->sinfo_tsn = tchk->rec.data.tsn; - sctp_mark_non_revokable(asoc, tchk->rec.data.tsn); - tchk->data = NULL; - sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED); - sctp_setup_tail_pointer(nc); - tchk = TAILQ_FIRST(&control->reasm); - } - /* Spin the rest onto the queue */ - while (tchk) { - TAILQ_REMOVE(&control->reasm, tchk, sctp_next); - TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next); - tchk = TAILQ_FIRST(&control->reasm); - } - /* Now lets add it to the queue after removing control */ - TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm); - nc->on_strm_q = SCTP_ON_UNORDERED; - if (control->on_strm_q) { - TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); - control->on_strm_q = 0; - } - } - if (control->pdapi_started) { - strm->pd_api_started = 0; - control->pdapi_started = 0; - } - if (control->on_strm_q) { - TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); - control->on_strm_q = 0; - SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); - } - if (control->on_read_q == 0) { - sctp_add_to_readq(stcb->sctp_ep, stcb, control, - &stcb->sctp_socket->so_rcv, control->end_added, - inp_read_lock_held, SCTP_SO_NOT_LOCKED); -#if defined(__Userspace__) - } else { - sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, inp_read_lock_held); -#endif - } - sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) { - /* Switch to the new guy and continue */ - control = nc; - goto restart; - } else { - if (nc->on_strm_q == 0) { - sctp_free_a_readq(stcb, nc); - } - } - return (1); - } else { - sctp_free_a_readq(stcb, nc); - } - } else { - /* Can't add more */ - break; - } - } - if (cnt_added && strm->pd_api_started) { -#if defined(__Userspace__) - sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, inp_read_lock_held); -#endif - sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - } - if ((control->length > pd_point) && (strm->pd_api_started == 0)) { - strm->pd_api_started = 1; - control->pdapi_started = 1; - sctp_add_to_readq(stcb->sctp_ep, stcb, control, - &stcb->sctp_socket->so_rcv, control->end_added, - inp_read_lock_held, SCTP_SO_NOT_LOCKED); - sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - return (0); - } else { - return (1); - } -} - -static void -sctp_inject_old_unordered_data(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_queued_to_read *control, - struct sctp_tmit_chunk *chk, - int *abort_flag) -{ - struct sctp_tmit_chunk *at; - int inserted; - /* - * Here we need to place the chunk into the control structure - * sorted in the correct order. - */ - if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - /* Its the very first one. */ - SCTPDBG(SCTP_DEBUG_XXX, - "chunk is a first fsn: %u becomes fsn_included\n", - chk->rec.data.fsn); - at = TAILQ_FIRST(&control->reasm); - if (at && SCTP_TSN_GT(chk->rec.data.fsn, at->rec.data.fsn)) { - /* - * The first chunk in the reassembly is - * a smaller TSN than this one, even though - * this has a first, it must be from a subsequent - * msg. - */ - goto place_chunk; - } - if (control->first_frag_seen) { - /* - * In old un-ordered we can reassembly on - * one control multiple messages. As long - * as the next FIRST is greater then the old - * first (TSN i.e. FSN wise) - */ - struct mbuf *tdata; - uint32_t tmp; - - if (SCTP_TSN_GT(chk->rec.data.fsn, control->fsn_included)) { - /* Easy way the start of a new guy beyond the lowest */ - goto place_chunk; - } - if ((chk->rec.data.fsn == control->fsn_included) || - (control->pdapi_started)) { - /* - * Ok this should not happen, if it does - * we started the pd-api on the higher TSN (since - * the equals part is a TSN failure it must be that). - * - * We are completely hosed in that case since I have - * no way to recover. This really will only happen - * if we can get more TSN's higher before the pd-api-point. - */ - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_4); - - return; - } - /* - * Ok we have two firsts and the one we just got - * is smaller than the one we previously placed.. yuck! - * We must swap them out. - */ - /* swap the mbufs */ - tdata = control->data; - control->data = chk->data; - chk->data = tdata; - /* Save the lengths */ - chk->send_size = control->length; - /* Recompute length of control and tail pointer */ - sctp_setup_tail_pointer(control); - /* Fix the FSN included */ - tmp = control->fsn_included; - control->fsn_included = chk->rec.data.fsn; - chk->rec.data.fsn = tmp; - /* Fix the TSN included */ - tmp = control->sinfo_tsn; - control->sinfo_tsn = chk->rec.data.tsn; - chk->rec.data.tsn = tmp; - /* Fix the PPID included */ - tmp = control->sinfo_ppid; - control->sinfo_ppid = chk->rec.data.ppid; - chk->rec.data.ppid = tmp; - /* Fix tail pointer */ - goto place_chunk; - } - control->first_frag_seen = 1; - control->fsn_included = chk->rec.data.fsn; - control->top_fsn = chk->rec.data.fsn; - control->sinfo_tsn = chk->rec.data.tsn; - control->sinfo_ppid = chk->rec.data.ppid; - control->data = chk->data; - sctp_mark_non_revokable(asoc, chk->rec.data.tsn); - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - sctp_setup_tail_pointer(control); - return; - } -place_chunk: - inserted = 0; - TAILQ_FOREACH(at, &control->reasm, sctp_next) { - if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) { - /* - * This one in queue is bigger than the new one, insert - * the new one before at. - */ - asoc->size_on_reasm_queue += chk->send_size; - sctp_ucount_incr(asoc->cnt_on_reasm_queue); - inserted = 1; - TAILQ_INSERT_BEFORE(at, chk, sctp_next); - break; - } else if (at->rec.data.fsn == chk->rec.data.fsn) { - /* - * They sent a duplicate fsn number. This - * really should not happen since the FSN is - * a TSN and it should have been dropped earlier. - */ - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_5); - return; - } - } - if (inserted == 0) { - /* Its at the end */ - asoc->size_on_reasm_queue += chk->send_size; - sctp_ucount_incr(asoc->cnt_on_reasm_queue); - control->top_fsn = chk->rec.data.fsn; - TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next); - } -} - -static int -sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_in *strm, int inp_read_lock_held) -{ - /* - * Given a stream, strm, see if any of - * the SSN's on it that are fragmented - * are ready to deliver. If so go ahead - * and place them on the read queue. In - * so placing if we have hit the end, then - * we need to remove them from the stream's queue. - */ - struct sctp_queued_to_read *control, *nctl = NULL; - uint32_t next_to_del; - uint32_t pd_point; - int ret = 0; - - if (stcb->sctp_socket) { - pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, - stcb->sctp_ep->partial_delivery_point); - } else { - pd_point = stcb->sctp_ep->partial_delivery_point; - } - control = TAILQ_FIRST(&strm->uno_inqueue); - - if ((control != NULL) && - (asoc->idata_supported == 0)) { - /* Special handling needed for "old" data format */ - if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) { - goto done_un; - } - } - if (strm->pd_api_started) { - /* Can't add more */ - return (0); - } - while (control) { - SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n", - control, control->end_added, control->mid, control->top_fsn, control->fsn_included); - nctl = TAILQ_NEXT(control, next_instrm); - if (control->end_added) { - /* We just put the last bit on */ - if (control->on_strm_q) { -#ifdef INVARIANTS - if (control->on_strm_q != SCTP_ON_UNORDERED) { - panic("Huh control: %p on_q: %d -- not unordered?", - control, control->on_strm_q); - } -#endif - SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); - TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - control->on_strm_q = 0; - } - if (control->on_read_q == 0) { - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, control->end_added, - inp_read_lock_held, SCTP_SO_NOT_LOCKED); - } - } else { - /* Can we do a PD-API for this un-ordered guy? */ - if ((control->length >= pd_point) && (strm->pd_api_started == 0)) { - strm->pd_api_started = 1; - control->pdapi_started = 1; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, control->end_added, - inp_read_lock_held, SCTP_SO_NOT_LOCKED); - - break; - } - } - control = nctl; - } -done_un: - control = TAILQ_FIRST(&strm->inqueue); - if (strm->pd_api_started) { - /* Can't add more */ - return (0); - } - if (control == NULL) { - return (ret); - } - if (SCTP_MID_EQ(asoc->idata_supported, strm->last_mid_delivered, control->mid)) { - /* Ok the guy at the top was being partially delivered - * completed, so we remove it. Note - * the pd_api flag was taken off when the - * chunk was merged on in sctp_queue_data_for_reasm below. - */ - nctl = TAILQ_NEXT(control, next_instrm); - SCTPDBG(SCTP_DEBUG_XXX, - "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n", - control, control->end_added, control->mid, - control->top_fsn, control->fsn_included, - strm->last_mid_delivered); - if (control->end_added) { - if (control->on_strm_q) { -#ifdef INVARIANTS - if (control->on_strm_q != SCTP_ON_ORDERED) { - panic("Huh control: %p on_q: %d -- not ordered?", - control, control->on_strm_q); - } -#endif - SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); - TAILQ_REMOVE(&strm->inqueue, control, next_instrm); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - control->on_strm_q = 0; - } - if (strm->pd_api_started && control->pdapi_started) { - control->pdapi_started = 0; - strm->pd_api_started = 0; - } - if (control->on_read_q == 0) { - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, control->end_added, - inp_read_lock_held, SCTP_SO_NOT_LOCKED); - } - control = nctl; - } - } - if (strm->pd_api_started) { - /* Can't add more must have gotten an un-ordered above being partially delivered. */ - return (0); - } -deliver_more: - next_to_del = strm->last_mid_delivered + 1; - if (control) { - SCTPDBG(SCTP_DEBUG_XXX, - "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n", - control, control->end_added, control->mid, control->top_fsn, control->fsn_included, - next_to_del); - nctl = TAILQ_NEXT(control, next_instrm); - if (SCTP_MID_EQ(asoc->idata_supported, control->mid, next_to_del) && - (control->first_frag_seen)) { - int done; - - /* Ok we can deliver it onto the stream. */ - if (control->end_added) { - /* We are done with it afterwards */ - if (control->on_strm_q) { -#ifdef INVARIANTS - if (control->on_strm_q != SCTP_ON_ORDERED) { - panic("Huh control: %p on_q: %d -- not ordered?", - control, control->on_strm_q); - } -#endif - SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); - TAILQ_REMOVE(&strm->inqueue, control, next_instrm); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - control->on_strm_q = 0; - } - ret++; - } - if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { - /* A singleton now slipping through - mark it non-revokable too */ - sctp_mark_non_revokable(asoc, control->sinfo_tsn); - } else if (control->end_added == 0) { - /* Check if we can defer adding until its all there */ - if ((control->length < pd_point) || (strm->pd_api_started)) { - /* Don't need it or cannot add more (one being delivered that way) */ - goto out; - } - } - done = (control->end_added) && (control->last_frag_seen); - if (control->on_read_q == 0) { - if (!done) { - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - strm->pd_api_started = 1; - control->pdapi_started = 1; - } - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, control->end_added, - inp_read_lock_held, SCTP_SO_NOT_LOCKED); - } - strm->last_mid_delivered = next_to_del; - if (done) { - control = nctl; - goto deliver_more; - } - } - } -out: - return (ret); -} - -uint32_t -sctp_add_chk_to_control(struct sctp_queued_to_read *control, - struct sctp_stream_in *strm, - struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_tmit_chunk *chk, int hold_rlock) -{ - /* - * Given a control and a chunk, merge the - * data from the chk onto the control and free - * up the chunk resources. - */ - uint32_t added=0; - int i_locked = 0; - - if (control->on_read_q && (hold_rlock == 0)) { - /* - * Its being pd-api'd so we must - * do some locks. - */ - SCTP_INP_READ_LOCK(stcb->sctp_ep); - i_locked = 1; - } - if (control->data == NULL) { - control->data = chk->data; - sctp_setup_tail_pointer(control); - } else { - sctp_add_to_tail_pointer(control, chk->data, &added); - } - control->fsn_included = chk->rec.data.fsn; - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - sctp_mark_non_revokable(asoc, chk->rec.data.tsn); - chk->data = NULL; - if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - control->first_frag_seen = 1; - control->sinfo_tsn = chk->rec.data.tsn; - control->sinfo_ppid = chk->rec.data.ppid; - } - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - /* Its complete */ - if ((control->on_strm_q) && (control->on_read_q)) { - if (control->pdapi_started) { - control->pdapi_started = 0; - strm->pd_api_started = 0; - } - if (control->on_strm_q == SCTP_ON_UNORDERED) { - /* Unordered */ - TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); - control->on_strm_q = 0; - } else if (control->on_strm_q == SCTP_ON_ORDERED) { - /* Ordered */ - TAILQ_REMOVE(&strm->inqueue, control, next_instrm); - /* - * Don't need to decrement size_on_all_streams, - * since control is on the read queue. - */ - sctp_ucount_decr(asoc->cnt_on_all_streams); - control->on_strm_q = 0; -#ifdef INVARIANTS - } else if (control->on_strm_q) { - panic("Unknown state on ctrl: %p on_strm_q: %d", control, - control->on_strm_q); -#endif - } - } - control->end_added = 1; - control->last_frag_seen = 1; - } - if (i_locked) { - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return (added); -} - -/* - * Dump onto the re-assembly queue, in its proper place. After dumping on the - * queue, see if anthing can be delivered. If so pull it off (or as much as - * we can. If we run out of space then we must dump what we can and set the - * appropriate flag to say we queued what we could. - */ -static void -sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_queued_to_read *control, - struct sctp_tmit_chunk *chk, - int created_control, - int *abort_flag, uint32_t tsn) -{ - uint32_t next_fsn; - struct sctp_tmit_chunk *at, *nat; - struct sctp_stream_in *strm; - int do_wakeup, unordered; - uint32_t lenadded; - - strm = &asoc->strmin[control->sinfo_stream]; - /* - * For old un-ordered data chunks. - */ - if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { - unordered = 1; - } else { - unordered = 0; - } - /* Must be added to the stream-in queue */ - if (created_control) { - if ((unordered == 0) || (asoc->idata_supported)) { - sctp_ucount_incr(asoc->cnt_on_all_streams); - } - if (sctp_place_control_in_stream(strm, asoc, control)) { - /* Duplicate SSN? */ - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_6); - sctp_clean_up_control(stcb, control); - return; - } - if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) { - /* Ok we created this control and now - * lets validate that its legal i.e. there - * is a B bit set, if not and we have - * up to the cum-ack then its invalid. - */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_7); - return; - } - } - } - if ((asoc->idata_supported == 0) && (unordered == 1)) { - sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag); - return; - } - /* - * Ok we must queue the chunk into the reasembly portion: - * o if its the first it goes to the control mbuf. - * o if its not first but the next in sequence it goes to the control, - * and each succeeding one in order also goes. - * o if its not in order we place it on the list in its place. - */ - if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - /* Its the very first one. */ - SCTPDBG(SCTP_DEBUG_XXX, - "chunk is a first fsn: %u becomes fsn_included\n", - chk->rec.data.fsn); - if (control->first_frag_seen) { - /* - * Error on senders part, they either - * sent us two data chunks with FIRST, - * or they sent two un-ordered chunks that - * were fragmented at the same time in the same stream. - */ - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_8); - return; - } - control->first_frag_seen = 1; - control->sinfo_ppid = chk->rec.data.ppid; - control->sinfo_tsn = chk->rec.data.tsn; - control->fsn_included = chk->rec.data.fsn; - control->data = chk->data; - sctp_mark_non_revokable(asoc, chk->rec.data.tsn); - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - sctp_setup_tail_pointer(control); - asoc->size_on_all_streams += control->length; - } else { - /* Place the chunk in our list */ - int inserted=0; - if (control->last_frag_seen == 0) { - /* Still willing to raise highest FSN seen */ - if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) { - SCTPDBG(SCTP_DEBUG_XXX, - "We have a new top_fsn: %u\n", - chk->rec.data.fsn); - control->top_fsn = chk->rec.data.fsn; - } - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - SCTPDBG(SCTP_DEBUG_XXX, - "The last fsn is now in place fsn: %u\n", - chk->rec.data.fsn); - control->last_frag_seen = 1; - if (SCTP_TSN_GT(control->top_fsn, chk->rec.data.fsn)) { - SCTPDBG(SCTP_DEBUG_XXX, - "New fsn: %u is not at top_fsn: %u -- abort\n", - chk->rec.data.fsn, - control->top_fsn); - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_9); - return; - } - } - if (asoc->idata_supported || control->first_frag_seen) { - /* - * For IDATA we always check since we know that - * the first fragment is 0. For old DATA we have - * to receive the first before we know the first FSN - * (which is the TSN). - */ - if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) { - /* We have already delivered up to this so its a dup */ - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_10); - return; - } - } - } else { - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - /* Second last? huh? */ - SCTPDBG(SCTP_DEBUG_XXX, - "Duplicate last fsn: %u (top: %u) -- abort\n", - chk->rec.data.fsn, control->top_fsn); - sctp_abort_in_reasm(stcb, control, - chk, abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_11); - return; - } - if (asoc->idata_supported || control->first_frag_seen) { - /* - * For IDATA we always check since we know that - * the first fragment is 0. For old DATA we have - * to receive the first before we know the first FSN - * (which is the TSN). - */ - - if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) { - /* We have already delivered up to this so its a dup */ - SCTPDBG(SCTP_DEBUG_XXX, - "New fsn: %u is already seen in included_fsn: %u -- abort\n", - chk->rec.data.fsn, control->fsn_included); - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_12); - return; - } - } - /* validate not beyond top FSN if we have seen last one */ - if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) { - SCTPDBG(SCTP_DEBUG_XXX, - "New fsn: %u is beyond or at top_fsn: %u -- abort\n", - chk->rec.data.fsn, - control->top_fsn); - sctp_abort_in_reasm(stcb, control, chk, - abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_13); - return; - } - } - /* - * If we reach here, we need to place the - * new chunk in the reassembly for this - * control. - */ - SCTPDBG(SCTP_DEBUG_XXX, - "chunk is a not first fsn: %u needs to be inserted\n", - chk->rec.data.fsn); - TAILQ_FOREACH(at, &control->reasm, sctp_next) { - if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) { - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - /* Last not at the end? huh? */ - SCTPDBG(SCTP_DEBUG_XXX, - "Last fragment not last in list: -- abort\n"); - sctp_abort_in_reasm(stcb, control, - chk, abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_14); - return; - } - /* - * This one in queue is bigger than the new one, insert - * the new one before at. - */ - SCTPDBG(SCTP_DEBUG_XXX, - "Insert it before fsn: %u\n", - at->rec.data.fsn); - asoc->size_on_reasm_queue += chk->send_size; - sctp_ucount_incr(asoc->cnt_on_reasm_queue); - TAILQ_INSERT_BEFORE(at, chk, sctp_next); - inserted = 1; - break; - } else if (at->rec.data.fsn == chk->rec.data.fsn) { - /* Gak, He sent me a duplicate str seq number */ - /* - * foo bar, I guess I will just free this new guy, - * should we abort too? FIX ME MAYBE? Or it COULD be - * that the SSN's have wrapped. Maybe I should - * compare to TSN somehow... sigh for now just blow - * away the chunk! - */ - SCTPDBG(SCTP_DEBUG_XXX, - "Duplicate to fsn: %u -- abort\n", - at->rec.data.fsn); - sctp_abort_in_reasm(stcb, control, - chk, abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_15); - return; - } - } - if (inserted == 0) { - /* Goes on the end */ - SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n", - chk->rec.data.fsn); - asoc->size_on_reasm_queue += chk->send_size; - sctp_ucount_incr(asoc->cnt_on_reasm_queue); - TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next); - } - } - /* - * Ok lets see if we can suck any up into the control - * structure that are in seq if it makes sense. - */ - do_wakeup = 0; - /* - * If the first fragment has not been - * seen there is no sense in looking. - */ - if (control->first_frag_seen) { - next_fsn = control->fsn_included + 1; - TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) { - if (at->rec.data.fsn == next_fsn) { - /* We can add this one now to the control */ - SCTPDBG(SCTP_DEBUG_XXX, - "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n", - control, at, - at->rec.data.fsn, - next_fsn, control->fsn_included); - TAILQ_REMOVE(&control->reasm, at, sctp_next); - lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD); - if (control->on_read_q) { - do_wakeup = 1; - } else { - /* - * We only add to the size-on-all-streams - * if its not on the read q. The read q - * flag will cause a sballoc so its accounted - * for there. - */ - asoc->size_on_all_streams += lenadded; - } - next_fsn++; - if (control->end_added && control->pdapi_started) { - if (strm->pd_api_started) { - strm->pd_api_started = 0; - control->pdapi_started = 0; - } - if (control->on_read_q == 0) { - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, control->end_added, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - } - break; - } - } else { - break; - } - } - } - if (do_wakeup) { -#if defined(__Userspace__) - sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, SCTP_READ_LOCK_NOT_HELD); -#endif - /* Need to wakeup the reader */ - sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - } -} - -static struct sctp_queued_to_read * -sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t mid, int ordered, int idata_supported) -{ - struct sctp_queued_to_read *control; - - if (ordered) { - TAILQ_FOREACH(control, &strm->inqueue, next_instrm) { - if (SCTP_MID_EQ(idata_supported, control->mid, mid)) { - break; - } - } - } else { - if (idata_supported) { - TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) { - if (SCTP_MID_EQ(idata_supported, control->mid, mid)) { - break; - } - } - } else { - control = TAILQ_FIRST(&strm->uno_inqueue); - } - } - return (control); -} - -static int -sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct mbuf **m, int offset, int chk_length, - struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag, - int *break_flag, int last_chunk, uint8_t chk_type) -{ - struct sctp_tmit_chunk *chk = NULL; /* make gcc happy */ - struct sctp_stream_in *strm; - uint32_t tsn, fsn, gap, mid; - struct mbuf *dmbuf; - int the_len; - int need_reasm_check = 0; - uint16_t sid; - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - struct sctp_queued_to_read *control, *ncontrol; - uint32_t ppid; - uint8_t chk_flags; - struct sctp_stream_reset_list *liste; - int ordered; - size_t clen; - int created_control = 0; - - if (chk_type == SCTP_IDATA) { - struct sctp_idata_chunk *chunk, chunk_buf; - - chunk = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset, - sizeof(struct sctp_idata_chunk), (uint8_t *)&chunk_buf); - chk_flags = chunk->ch.chunk_flags; - clen = sizeof(struct sctp_idata_chunk); - tsn = ntohl(chunk->dp.tsn); - sid = ntohs(chunk->dp.sid); - mid = ntohl(chunk->dp.mid); - if (chk_flags & SCTP_DATA_FIRST_FRAG) { - fsn = 0; - ppid = chunk->dp.ppid_fsn.ppid; - } else { - fsn = ntohl(chunk->dp.ppid_fsn.fsn); - ppid = 0xffffffff; /* Use as an invalid value. */ - } - } else { - struct sctp_data_chunk *chunk, chunk_buf; - - chunk = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset, - sizeof(struct sctp_data_chunk), (uint8_t *)&chunk_buf); - chk_flags = chunk->ch.chunk_flags; - clen = sizeof(struct sctp_data_chunk); - tsn = ntohl(chunk->dp.tsn); - sid = ntohs(chunk->dp.sid); - mid = (uint32_t)(ntohs(chunk->dp.ssn)); - fsn = tsn; - ppid = chunk->dp.ppid; - } - if ((size_t)chk_length == clen) { - /* - * Need to send an abort since we had a - * empty data chunk. - */ - op_err = sctp_generate_no_user_data_cause(tsn); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return (0); - } - if ((chk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) { - asoc->send_sack = 1; - } - ordered = ((chk_flags & SCTP_DATA_UNORDERED) == 0); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS); - } - if (stcb == NULL) { - return (0); - } - SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, chk_type, tsn); - if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) { - /* It is a duplicate */ - SCTP_STAT_INCR(sctps_recvdupdata); - if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { - /* Record a dup for the next outbound sack */ - asoc->dup_tsns[asoc->numduptsns] = tsn; - asoc->numduptsns++; - } - asoc->send_sack = 1; - return (0); - } - /* Calculate the number of TSN's between the base and this TSN */ - SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); - if (gap >= (SCTP_MAPPING_ARRAY << 3)) { - /* Can't hold the bit in the mapping at max array, toss it */ - return (0); - } - if (gap >= (uint32_t) (asoc->mapping_array_size << 3)) { - SCTP_TCB_LOCK_ASSERT(stcb); - if (sctp_expand_mapping_array(asoc, gap)) { - /* Can't expand, drop it */ - return (0); - } - } - if (SCTP_TSN_GT(tsn, *high_tsn)) { - *high_tsn = tsn; - } - /* See if we have received this one already */ - if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap) || - SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap)) { - SCTP_STAT_INCR(sctps_recvdupdata); - if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) { - /* Record a dup for the next outbound sack */ - asoc->dup_tsns[asoc->numduptsns] = tsn; - asoc->numduptsns++; - } - asoc->send_sack = 1; - return (0); - } - /* - * Check to see about the GONE flag, duplicates would cause a sack - * to be sent up above - */ - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))) { - /* - * wait a minute, this guy is gone, there is no longer a - * receiver. Send peer an ABORT! - */ - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return (0); - } - /* - * Now before going further we see if there is room. If NOT then we - * MAY let one through only IF this TSN is the one we are waiting - * for on a partial delivery API. - */ - - /* Is the stream valid? */ - if (sid >= asoc->streamincnt) { - struct sctp_error_invalid_stream *cause; - - op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream), - 0, M_NOWAIT, 1, MT_DATA); - if (op_err != NULL) { - /* add some space up front so prepend will work well */ - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - cause = mtod(op_err, struct sctp_error_invalid_stream *); - /* - * Error causes are just param's and this one has - * two back to back phdr, one with the error type - * and size, the other with the streamid and a rsvd - */ - SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream); - cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM); - cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream)); - cause->stream_id = htons(sid); - cause->reserved = htons(0); - sctp_queue_op_err(stcb, op_err); - } - SCTP_STAT_INCR(sctps_badsid); - SCTP_TCB_LOCK_ASSERT(stcb); - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = tsn; - } - if (tsn == (asoc->cumulative_tsn + 1)) { - /* Update cum-ack */ - asoc->cumulative_tsn = tsn; - } - return (0); - } - /* - * If its a fragmented message, lets see if we can - * find the control on the reassembly queues. - */ - if ((chk_type == SCTP_IDATA) && - ((chk_flags & SCTP_DATA_FIRST_FRAG) == 0) && - (fsn == 0)) { - /* - * The first *must* be fsn 0, and other - * (middle/end) pieces can *not* be fsn 0. - * XXX: This can happen in case of a wrap around. - * Ignore is for now. - */ - SCTP_SNPRINTF(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x", mid, chk_flags); - goto err_out; - } - control = sctp_find_reasm_entry(&asoc->strmin[sid], mid, ordered, asoc->idata_supported); - SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n", - chk_flags, control); - if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) { - /* See if we can find the re-assembly entity */ - if (control != NULL) { - /* We found something, does it belong? */ - if (ordered && (mid != control->mid)) { - SCTP_SNPRINTF(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid); - err_out: - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return (0); - } - if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) { - /* We can't have a switched order with an unordered chunk */ - SCTP_SNPRINTF(msg, sizeof(msg), - "All fragments of a user message must be ordered or unordered (TSN=%8.8x)", - tsn); - goto err_out; - } - if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) { - /* We can't have a switched unordered with a ordered chunk */ - SCTP_SNPRINTF(msg, sizeof(msg), - "All fragments of a user message must be ordered or unordered (TSN=%8.8x)", - tsn); - goto err_out; - } - } - } else { - /* Its a complete segment. Lets validate we - * don't have a re-assembly going on with - * the same Stream/Seq (for ordered) or in - * the same Stream for unordered. - */ - if (control != NULL) { - if (ordered || asoc->idata_supported) { - SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on MID: %u\n", - chk_flags, mid); - SCTP_SNPRINTF(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid); - goto err_out; - } else { - if ((tsn == control->fsn_included + 1) && - (control->end_added == 0)) { - SCTP_SNPRINTF(msg, sizeof(msg), - "Illegal message sequence, missing end for MID: %8.8x", - control->fsn_included); - goto err_out; - } else { - control = NULL; - } - } - } - } - /* now do the tests */ - if (((asoc->cnt_on_all_streams + - asoc->cnt_on_reasm_queue + - asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) || - (((int)asoc->my_rwnd) <= 0)) { - /* - * When we have NO room in the rwnd we check to make sure - * the reader is doing its job... - */ - if (SCTP_SBAVAIL(&stcb->sctp_socket->so_rcv) > 0) { - /* some to read, wake-up */ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return (0); - } -#endif - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - /* now is it in the mapping array of what we have accepted? */ - if (chk_type == SCTP_DATA) { - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) && - SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - /* Nope not in the valid range dump it */ - dump_packet: - sctp_set_rwnd(stcb, asoc); - if ((asoc->cnt_on_all_streams + - asoc->cnt_on_reasm_queue + - asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) { - SCTP_STAT_INCR(sctps_datadropchklmt); - } else { - SCTP_STAT_INCR(sctps_datadroprwnd); - } - *break_flag = 1; - return (0); - } - } else { - if (control == NULL) { - goto dump_packet; - } - if (SCTP_TSN_GT(fsn, control->top_fsn)) { - goto dump_packet; - } - } - } -#ifdef SCTP_ASOCLOG_OF_TSNS - SCTP_TCB_LOCK_ASSERT(stcb); - if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) { - asoc->tsn_in_at = 0; - asoc->tsn_in_wrapped = 1; - } - asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn; - asoc->in_tsnlog[asoc->tsn_in_at].strm = sid; - asoc->in_tsnlog[asoc->tsn_in_at].seq = mid; - asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length; - asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags; - asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb; - asoc->in_tsnlog[asoc->tsn_in_at].in_pos = asoc->tsn_in_at; - asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1; - asoc->tsn_in_at++; -#endif - /* - * Before we continue lets validate that we are not being fooled by - * an evil attacker. We can only have Nk chunks based on our TSN - * spread allowed by the mapping array N * 8 bits, so there is no - * way our stream sequence numbers could have wrapped. We of course - * only validate the FIRST fragment so the bit must be set. - */ - if ((chk_flags & SCTP_DATA_FIRST_FRAG) && - (TAILQ_EMPTY(&asoc->resetHead)) && - (chk_flags & SCTP_DATA_UNORDERED) == 0 && - SCTP_MID_GE(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered, mid)) { - /* The incoming sseq is behind where we last delivered? */ - SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n", - mid, asoc->strmin[sid].last_mid_delivered); - - if (asoc->idata_supported) { - SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x", - asoc->strmin[sid].last_mid_delivered, - tsn, - sid, - mid); - } else { - SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - (uint16_t)asoc->strmin[sid].last_mid_delivered, - tsn, - sid, - (uint16_t)mid); - } - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return (0); - } - if (chk_type == SCTP_IDATA) { - the_len = (chk_length - sizeof(struct sctp_idata_chunk)); - } else { - the_len = (chk_length - sizeof(struct sctp_data_chunk)); - } - if (last_chunk == 0) { - if (chk_type == SCTP_IDATA) { - dmbuf = SCTP_M_COPYM(*m, - (offset + sizeof(struct sctp_idata_chunk)), - the_len, M_NOWAIT); - } else { - dmbuf = SCTP_M_COPYM(*m, - (offset + sizeof(struct sctp_data_chunk)), - the_len, M_NOWAIT); - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY); - } -#endif - } else { - /* We can steal the last chunk */ - int l_len; - dmbuf = *m; - /* lop off the top part */ - if (chk_type == SCTP_IDATA) { - m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk))); - } else { - m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk))); - } - if (SCTP_BUF_NEXT(dmbuf) == NULL) { - l_len = SCTP_BUF_LEN(dmbuf); - } else { - /* need to count up the size hopefully - * does not hit this to often :-0 - */ - struct mbuf *lat; - - l_len = 0; - for (lat = dmbuf; lat; lat = SCTP_BUF_NEXT(lat)) { - l_len += SCTP_BUF_LEN(lat); - } - } - if (l_len > the_len) { - /* Trim the end round bytes off too */ - m_adj(dmbuf, -(l_len - the_len)); - } - } - if (dmbuf == NULL) { - SCTP_STAT_INCR(sctps_nomem); - return (0); - } - /* - * Now no matter what, we need a control, get one - * if we don't have one (we may have gotten it - * above when we found the message was fragmented - */ - if (control == NULL) { - sctp_alloc_a_readq(stcb, control); - sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn, - ppid, - sid, - chk_flags, - NULL, fsn, mid); - if (control == NULL) { - SCTP_STAT_INCR(sctps_nomem); - return (0); - } - if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { - struct mbuf *mm; - - control->data = dmbuf; - control->tail_mbuf = NULL; - for (mm = control->data; mm; mm = mm->m_next) { - control->length += SCTP_BUF_LEN(mm); - if (SCTP_BUF_NEXT(mm) == NULL) { - control->tail_mbuf = mm; - } - } - control->end_added = 1; - control->last_frag_seen = 1; - control->first_frag_seen = 1; - control->fsn_included = fsn; - control->top_fsn = fsn; - } - created_control = 1; - } - SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d MID: %u control: %p\n", - chk_flags, ordered, mid, control); - if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG && - TAILQ_EMPTY(&asoc->resetHead) && - ((ordered == 0) || - (SCTP_MID_EQ(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered + 1, mid) && - TAILQ_EMPTY(&asoc->strmin[sid].inqueue)))) { - /* Candidate for express delivery */ - /* - * Its not fragmented, No PD-API is up, Nothing in the - * delivery queue, Its un-ordered OR ordered and the next to - * deliver AND nothing else is stuck on the stream queue, - * And there is room for it in the socket buffer. Lets just - * stuff it up the buffer.... - */ - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = tsn; - } - SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (MID: %u)\n", - control, mid); - - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, &stcb->sctp_socket->so_rcv, - 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - - if ((chk_flags & SCTP_DATA_UNORDERED) == 0) { - /* for ordered, bump what we delivered */ - asoc->strmin[sid].last_mid_delivered++; - } - SCTP_STAT_INCR(sctps_recvexpress); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del_alt(stcb, tsn, mid, sid, - SCTP_STR_LOG_FROM_EXPRS_DEL); - } - control = NULL; - goto finish_express_del; - } - - /* Now will we need a chunk too? */ - if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) { - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* No memory so we drop the chunk */ - SCTP_STAT_INCR(sctps_nomem); - if (last_chunk == 0) { - /* we copied it, free the copy */ - sctp_m_freem(dmbuf); - } - return (0); - } - chk->rec.data.tsn = tsn; - chk->no_fr_allowed = 0; - chk->rec.data.fsn = fsn; - chk->rec.data.mid = mid; - chk->rec.data.sid = sid; - chk->rec.data.ppid = ppid; - chk->rec.data.context = stcb->asoc.context; - chk->rec.data.doing_fast_retransmit = 0; - chk->rec.data.rcv_flags = chk_flags; - chk->asoc = asoc; - chk->send_size = the_len; - chk->whoTo = net; - SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (MID: %u)\n", - chk, - control, mid); - atomic_add_int(&net->ref_count, 1); - chk->data = dmbuf; - } - /* Set the appropriate TSN mark */ - if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = tsn; - } - } else { - SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) { - asoc->highest_tsn_inside_map = tsn; - } - } - /* Now is it complete (i.e. not fragmented)? */ - if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { - /* - * Special check for when streams are resetting. We - * could be more smart about this and check the - * actual stream to see if it is not being reset.. - * that way we would not create a HOLB when amongst - * streams being reset and those not being reset. - * - */ - if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && - SCTP_TSN_GT(tsn, liste->tsn)) { - /* - * yep its past where we need to reset... go - * ahead and queue it. - */ - if (TAILQ_EMPTY(&asoc->pending_reply_queue)) { - /* first one on */ - TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); - } else { - struct sctp_queued_to_read *lcontrol, *nlcontrol; - unsigned char inserted = 0; - TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) { - if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) { - continue; - } else { - /* found it */ - TAILQ_INSERT_BEFORE(lcontrol, control, next); - inserted = 1; - break; - } - } - if (inserted == 0) { - /* - * must be put at end, use - * prevP (all setup from - * loop) to setup nextP. - */ - TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); - } - } - goto finish_express_del; - } - if (chk_flags & SCTP_DATA_UNORDERED) { - /* queue directly into socket buffer */ - SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p MID: %u\n", - control, mid); - sctp_mark_non_revokable(asoc, control->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - - } else { - SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering MID: %u\n", control, - mid); - sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check); - if (*abort_flag) { - if (last_chunk) { - *m = NULL; - } - return (0); - } - } - goto finish_express_del; - } - /* If we reach here its a reassembly */ - need_reasm_check = 1; - SCTPDBG(SCTP_DEBUG_XXX, - "Queue data to stream for reasm control: %p MID: %u\n", - control, mid); - sctp_queue_data_for_reasm(stcb, asoc, control, chk, created_control, abort_flag, tsn); - if (*abort_flag) { - /* - * the assoc is now gone and chk was put onto the - * reasm queue, which has all been freed. - */ - if (last_chunk) { - *m = NULL; - } - return (0); - } -finish_express_del: - /* Here we tidy up things */ - if (tsn == (asoc->cumulative_tsn + 1)) { - /* Update cum-ack */ - asoc->cumulative_tsn = tsn; - } - if (last_chunk) { - *m = NULL; - } - if (ordered) { - SCTP_STAT_INCR_COUNTER64(sctps_inorderchunks); - } else { - SCTP_STAT_INCR_COUNTER64(sctps_inunorderchunks); - } - SCTP_STAT_INCR(sctps_recvdata); - /* Set it present please */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del_alt(stcb, tsn, mid, sid, SCTP_STR_LOG_FROM_MARK_TSN); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, - asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE); - } - if (need_reasm_check) { - (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[sid], SCTP_READ_LOCK_NOT_HELD); - need_reasm_check = 0; - } - /* check the special flag for stream resets */ - if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && - SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) { - /* - * we have finished working through the backlogged TSN's now - * time to reset streams. 1: call reset function. 2: free - * pending_reply space 3: distribute any chunks in - * pending_reply_queue. - */ - sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams); - TAILQ_REMOVE(&asoc->resetHead, liste, next_resp); - sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED); - SCTP_FREE(liste, SCTP_M_STRESET); - /*sa_ignore FREED_MEMORY*/ - liste = TAILQ_FIRST(&asoc->resetHead); - if (TAILQ_EMPTY(&asoc->resetHead)) { - /* All can be removed */ - TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) { - TAILQ_REMOVE(&asoc->pending_reply_queue, control, next); - strm = &asoc->strmin[control->sinfo_stream]; - sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check); - if (*abort_flag) { - return (0); - } - if (need_reasm_check) { - (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD); - need_reasm_check = 0; - } - } - } else { - TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) { - if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) { - break; - } - /* - * if control->sinfo_tsn is <= liste->tsn we can - * process it which is the NOT of - * control->sinfo_tsn > liste->tsn - */ - TAILQ_REMOVE(&asoc->pending_reply_queue, control, next); - strm = &asoc->strmin[control->sinfo_stream]; - sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check); - if (*abort_flag) { - return (0); - } - if (need_reasm_check) { - (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD); - need_reasm_check = 0; - } - } - } - } - return (1); -} - -static const int8_t sctp_map_lookup_tab[256] = { - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 5, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 6, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 5, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 7, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 5, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 6, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 5, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 4, - 0, 1, 0, 2, 0, 1, 0, 3, - 0, 1, 0, 2, 0, 1, 0, 8 -}; - -void -sctp_slide_mapping_arrays(struct sctp_tcb *stcb) -{ - /* - * Now we also need to check the mapping array in a couple of ways. - * 1) Did we move the cum-ack point? - * - * When you first glance at this you might think - * that all entries that make up the position - * of the cum-ack would be in the nr-mapping array - * only.. i.e. things up to the cum-ack are always - * deliverable. Thats true with one exception, when - * its a fragmented message we may not deliver the data - * until some threshold (or all of it) is in place. So - * we must OR the nr_mapping_array and mapping_array to - * get a true picture of the cum-ack. - */ - struct sctp_association *asoc; - int at; - uint8_t val; - int slide_from, slide_end, lgap, distance; - uint32_t old_cumack, old_base, old_highest, highest_tsn; - - asoc = &stcb->asoc; - - old_cumack = asoc->cumulative_tsn; - old_base = asoc->mapping_array_base_tsn; - old_highest = asoc->highest_tsn_inside_map; - /* - * We could probably improve this a small bit by calculating the - * offset of the current cum-ack as the starting point. - */ - at = 0; - for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) { - val = asoc->nr_mapping_array[slide_from] | asoc->mapping_array[slide_from]; - if (val == 0xff) { - at += 8; - } else { - /* there is a 0 bit */ - at += sctp_map_lookup_tab[val]; - break; - } - } - asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at-1); - - if (SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_map) && - SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_nr_map)) { -#ifdef INVARIANTS - panic("huh, cumack 0x%x greater than high-tsn 0x%x in map", - asoc->cumulative_tsn, asoc->highest_tsn_inside_map); -#else - SCTP_PRINTF("huh, cumack 0x%x greater than high-tsn 0x%x in map - should panic?\n", - asoc->cumulative_tsn, asoc->highest_tsn_inside_map); - sctp_print_mapping_array(asoc); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(0, 6, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); - } - asoc->highest_tsn_inside_map = asoc->cumulative_tsn; - asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn; -#endif - } - if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) { - highest_tsn = asoc->highest_tsn_inside_nr_map; - } else { - highest_tsn = asoc->highest_tsn_inside_map; - } - if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) { - /* The complete array was completed by a single FR */ - /* highest becomes the cum-ack */ - int clr; -#ifdef INVARIANTS - unsigned int i; -#endif - - /* clear the array */ - clr = ((at+7) >> 3); - if (clr > asoc->mapping_array_size) { - clr = asoc->mapping_array_size; - } - memset(asoc->mapping_array, 0, clr); - memset(asoc->nr_mapping_array, 0, clr); -#ifdef INVARIANTS - for (i = 0; i < asoc->mapping_array_size; i++) { - if ((asoc->mapping_array[i]) || (asoc->nr_mapping_array[i])) { - SCTP_PRINTF("Error Mapping array's not clean at clear\n"); - sctp_print_mapping_array(asoc); - } - } -#endif - asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1; - asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map = asoc->cumulative_tsn; - } else if (at >= 8) { - /* we can slide the mapping array down */ - /* slide_from holds where we hit the first NON 0xff byte */ - - /* - * now calculate the ceiling of the move using our highest - * TSN value - */ - SCTP_CALC_TSN_TO_GAP(lgap, highest_tsn, asoc->mapping_array_base_tsn); - slide_end = (lgap >> 3); - if (slide_end < slide_from) { - sctp_print_mapping_array(asoc); -#ifdef INVARIANTS - panic("impossible slide"); -#else - SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n", - lgap, slide_end, slide_from, at); - return; -#endif - } - if (slide_end > asoc->mapping_array_size) { -#ifdef INVARIANTS - panic("would overrun buffer"); -#else - SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n", - asoc->mapping_array_size, slide_end); - slide_end = asoc->mapping_array_size; -#endif - } - distance = (slide_end - slide_from) + 1; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(old_base, old_cumack, old_highest, - SCTP_MAP_PREPARE_SLIDE); - sctp_log_map((uint32_t) slide_from, (uint32_t) slide_end, - (uint32_t) lgap, SCTP_MAP_SLIDE_FROM); - } - if (distance + slide_from > asoc->mapping_array_size || - distance < 0) { - /* - * Here we do NOT slide forward the array so that - * hopefully when more data comes in to fill it up - * we will be able to slide it forward. Really I - * don't think this should happen :-0 - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map((uint32_t) distance, (uint32_t) slide_from, - (uint32_t) asoc->mapping_array_size, - SCTP_MAP_SLIDE_NONE); - } - } else { - int ii; - - for (ii = 0; ii < distance; ii++) { - asoc->mapping_array[ii] = asoc->mapping_array[slide_from + ii]; - asoc->nr_mapping_array[ii] = asoc->nr_mapping_array[slide_from + ii]; - } - for (ii = distance; ii < asoc->mapping_array_size; ii++) { - asoc->mapping_array[ii] = 0; - asoc->nr_mapping_array[ii] = 0; - } - if (asoc->highest_tsn_inside_map + 1 == asoc->mapping_array_base_tsn) { - asoc->highest_tsn_inside_map += (slide_from << 3); - } - if (asoc->highest_tsn_inside_nr_map + 1 == asoc->mapping_array_base_tsn) { - asoc->highest_tsn_inside_nr_map += (slide_from << 3); - } - asoc->mapping_array_base_tsn += (slide_from << 3); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(asoc->mapping_array_base_tsn, - asoc->cumulative_tsn, asoc->highest_tsn_inside_map, - SCTP_MAP_SLIDE_RESULT); - } - } - } -} - -void -sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) -{ - struct sctp_association *asoc; - uint32_t highest_tsn; - int is_a_gap; - - sctp_slide_mapping_arrays(stcb); - asoc = &stcb->asoc; - if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) { - highest_tsn = asoc->highest_tsn_inside_nr_map; - } else { - highest_tsn = asoc->highest_tsn_inside_map; - } - /* Is there a gap now? */ - is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn); - - /* - * Now we need to see if we need to queue a sack or just start the - * timer (if allowed). - */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) { - /* - * Ok special case, in SHUTDOWN-SENT case. here we - * maker sure SACK timer is off and instead send a - * SHUTDOWN and a SACK - */ - if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_19); - } - sctp_send_shutdown(stcb, - ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination)); - if (is_a_gap) { - sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); - } - } else { - /* - * CMT DAC algorithm: increase number of packets - * received since last ack - */ - stcb->asoc.cmt_dac_pkts_rcvd++; - - if ((stcb->asoc.send_sack == 1) || /* We need to send a SACK */ - ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no - * longer is one */ - (stcb->asoc.numduptsns) || /* we have dup's */ - (is_a_gap) || /* is still a gap */ - (stcb->asoc.delayed_ack == 0) || /* Delayed sack disabled */ - (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq)) { /* hit limit of pkts */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) && - (stcb->asoc.send_sack == 0) && - (stcb->asoc.numduptsns == 0) && - (stcb->asoc.delayed_ack) && - (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) { - /* - * CMT DAC algorithm: With CMT, - * delay acks even in the face of - * reordering. Therefore, if acks - * that do not have to be sent - * because of the above reasons, - * will be delayed. That is, acks - * that would have been sent due to - * gap reports will be delayed with - * DAC. Start the delayed ack timer. - */ - sctp_timer_start(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); - } else { - /* - * Ok we must build a SACK since the - * timer is pending, we got our - * first packet OR there are gaps or - * duplicates. - */ - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); - sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); - } - } else { - if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); - } - } - } -} - -int -sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, - struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net, uint32_t *high_tsn) -{ - struct sctp_chunkhdr *ch, chunk_buf; - struct sctp_association *asoc; - int num_chunks = 0; /* number of control chunks processed */ - int stop_proc = 0; - int break_flag, last_chunk; - int abort_flag = 0, was_a_gap; - struct mbuf *m; - uint32_t highest_tsn; - uint16_t chk_length; - - /* set the rwnd */ - sctp_set_rwnd(stcb, &stcb->asoc); - - m = *mm; - SCTP_TCB_LOCK_ASSERT(stcb); - asoc = &stcb->asoc; - if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) { - highest_tsn = asoc->highest_tsn_inside_nr_map; - } else { - highest_tsn = asoc->highest_tsn_inside_map; - } - was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn); - /* - * setup where we got the last DATA packet from for any SACK that - * may need to go out. Don't bump the net. This is done ONLY when a - * chunk is assigned. - */ - asoc->last_data_chunk_from = net; - - /*- - * Now before we proceed we must figure out if this is a wasted - * cluster... i.e. it is a small packet sent in and yet the driver - * underneath allocated a full cluster for it. If so we must copy it - * to a smaller mbuf and free up the cluster mbuf. This will help - * with cluster starvation. - */ - if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) { - /* we only handle mbufs that are singletons.. not chains */ - m = sctp_get_mbuf_for_msg(SCTP_BUF_LEN(m), 0, M_NOWAIT, 1, MT_DATA); - if (m) { - /* ok lets see if we can copy the data up */ - caddr_t *from, *to; - /* get the pointers and copy */ - to = mtod(m, caddr_t *); - from = mtod((*mm), caddr_t *); - memcpy(to, from, SCTP_BUF_LEN((*mm))); - /* copy the length and free up the old */ - SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm)); - sctp_m_freem(*mm); - /* success, back copy */ - *mm = m; - } else { - /* We are in trouble in the mbuf world .. yikes */ - m = *mm; - } - } - /* get pointer to the first chunk header */ - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_chunkhdr), - (uint8_t *)&chunk_buf); - if (ch == NULL) { - return (1); - } - /* - * process all DATA chunks... - */ - *high_tsn = asoc->cumulative_tsn; - break_flag = 0; - asoc->data_pkts_seen++; - while (stop_proc == 0) { - /* validate chunk length */ - chk_length = ntohs(ch->chunk_length); - if (length - *offset < chk_length) { - /* all done, mutulated chunk */ - stop_proc = 1; - continue; - } - if ((asoc->idata_supported == 1) && - (ch->chunk_type == SCTP_DATA)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated"); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return (2); - } - if ((asoc->idata_supported == 0) && - (ch->chunk_type == SCTP_IDATA)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated"); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22; - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return (2); - } - if ((ch->chunk_type == SCTP_DATA) || - (ch->chunk_type == SCTP_IDATA)) { - uint16_t clen; - - if (ch->chunk_type == SCTP_DATA) { - clen = sizeof(struct sctp_data_chunk); - } else { - clen = sizeof(struct sctp_idata_chunk); - } - if (chk_length < clen) { - /* - * Need to send an abort since we had a - * invalid data chunk. - */ - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "%s chunk of length %u", - ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA", - chk_length); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23; - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return (2); - } -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xB1, 0); -#endif - if (SCTP_SIZE32(chk_length) == (length - *offset)) { - last_chunk = 1; - } else { - last_chunk = 0; - } - if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, - chk_length, net, high_tsn, &abort_flag, &break_flag, - last_chunk, ch->chunk_type)) { - num_chunks++; - } - if (abort_flag) - return (2); - - if (break_flag) { - /* - * Set because of out of rwnd space and no - * drop rep space left. - */ - stop_proc = 1; - continue; - } - } else { - /* not a data chunk in the data region */ - switch (ch->chunk_type) { - case SCTP_INITIATION: - case SCTP_INITIATION_ACK: - case SCTP_SELECTIVE_ACK: - case SCTP_NR_SELECTIVE_ACK: - case SCTP_HEARTBEAT_REQUEST: - case SCTP_HEARTBEAT_ACK: - case SCTP_ABORT_ASSOCIATION: - case SCTP_SHUTDOWN: - case SCTP_SHUTDOWN_ACK: - case SCTP_OPERATION_ERROR: - case SCTP_COOKIE_ECHO: - case SCTP_COOKIE_ACK: - case SCTP_ECN_ECHO: - case SCTP_ECN_CWR: - case SCTP_SHUTDOWN_COMPLETE: - case SCTP_AUTHENTICATION: - case SCTP_ASCONF_ACK: - case SCTP_PACKET_DROPPED: - case SCTP_STREAM_RESET: - case SCTP_FORWARD_CUM_TSN: - case SCTP_ASCONF: - { - /* - * Now, what do we do with KNOWN chunks that - * are NOT in the right place? - * - * For now, I do nothing but ignore them. We - * may later want to add sysctl stuff to - * switch out and do either an ABORT() or - * possibly process them. - */ - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x", - ch->chunk_type); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return (2); - } - default: - /* - * Unknown chunk type: use bit rules after - * checking length - */ - if (chk_length < sizeof(struct sctp_chunkhdr)) { - /* - * Need to send an abort since we had a - * invalid chunk. - */ - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "Chunk of length %u", chk_length); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return (2); - } - if (ch->chunk_type & 0x40) { - /* Add a error report to the queue */ - struct mbuf *op_err; - struct sctp_gen_error_cause *cause; - - op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause), - 0, M_NOWAIT, 1, MT_DATA); - if (op_err != NULL) { - cause = mtod(op_err, struct sctp_gen_error_cause *); - cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK); - cause->length = htons((uint16_t)(chk_length + sizeof(struct sctp_gen_error_cause))); - SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); - SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); - if (SCTP_BUF_NEXT(op_err) != NULL) { - sctp_queue_op_err(stcb, op_err); - } else { - sctp_m_freem(op_err); - } - } - } - if ((ch->chunk_type & 0x80) == 0) { - /* discard the rest of this packet */ - stop_proc = 1; - } /* else skip this bad chunk and - * continue... */ - break; - } /* switch of chunk type */ - } - *offset += SCTP_SIZE32(chk_length); - if ((*offset >= length) || stop_proc) { - /* no more data left in the mbuf chain */ - stop_proc = 1; - continue; - } - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_chunkhdr), - (uint8_t *)&chunk_buf); - if (ch == NULL) { - *offset = length; - stop_proc = 1; - continue; - } - } - if (break_flag) { - /* - * we need to report rwnd overrun drops. - */ - sctp_send_packet_dropped(stcb, net, *mm, length, iphlen, 0); - } - if (num_chunks) { - /* - * Did we get data, if so update the time for auto-close and - * give peer credit for being alive. - */ - SCTP_STAT_INCR(sctps_recvpktwithdata); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INDATA, - __LINE__); - } - stcb->asoc.overall_error_count = 0; - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd); - } - /* now service all of the reassm queue if needed */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) { - /* Assure that we ack right away */ - stcb->asoc.send_sack = 1; - } - /* Start a sack timer or QUEUE a SACK for sending */ - sctp_sack_check(stcb, was_a_gap); - return (0); -} - -static int -sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1, uint32_t last_tsn, - uint16_t frag_strt, uint16_t frag_end, int nr_sacking, - int *num_frs, - uint32_t *biggest_newly_acked_tsn, - uint32_t *this_sack_lowest_newack, - int *rto_ok) -{ - struct sctp_tmit_chunk *tp1; - unsigned int theTSN; - int j, wake_him = 0, circled = 0; - - /* Recover the tp1 we last saw */ - tp1 = *p_tp1; - if (tp1 == NULL) { - tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue); - } - for (j = frag_strt; j <= frag_end; j++) { - theTSN = j + last_tsn; - while (tp1) { - if (tp1->rec.data.doing_fast_retransmit) - (*num_frs) += 1; - - /*- - * CMT: CUCv2 algorithm. For each TSN being - * processed from the sent queue, track the - * next expected pseudo-cumack, or - * rtx_pseudo_cumack, if required. Separate - * cumack trackers for first transmissions, - * and retransmissions. - */ - if ((tp1->sent < SCTP_DATAGRAM_RESEND) && - (tp1->whoTo->find_pseudo_cumack == 1) && - (tp1->snd_count == 1)) { - tp1->whoTo->pseudo_cumack = tp1->rec.data.tsn; - tp1->whoTo->find_pseudo_cumack = 0; - } - if ((tp1->sent < SCTP_DATAGRAM_RESEND) && - (tp1->whoTo->find_rtx_pseudo_cumack == 1) && - (tp1->snd_count > 1)) { - tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.tsn; - tp1->whoTo->find_rtx_pseudo_cumack = 0; - } - if (tp1->rec.data.tsn == theTSN) { - if (tp1->sent != SCTP_DATAGRAM_UNSENT) { - /*- - * must be held until - * cum-ack passes - */ - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - /*- - * If it is less than RESEND, it is - * now no-longer in flight. - * Higher values may already be set - * via previous Gap Ack Blocks... - * i.e. ACKED or RESEND. - */ - if (SCTP_TSN_GT(tp1->rec.data.tsn, - *biggest_newly_acked_tsn)) { - *biggest_newly_acked_tsn = tp1->rec.data.tsn; - } - /*- - * CMT: SFR algo (and HTNA) - set - * saw_newack to 1 for dest being - * newly acked. update - * this_sack_highest_newack if - * appropriate. - */ - if (tp1->rec.data.chunk_was_revoked == 0) - tp1->whoTo->saw_newack = 1; - - if (SCTP_TSN_GT(tp1->rec.data.tsn, - tp1->whoTo->this_sack_highest_newack)) { - tp1->whoTo->this_sack_highest_newack = - tp1->rec.data.tsn; - } - /*- - * CMT DAC algo: also update - * this_sack_lowest_newack - */ - if (*this_sack_lowest_newack == 0) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(*this_sack_lowest_newack, - last_tsn, - tp1->rec.data.tsn, - 0, - 0, - SCTP_LOG_TSN_ACKED); - } - *this_sack_lowest_newack = tp1->rec.data.tsn; - } - /*- - * CMT: CUCv2 algorithm. If (rtx-)pseudo-cumack for corresp - * dest is being acked, then we have a new (rtx-)pseudo-cumack. Set - * new_(rtx_)pseudo_cumack to TRUE so that the cwnd for this dest can be - * updated. Also trigger search for the next expected (rtx-)pseudo-cumack. - * Separate pseudo_cumack trackers for first transmissions and - * retransmissions. - */ - if (tp1->rec.data.tsn == tp1->whoTo->pseudo_cumack) { - if (tp1->rec.data.chunk_was_revoked == 0) { - tp1->whoTo->new_pseudo_cumack = 1; - } - tp1->whoTo->find_pseudo_cumack = 1; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK); - } - if (tp1->rec.data.tsn == tp1->whoTo->rtx_pseudo_cumack) { - if (tp1->rec.data.chunk_was_revoked == 0) { - tp1->whoTo->new_pseudo_cumack = 1; - } - tp1->whoTo->find_rtx_pseudo_cumack = 1; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(*biggest_newly_acked_tsn, - last_tsn, - tp1->rec.data.tsn, - frag_strt, - frag_end, - SCTP_LOG_TSN_ACKED); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } - sctp_flight_size_decrease(tp1); - if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { - (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged)(tp1->whoTo, - tp1); - } - sctp_total_flight_decrease(stcb, tp1); - - tp1->whoTo->net_ack += tp1->send_size; - if (tp1->snd_count < 2) { - /*- - * True non-retransmitted chunk - */ - tp1->whoTo->net_ack2 += tp1->send_size; - - /*- - * update RTO too ? - */ - if (tp1->do_rtt) { - if (*rto_ok && - sctp_calculate_rto(stcb, - &stcb->asoc, - tp1->whoTo, - &tp1->sent_rcv_time, - SCTP_RTT_FROM_DATA)) { - *rto_ok = 0; - } - if (tp1->whoTo->rto_needed == 0) { - tp1->whoTo->rto_needed = 1; - } - tp1->do_rtt = 0; - } - } - } - if (tp1->sent <= SCTP_DATAGRAM_RESEND) { - if (SCTP_TSN_GT(tp1->rec.data.tsn, - stcb->asoc.this_sack_highest_gap)) { - stcb->asoc.this_sack_highest_gap = - tp1->rec.data.tsn; - } - if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt); -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xB2, - (stcb->asoc.sent_queue_retran_cnt & 0x000000ff)); -#endif - } - } - /*- - * All chunks NOT UNSENT fall through here and are marked - * (leave PR-SCTP ones that are to skip alone though) - */ - if ((tp1->sent != SCTP_FORWARD_TSN_SKIP) && - (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) { - tp1->sent = SCTP_DATAGRAM_MARKED; - } - if (tp1->rec.data.chunk_was_revoked) { - /* deflate the cwnd */ - tp1->whoTo->cwnd -= tp1->book_size; - tp1->rec.data.chunk_was_revoked = 0; - } - /* NR Sack code here */ - if (nr_sacking && - (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) { - if (stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues > 0) { - stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", tp1->rec.data.sid); -#endif - } - if ((stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues == 0) && - (stcb->asoc.strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && - TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.sid].outqueue)) { - stcb->asoc.trigger_reset = 1; - } - tp1->sent = SCTP_DATAGRAM_NR_ACKED; - if (tp1->data) { - /* sa_ignore NO_NULL_CHK */ - sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); - sctp_m_freem(tp1->data); - tp1->data = NULL; - } - wake_him++; - } - } - break; - } /* if (tp1->tsn == theTSN) */ - if (SCTP_TSN_GT(tp1->rec.data.tsn, theTSN)) { - break; - } - tp1 = TAILQ_NEXT(tp1, sctp_next); - if ((tp1 == NULL) && (circled == 0)) { - circled++; - tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue); - } - } /* end while (tp1) */ - if (tp1 == NULL) { - circled = 0; - tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue); - } - /* In case the fragments were not in order we must reset */ - } /* end for (j = fragStart */ - *p_tp1 = tp1; - return (wake_him); /* Return value only used for nr-sack */ -} - -static int -sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc, - uint32_t last_tsn, uint32_t *biggest_tsn_acked, - uint32_t *biggest_newly_acked_tsn, uint32_t *this_sack_lowest_newack, - int num_seg, int num_nr_seg, int *rto_ok) -{ - struct sctp_gap_ack_block *frag, block; - struct sctp_tmit_chunk *tp1; - int i; - int num_frs = 0; - int chunk_freed; - int non_revocable; - uint16_t frag_strt, frag_end, prev_frag_end; - - tp1 = TAILQ_FIRST(&asoc->sent_queue); - prev_frag_end = 0; - chunk_freed = 0; - - for (i = 0; i < (num_seg + num_nr_seg); i++) { - if (i == num_seg) { - prev_frag_end = 0; - tp1 = TAILQ_FIRST(&asoc->sent_queue); - } - frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_gap_ack_block), (uint8_t *) &block); - *offset += sizeof(block); - if (frag == NULL) { - return (chunk_freed); - } - frag_strt = ntohs(frag->start); - frag_end = ntohs(frag->end); - - if (frag_strt > frag_end) { - /* This gap report is malformed, skip it. */ - continue; - } - if (frag_strt <= prev_frag_end) { - /* This gap report is not in order, so restart. */ - tp1 = TAILQ_FIRST(&asoc->sent_queue); - } - if (SCTP_TSN_GT((last_tsn + frag_end), *biggest_tsn_acked)) { - *biggest_tsn_acked = last_tsn + frag_end; - } - if (i < num_seg) { - non_revocable = 0; - } else { - non_revocable = 1; - } - if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end, - non_revocable, &num_frs, biggest_newly_acked_tsn, - this_sack_lowest_newack, rto_ok)) { - chunk_freed = 1; - } - prev_frag_end = frag_end; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - if (num_frs) - sctp_log_fr(*biggest_tsn_acked, - *biggest_newly_acked_tsn, - last_tsn, SCTP_FR_LOG_BIGGEST_TSNS); - } - return (chunk_freed); -} - -static void -sctp_check_for_revoked(struct sctp_tcb *stcb, - struct sctp_association *asoc, uint32_t cumack, - uint32_t biggest_tsn_acked) -{ - struct sctp_tmit_chunk *tp1; - - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (SCTP_TSN_GT(tp1->rec.data.tsn, cumack)) { - /* - * ok this guy is either ACK or MARKED. If it is - * ACKED it has been previously acked but not this - * time i.e. revoked. If it is MARKED it was ACK'ed - * again. - */ - if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked)) { - break; - } - if (tp1->sent == SCTP_DATAGRAM_ACKED) { - /* it has been revoked */ - tp1->sent = SCTP_DATAGRAM_SENT; - tp1->rec.data.chunk_was_revoked = 1; - /* We must add this stuff back in to - * assure timers and such get started. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } - sctp_flight_size_increase(tp1); - sctp_total_flight_increase(stcb, tp1); - /* We inflate the cwnd to compensate for our - * artificial inflation of the flight_size. - */ - tp1->whoTo->cwnd += tp1->book_size; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(asoc->last_acked_seq, - cumack, - tp1->rec.data.tsn, - 0, - 0, - SCTP_LOG_TSN_REVOKED); - } - } else if (tp1->sent == SCTP_DATAGRAM_MARKED) { - /* it has been re-acked in this SACK */ - tp1->sent = SCTP_DATAGRAM_ACKED; - } - } - if (tp1->sent == SCTP_DATAGRAM_UNSENT) - break; - } -} - -static void -sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, - uint32_t biggest_tsn_acked, uint32_t biggest_tsn_newly_acked, uint32_t this_sack_lowest_newack, int accum_moved) -{ - struct sctp_tmit_chunk *tp1; - int strike_flag = 0; - struct timeval now; - uint32_t sending_seq; - struct sctp_nets *net; - int num_dests_sacked = 0; - - /* - * select the sending_seq, this is either the next thing ready to be - * sent but not transmitted, OR, the next seq we assign. - */ - tp1 = TAILQ_FIRST(&stcb->asoc.send_queue); - if (tp1 == NULL) { - sending_seq = asoc->sending_seq; - } else { - sending_seq = tp1->rec.data.tsn; - } - - /* CMT DAC algo: finding out if SACK is a mixed SACK */ - if ((asoc->sctp_cmt_on_off > 0) && - SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (net->saw_newack) - num_dests_sacked++; - } - } - if (stcb->asoc.prsctp_supported) { - (void)SCTP_GETTIME_TIMEVAL(&now); - } - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - strike_flag = 0; - if (tp1->no_fr_allowed) { - /* this one had a timeout or something */ - continue; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - if (tp1->sent < SCTP_DATAGRAM_RESEND) - sctp_log_fr(biggest_tsn_newly_acked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_CHECK_STRIKE); - } - if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked) || - tp1->sent == SCTP_DATAGRAM_UNSENT) { - /* done */ - break; - } - if (stcb->asoc.prsctp_supported) { - if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) { - /* Is it expired? */ -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (timercmp(&now, &tp1->rec.data.timetodrop, >)) { -#else - if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { -#endif - /* Yes so drop it */ - if (tp1->data != NULL) { - (void)sctp_release_pr_sctp_chunk(stcb, tp1, 1, - SCTP_SO_NOT_LOCKED); - } - continue; - } - } - } - if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->this_sack_highest_gap) && - !(accum_moved && asoc->fast_retran_loss_recovery)) { - /* we are beyond the tsn in the sack */ - break; - } - if (tp1->sent >= SCTP_DATAGRAM_RESEND) { - /* either a RESEND, ACKED, or MARKED */ - /* skip */ - if (tp1->sent == SCTP_FORWARD_TSN_SKIP) { - /* Continue strikin FWD-TSN chunks */ - tp1->rec.data.fwd_tsn_cnt++; - } - continue; - } - /* - * CMT : SFR algo (covers part of DAC and HTNA as well) - */ - if (tp1->whoTo && tp1->whoTo->saw_newack == 0) { - /* - * No new acks were received for data sent to this - * dest. Therefore, according to the SFR algo for - * CMT, no data sent to this dest can be marked for - * FR using this SACK. - */ - continue; - } else if (tp1->whoTo && - SCTP_TSN_GT(tp1->rec.data.tsn, - tp1->whoTo->this_sack_highest_newack) && - !(accum_moved && asoc->fast_retran_loss_recovery)) { - /* - * CMT: New acks were received for data sent to - * this dest. But no new acks were seen for data - * sent after tp1. Therefore, according to the SFR - * algo for CMT, tp1 cannot be marked for FR using - * this SACK. This step covers part of the DAC algo - * and the HTNA algo as well. - */ - continue; - } - /* - * Here we check to see if we were have already done a FR - * and if so we see if the biggest TSN we saw in the sack is - * smaller than the recovery point. If so we don't strike - * the tsn... otherwise we CAN strike the TSN. - */ - /* - * @@@ JRI: Check for CMT - * if (accum_moved && asoc->fast_retran_loss_recovery && (sctp_cmt_on_off == 0)) { - */ - if (accum_moved && asoc->fast_retran_loss_recovery) { - /* - * Strike the TSN if in fast-recovery and cum-ack - * moved. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(biggest_tsn_newly_acked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_STRIKE_CHUNK); - } - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - tp1->sent++; - } - if ((asoc->sctp_cmt_on_off > 0) && - SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { - /* - * CMT DAC algorithm: If SACK flag is set to - * 0, then lowest_newack test will not pass - * because it would have been set to the - * cumack earlier. If not already to be - * rtx'd, If not a mixed sack and if tp1 is - * not between two sacked TSNs, then mark by - * one more. - * NOTE that we are marking by one additional time since the SACK DAC flag indicates that - * two packets have been received after this missing TSN. - */ - if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && - SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(16 + num_dests_sacked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_STRIKE_CHUNK); - } - tp1->sent++; - } - } - } else if ((tp1->rec.data.doing_fast_retransmit) && - (asoc->sctp_cmt_on_off == 0)) { - /* - * For those that have done a FR we must take - * special consideration if we strike. I.e the - * biggest_newly_acked must be higher than the - * sending_seq at the time we did the FR. - */ - if ( -#ifdef SCTP_FR_TO_ALTERNATE - /* - * If FR's go to new networks, then we must only do - * this for singly homed asoc's. However if the FR's - * go to the same network (Armando's work) then its - * ok to FR multiple times. - */ - (asoc->numnets < 2) -#else - (1) -#endif - ) { - if (SCTP_TSN_GE(biggest_tsn_newly_acked, - tp1->rec.data.fast_retran_tsn)) { - /* - * Strike the TSN, since this ack is - * beyond where things were when we - * did a FR. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(biggest_tsn_newly_acked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_STRIKE_CHUNK); - } - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - tp1->sent++; - } - strike_flag = 1; - if ((asoc->sctp_cmt_on_off > 0) && - SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { - /* - * CMT DAC algorithm: If - * SACK flag is set to 0, - * then lowest_newack test - * will not pass because it - * would have been set to - * the cumack earlier. If - * not already to be rtx'd, - * If not a mixed sack and - * if tp1 is not between two - * sacked TSNs, then mark by - * one more. - * NOTE that we are marking by one additional time since the SACK DAC flag indicates that - * two packets have been received after this missing TSN. - */ - if ((tp1->sent < SCTP_DATAGRAM_RESEND) && - (num_dests_sacked == 1) && - SCTP_TSN_GT(this_sack_lowest_newack, - tp1->rec.data.tsn)) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(32 + num_dests_sacked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_STRIKE_CHUNK); - } - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - tp1->sent++; - } - } - } - } - } - /* - * JRI: TODO: remove code for HTNA algo. CMT's - * SFR algo covers HTNA. - */ - } else if (SCTP_TSN_GT(tp1->rec.data.tsn, - biggest_tsn_newly_acked)) { - /* - * We don't strike these: This is the HTNA - * algorithm i.e. we don't strike If our TSN is - * larger than the Highest TSN Newly Acked. - */ - ; - } else { - /* Strike the TSN */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(biggest_tsn_newly_acked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_STRIKE_CHUNK); - } - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - tp1->sent++; - } - if ((asoc->sctp_cmt_on_off > 0) && - SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { - /* - * CMT DAC algorithm: If SACK flag is set to - * 0, then lowest_newack test will not pass - * because it would have been set to the - * cumack earlier. If not already to be - * rtx'd, If not a mixed sack and if tp1 is - * not between two sacked TSNs, then mark by - * one more. - * NOTE that we are marking by one additional time since the SACK DAC flag indicates that - * two packets have been received after this missing TSN. - */ - if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && - SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(48 + num_dests_sacked, - tp1->rec.data.tsn, - tp1->sent, - SCTP_FR_LOG_STRIKE_CHUNK); - } - tp1->sent++; - } - } - } - if (tp1->sent == SCTP_DATAGRAM_RESEND) { - struct sctp_nets *alt; - - /* fix counts and things */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND, - (tp1->whoTo ? (tp1->whoTo->flight_size) : 0), - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } - if (tp1->whoTo) { - tp1->whoTo->net_ack++; - sctp_flight_size_decrease(tp1); - if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { - (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged)(tp1->whoTo, - tp1); - } - } - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { - sctp_log_rwnd(SCTP_INCREASE_PEER_RWND, - asoc->peers_rwnd, tp1->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); - } - /* add back to the rwnd */ - asoc->peers_rwnd += (tp1->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); - - /* remove from the total flight */ - sctp_total_flight_decrease(stcb, tp1); - - if ((stcb->asoc.prsctp_supported) && - (PR_SCTP_RTX_ENABLED(tp1->flags))) { - /* Has it been retransmitted tv_sec times? - we store the retran count there. */ - if (tp1->snd_count > tp1->rec.data.timetodrop.tv_sec) { - /* Yes, so drop it */ - if (tp1->data != NULL) { - (void)sctp_release_pr_sctp_chunk(stcb, tp1, 1, - SCTP_SO_NOT_LOCKED); - } - /* Make sure to flag we had a FR */ - if (tp1->whoTo != NULL) { - tp1->whoTo->net_ack++; - } - continue; - } - } - /* SCTP_PRINTF("OK, we are now ready to FR this guy\n"); */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(tp1->rec.data.tsn, tp1->snd_count, - 0, SCTP_FR_MARKED); - } - if (strike_flag) { - /* This is a subsequent FR */ - SCTP_STAT_INCR(sctps_sendmultfastretrans); - } - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - if (asoc->sctp_cmt_on_off > 0) { - /* - * CMT: Using RTX_SSTHRESH policy for CMT. - * If CMT is being used, then pick dest with - * largest ssthresh for any retransmission. - */ - tp1->no_fr_allowed = 1; - alt = tp1->whoTo; - /*sa_ignore NO_NULL_CHK*/ - if (asoc->sctp_cmt_pf > 0) { - /* JRS 5/18/07 - If CMT PF is on, use the PF version of find_alt_net() */ - alt = sctp_find_alternate_net(stcb, alt, 2); - } else { - /* JRS 5/18/07 - If only CMT is on, use the CMT version of find_alt_net() */ - /*sa_ignore NO_NULL_CHK*/ - alt = sctp_find_alternate_net(stcb, alt, 1); - } - if (alt == NULL) { - alt = tp1->whoTo; - } - /* - * CUCv2: If a different dest is picked for - * the retransmission, then new - * (rtx-)pseudo_cumack needs to be tracked - * for orig dest. Let CUCv2 track new (rtx-) - * pseudo-cumack always. - */ - if (tp1->whoTo) { - tp1->whoTo->find_pseudo_cumack = 1; - tp1->whoTo->find_rtx_pseudo_cumack = 1; - } - } else {/* CMT is OFF */ -#ifdef SCTP_FR_TO_ALTERNATE - /* Can we find an alternate? */ - alt = sctp_find_alternate_net(stcb, tp1->whoTo, 0); -#else - /* - * default behavior is to NOT retransmit - * FR's to an alternate. Armando Caro's - * paper details why. - */ - alt = tp1->whoTo; -#endif - } - - tp1->rec.data.doing_fast_retransmit = 1; - /* mark the sending seq for possible subsequent FR's */ - /* - * SCTP_PRINTF("Marking TSN for FR new value %x\n", - * (uint32_t)tpi->rec.data.tsn); - */ - if (TAILQ_EMPTY(&asoc->send_queue)) { - /* - * If the queue of send is empty then its - * the next sequence number that will be - * assigned so we subtract one from this to - * get the one we last sent. - */ - tp1->rec.data.fast_retran_tsn = sending_seq; - } else { - /* - * If there are chunks on the send queue - * (unsent data that has made it from the - * stream queues but not out the door, we - * take the first one (which will have the - * lowest TSN) and subtract one to get the - * one we last sent. - */ - struct sctp_tmit_chunk *ttt; - - ttt = TAILQ_FIRST(&asoc->send_queue); - tp1->rec.data.fast_retran_tsn = - ttt->rec.data.tsn; - } - - if (tp1->do_rtt) { - /* - * this guy had a RTO calculation pending on - * it, cancel it - */ - if ((tp1->whoTo != NULL) && - (tp1->whoTo->rto_needed == 0)) { - tp1->whoTo->rto_needed = 1; - } - tp1->do_rtt = 0; - } - if (alt != tp1->whoTo) { - /* yes, there is an alternate. */ - sctp_free_remote_addr(tp1->whoTo); - /*sa_ignore FREED_MEMORY*/ - tp1->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } - } - } -} - -struct sctp_tmit_chunk * -sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb, - struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *tp1, *tp2, *a_adv = NULL; - struct timeval now; - int now_filled = 0; - - if (asoc->prsctp_supported == 0) { - return (NULL); - } - TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) { - if (tp1->sent != SCTP_FORWARD_TSN_SKIP && - tp1->sent != SCTP_DATAGRAM_RESEND && - tp1->sent != SCTP_DATAGRAM_NR_ACKED) { - /* no chance to advance, out of here */ - break; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) || - (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - asoc->advanced_peer_ack_point, - tp1->rec.data.tsn, 0, 0); - } - } - if (!PR_SCTP_ENABLED(tp1->flags)) { - /* - * We can't fwd-tsn past any that are reliable aka - * retransmitted until the asoc fails. - */ - break; - } - if (!now_filled) { - (void)SCTP_GETTIME_TIMEVAL(&now); - now_filled = 1; - } - /* - * now we got a chunk which is marked for another - * retransmission to a PR-stream but has run out its chances - * already maybe OR has been marked to skip now. Can we skip - * it if its a resend? - */ - if (tp1->sent == SCTP_DATAGRAM_RESEND && - (PR_SCTP_TTL_ENABLED(tp1->flags))) { - /* - * Now is this one marked for resend and its time is - * now up? - */ -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (timercmp(&now, &tp1->rec.data.timetodrop, >)) { -#else - if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { -#endif - /* Yes so drop it */ - if (tp1->data) { - (void)sctp_release_pr_sctp_chunk(stcb, tp1, - 1, SCTP_SO_NOT_LOCKED); - } - } else { - /* - * No, we are done when hit one for resend - * whos time as not expired. - */ - break; - } - } - /* - * Ok now if this chunk is marked to drop it we can clean up - * the chunk, advance our peer ack point and we can check - * the next chunk. - */ - if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) || - (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) { - /* advance PeerAckPoint goes forward */ - if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->advanced_peer_ack_point)) { - asoc->advanced_peer_ack_point = tp1->rec.data.tsn; - a_adv = tp1; - } else if (tp1->rec.data.tsn == asoc->advanced_peer_ack_point) { - /* No update but we do save the chk */ - a_adv = tp1; - } - } else { - /* - * If it is still in RESEND we can advance no - * further - */ - break; - } - } - return (a_adv); -} - -static int -sctp_fs_audit(struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *chk; - int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0; - int ret; -#ifndef INVARIANTS - int entry_flight, entry_cnt; -#endif - - ret = 0; -#ifndef INVARIANTS - entry_flight = asoc->total_flight; - entry_cnt = asoc->total_flight_count; -#endif - if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt) - return (0); - - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - if (chk->sent < SCTP_DATAGRAM_RESEND) { - SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n", - chk->rec.data.tsn, - chk->send_size, - chk->snd_count); - inflight++; - } else if (chk->sent == SCTP_DATAGRAM_RESEND) { - resend++; - } else if (chk->sent < SCTP_DATAGRAM_ACKED) { - inbetween++; - } else if (chk->sent > SCTP_DATAGRAM_ACKED) { - above++; - } else { - acked++; - } - } - - if ((inflight > 0) || (inbetween > 0)) { -#ifdef INVARIANTS - panic("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d", - inflight, inbetween, resend, above, acked); -#else - SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n", - entry_flight, entry_cnt); - SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n", - inflight, inbetween, resend, above, acked); - ret = 1; -#endif - } - return (ret); -} - -static void -sctp_window_probe_recovery(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_tmit_chunk *tp1) -{ - tp1->window_probe = 0; - if ((tp1->sent >= SCTP_DATAGRAM_ACKED) || (tp1->data == NULL)) { - /* TSN's skipped we do NOT move back. */ - sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD, - tp1->whoTo ? tp1->whoTo->flight_size : 0, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - return; - } - /* First setup this by shrinking flight */ - if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { - (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged)(tp1->whoTo, - tp1); - } - sctp_flight_size_decrease(tp1); - sctp_total_flight_decrease(stcb, tp1); - /* Now mark for resend */ - tp1->sent = SCTP_DATAGRAM_RESEND; - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } -} - -void -sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, - uint32_t rwnd, int *abort_now, int ecne_seen) -{ - struct sctp_nets *net; - struct sctp_association *asoc; - struct sctp_tmit_chunk *tp1, *tp2; - uint32_t old_rwnd; - int win_probe_recovery = 0; - int win_probe_recovered = 0; - int j, done_once = 0; - int rto_ok = 1; - uint32_t send_s; - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) { - sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack, - rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd); - } - SCTP_TCB_LOCK_ASSERT(stcb); -#ifdef SCTP_ASOCLOG_OF_TSNS - stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cumack; - stcb->asoc.cumack_log_at++; - if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) { - stcb->asoc.cumack_log_at = 0; - } -#endif - asoc = &stcb->asoc; - old_rwnd = asoc->peers_rwnd; - if (SCTP_TSN_GT(asoc->last_acked_seq, cumack)) { - /* old ack */ - return; - } else if (asoc->last_acked_seq == cumack) { - /* Window update sack */ - asoc->peers_rwnd = sctp_sbspace_sub(rwnd, - (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - if (asoc->peers_rwnd > old_rwnd) { - goto again; - } - return; - } - - /* First setup for CC stuff */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (SCTP_TSN_GT(cumack, net->cwr_window_tsn)) { - /* Drag along the window_tsn for cwr's */ - net->cwr_window_tsn = cumack; - } - net->prev_cwnd = net->cwnd; - net->net_ack = 0; - net->net_ack2 = 0; - - /* - * CMT: Reset CUC and Fast recovery algo variables before - * SACK processing - */ - net->new_pseudo_cumack = 0; - net->will_exit_fast_recovery = 0; - if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) { - (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack)(stcb, net); - } - } - if (!TAILQ_EMPTY(&asoc->sent_queue)) { - tp1 = TAILQ_LAST(&asoc->sent_queue, - sctpchunk_listhead); - send_s = tp1->rec.data.tsn + 1; - } else { - send_s = asoc->sending_seq; - } - if (SCTP_TSN_GE(cumack, send_s)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - *abort_now = 1; - /* XXX */ - SCTP_SNPRINTF(msg, sizeof(msg), - "Cum ack %8.8x greater or equal than TSN %8.8x", - cumack, send_s); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return; - } - asoc->this_sack_highest_gap = cumack; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INDATA, - __LINE__); - } - stcb->asoc.overall_error_count = 0; - if (SCTP_TSN_GT(cumack, asoc->last_acked_seq)) { - /* process the new consecutive TSN first */ - TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) { - if (SCTP_TSN_GE(cumack, tp1->rec.data.tsn)) { - if (tp1->sent == SCTP_DATAGRAM_UNSENT) { - SCTP_PRINTF("Warning, an unsent is now acked?\n"); - } - if (tp1->sent < SCTP_DATAGRAM_ACKED) { - /* - * If it is less than ACKED, it is - * now no-longer in flight. Higher - * values may occur during marking - */ - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } - sctp_flight_size_decrease(tp1); - if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { - (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged)(tp1->whoTo, - tp1); - } - /* sa_ignore NO_NULL_CHK */ - sctp_total_flight_decrease(stcb, tp1); - } - tp1->whoTo->net_ack += tp1->send_size; - if (tp1->snd_count < 2) { - /* - * True non-retransmitted - * chunk - */ - tp1->whoTo->net_ack2 += - tp1->send_size; - - /* update RTO too? */ - if (tp1->do_rtt) { - if (rto_ok && - sctp_calculate_rto(stcb, - &stcb->asoc, - tp1->whoTo, - &tp1->sent_rcv_time, - SCTP_RTT_FROM_DATA)) { - rto_ok = 0; - } - if (tp1->whoTo->rto_needed == 0) { - tp1->whoTo->rto_needed = 1; - } - tp1->do_rtt = 0; - } - } - /* - * CMT: CUCv2 algorithm. From the - * cumack'd TSNs, for each TSN being - * acked for the first time, set the - * following variables for the - * corresp destination. - * new_pseudo_cumack will trigger a - * cwnd update. - * find_(rtx_)pseudo_cumack will - * trigger search for the next - * expected (rtx-)pseudo-cumack. - */ - tp1->whoTo->new_pseudo_cumack = 1; - tp1->whoTo->find_pseudo_cumack = 1; - tp1->whoTo->find_rtx_pseudo_cumack = 1; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - /* sa_ignore NO_NULL_CHK */ - sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK); - } - } - if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_decr(asoc->sent_queue_retran_cnt); - } - if (tp1->rec.data.chunk_was_revoked) { - /* deflate the cwnd */ - tp1->whoTo->cwnd -= tp1->book_size; - tp1->rec.data.chunk_was_revoked = 0; - } - if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) { - if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[tp1->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", tp1->rec.data.sid); -#endif - } - } - if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) && - (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && - TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) { - asoc->trigger_reset = 1; - } - TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); - if (tp1->data) { - /* sa_ignore NO_NULL_CHK */ - sctp_free_bufspace(stcb, asoc, tp1, 1); - sctp_m_freem(tp1->data); - tp1->data = NULL; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(asoc->last_acked_seq, - cumack, - tp1->rec.data.tsn, - 0, - 0, - SCTP_LOG_FREE_SENT); - } - asoc->sent_queue_cnt--; - sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED); - } else { - break; - } - } - } -#if defined(__Userspace__) - if (stcb->sctp_ep->recv_callback) { - if (stcb->sctp_socket) { - uint32_t inqueue_bytes, sb_free_now; - struct sctp_inpcb *inp; - - inp = stcb->sctp_ep; - inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk)); - sb_free_now = SCTP_SB_LIMIT_SND(stcb->sctp_socket) - (inqueue_bytes + stcb->asoc.sb_send_resv); - - /* check if the amount free in the send socket buffer crossed the threshold */ - if (inp->send_callback && - (((inp->send_sb_threshold > 0) && - (sb_free_now >= inp->send_sb_threshold) && - (stcb->asoc.chunks_on_out_queue <= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) || - (inp->send_sb_threshold == 0))) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - inp->send_callback(stcb->sctp_socket, sb_free_now, inp->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - } - } else if (stcb->sctp_socket) { -#else - /* sa_ignore NO_NULL_CHK */ - if (stcb->sctp_socket) { -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - -#endif - SOCKBUF_LOCK(&stcb->sctp_socket->so_snd); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { - /* sa_ignore NO_NULL_CHK */ - sctp_wakeup_log(stcb, 1, SCTP_WAKESND_FROM_SACK); - } -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { - sctp_wakeup_log(stcb, 1, SCTP_NOWAKE_FROM_SACK); - } - } - - /* JRS - Use the congestion control given in the CC module */ - if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (net->net_ack2 > 0) { - /* - * Karn's rule applies to clearing error count, this - * is optional. - */ - net->error_count = 0; - if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { - /* addr came good */ - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, - 0, (void *)net, SCTP_SO_NOT_LOCKED); - } - if (net == stcb->asoc.primary_destination) { - if (stcb->asoc.alternate) { - /* release the alternate, primary is good */ - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - } - if (net->dest_state & SCTP_ADDR_PF) { - net->dest_state &= ~SCTP_ADDR_PF; - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); - /* Done with this net */ - net->net_ack = 0; - } - /* restore any doubled timers */ - net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - if (net->RTO < stcb->asoc.minrto) { - net->RTO = stcb->asoc.minrto; - } - if (net->RTO > stcb->asoc.maxrto) { - net->RTO = stcb->asoc.maxrto; - } - } - } - asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0); - } - asoc->last_acked_seq = cumack; - - if (TAILQ_EMPTY(&asoc->sent_queue)) { - /* nothing left in-flight */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - net->flight_size = 0; - net->partial_bytes_acked = 0; - } - asoc->total_flight = 0; - asoc->total_flight_count = 0; - } - - /* RWND update */ - asoc->peers_rwnd = sctp_sbspace_sub(rwnd, - (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - if (asoc->peers_rwnd > old_rwnd) { - win_probe_recovery = 1; - } - /* Now assure a timer where data is queued at */ -again: - j = 0; - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (win_probe_recovery && (net->window_probe)) { - win_probe_recovered = 1; - /* - * Find first chunk that was used with window probe - * and clear the sent - */ - /* sa_ignore FREED_MEMORY */ - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (tp1->window_probe) { - /* move back to data send queue */ - sctp_window_probe_recovery(stcb, asoc, tp1); - break; - } - } - } - if (net->flight_size) { - j++; - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); - if (net->window_probe) { - net->window_probe = 0; - } - } else { - if (net->window_probe) { - /* In window probes we must assure a timer is still running there */ - net->window_probe = 0; - if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); - } - } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_27); - } - } - } - if ((j == 0) && - (!TAILQ_EMPTY(&asoc->sent_queue)) && - (asoc->sent_queue_retran_cnt == 0) && - (win_probe_recovered == 0) && - (done_once == 0)) { - /* huh, this should not happen unless all packets - * are PR-SCTP and marked to skip of course. - */ - if (sctp_fs_audit(asoc)) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - net->flight_size = 0; - } - asoc->total_flight = 0; - asoc->total_flight_count = 0; - asoc->sent_queue_retran_cnt = 0; - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - sctp_flight_size_increase(tp1); - sctp_total_flight_increase(stcb, tp1); - } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - } - } - } - done_once = 1; - goto again; - } - /**********************************/ - /* Now what about shutdown issues */ - /**********************************/ - if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) { - /* nothing left on sendqueue.. consider done */ - /* clean up */ - if ((asoc->stream_queue_cnt == 1) && - ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) && - ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc))) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) && - (asoc->stream_queue_cnt == 1) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - - *abort_now = 1; - /* XXX */ - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return; - } - if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && - (asoc->stream_queue_cnt == 0)) { - struct sctp_nets *netp; - - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (asoc->alternate) { - netp = asoc->alternate; - } else { - netp = asoc->primary_destination; - } - sctp_send_shutdown(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); - } else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) && - (asoc->stream_queue_cnt == 0)) { - struct sctp_nets *netp; - - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (asoc->alternate) { - netp = asoc->alternate; - } else { - netp = asoc->primary_destination; - } - sctp_send_shutdown_ack(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, - stcb->sctp_ep, stcb, netp); - } - } - /*********************************************/ - /* Here we perform PR-SCTP procedures */ - /* (section 4.2) */ - /*********************************************/ - /* C1. update advancedPeerAckPoint */ - if (SCTP_TSN_GT(cumack, asoc->advanced_peer_ack_point)) { - asoc->advanced_peer_ack_point = cumack; - } - /* PR-Sctp issues need to be addressed too */ - if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) { - struct sctp_tmit_chunk *lchk; - uint32_t old_adv_peer_ack_point; - - old_adv_peer_ack_point = asoc->advanced_peer_ack_point; - lchk = sctp_try_advance_peer_ack_point(stcb, asoc); - /* C3. See if we need to send a Fwd-TSN */ - if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cumack)) { - /* - * ISSUE with ECN, see FWD-TSN processing. - */ - if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) { - send_forward_tsn(stcb, asoc); - } else if (lchk) { - /* try to FR fwd-tsn's that get lost too */ - if (lchk->rec.data.fwd_tsn_cnt >= 3) { - send_forward_tsn(stcb, asoc); - } - } - } - for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) { - if (lchk->whoTo != NULL) { - break; - } - } - if (lchk != NULL) { - /* Assure a timer is up */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, lchk->whoTo); - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_SACK_RWND_UPDATE, - rwnd, - stcb->asoc.peers_rwnd, - stcb->asoc.total_flight, - stcb->asoc.total_output_queue_size); - } -} - -void -sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, - struct sctp_tcb *stcb, - uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup, - int *abort_now, uint8_t flags, - uint32_t cum_ack, uint32_t rwnd, int ecne_seen) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *tp1, *tp2; - uint32_t last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked, this_sack_lowest_newack; - uint16_t wake_him = 0; - uint32_t send_s = 0; - long j; - int accum_moved = 0; - int will_exit_fast_recovery = 0; - uint32_t a_rwnd, old_rwnd; - int win_probe_recovery = 0; - int win_probe_recovered = 0; - struct sctp_nets *net = NULL; - int done_once; - int rto_ok = 1; - uint8_t reneged_all = 0; - uint8_t cmt_dac_flag; - /* - * we take any chance we can to service our queues since we cannot - * get awoken when the socket is read from :< - */ - /* - * Now perform the actual SACK handling: 1) Verify that it is not an - * old sack, if so discard. 2) If there is nothing left in the send - * queue (cum-ack is equal to last acked) then you have a duplicate - * too, update any rwnd change and verify no timers are running. - * then return. 3) Process any new consecutive data i.e. cum-ack - * moved process these first and note that it moved. 4) Process any - * sack blocks. 5) Drop any acked from the queue. 6) Check for any - * revoked blocks and mark. 7) Update the cwnd. 8) Nothing left, - * sync up flightsizes and things, stop all timers and also check - * for shutdown_pending state. If so then go ahead and send off the - * shutdown. If in shutdown recv, send off the shutdown-ack and - * start that timer, Ret. 9) Strike any non-acked things and do FR - * procedure if needed being sure to set the FR flag. 10) Do pr-sctp - * procedures. 11) Apply any FR penalties. 12) Assure we will SACK - * if in shutdown_recv state. - */ - SCTP_TCB_LOCK_ASSERT(stcb); - /* CMT DAC algo */ - this_sack_lowest_newack = 0; - SCTP_STAT_INCR(sctps_slowpath_sack); - last_tsn = cum_ack; - cmt_dac_flag = flags & SCTP_SACK_CMT_DAC; -#ifdef SCTP_ASOCLOG_OF_TSNS - stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cum_ack; - stcb->asoc.cumack_log_at++; - if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) { - stcb->asoc.cumack_log_at = 0; - } -#endif - a_rwnd = rwnd; - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) { - sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack, - rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd); - } - - old_rwnd = stcb->asoc.peers_rwnd; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INDATA, - __LINE__); - } - stcb->asoc.overall_error_count = 0; - asoc = &stcb->asoc; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(asoc->last_acked_seq, - cum_ack, - 0, - num_seg, - num_dup, - SCTP_LOG_NEW_SACK); - } - if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) { - uint16_t i; - uint32_t *dupdata, dblock; - - for (i = 0; i < num_dup; i++) { - dupdata = (uint32_t *)sctp_m_getptr(m, offset_dup + i * sizeof(uint32_t), - sizeof(uint32_t), (uint8_t *)&dblock); - if (dupdata == NULL) { - break; - } - sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED); - } - } - /* reality check */ - if (!TAILQ_EMPTY(&asoc->sent_queue)) { - tp1 = TAILQ_LAST(&asoc->sent_queue, - sctpchunk_listhead); - send_s = tp1->rec.data.tsn + 1; - } else { - tp1 = NULL; - send_s = asoc->sending_seq; - } - if (SCTP_TSN_GE(cum_ack, send_s)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - /* - * no way, we have not even sent this TSN out yet. - * Peer is hopelessly messed up with us. - */ - SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n", - cum_ack, send_s); - if (tp1) { - SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n", - tp1->rec.data.tsn, (void *)tp1); - } - hopeless_peer: - *abort_now = 1; - /* XXX */ - SCTP_SNPRINTF(msg, sizeof(msg), - "Cum ack %8.8x greater or equal than TSN %8.8x", - cum_ack, send_s); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_29; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return; - } - /**********************/ - /* 1) check the range */ - /**********************/ - if (SCTP_TSN_GT(asoc->last_acked_seq, last_tsn)) { - /* acking something behind */ - return; - } - - /* update the Rwnd of the peer */ - if (TAILQ_EMPTY(&asoc->sent_queue) && - TAILQ_EMPTY(&asoc->send_queue) && - (asoc->stream_queue_cnt == 0)) { - /* nothing left on send/sent and strmq */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { - sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, - asoc->peers_rwnd, 0, 0, a_rwnd); - } - asoc->peers_rwnd = a_rwnd; - if (asoc->sent_queue_retran_cnt) { - asoc->sent_queue_retran_cnt = 0; - } - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - /* stop any timers */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); - net->partial_bytes_acked = 0; - net->flight_size = 0; - } - asoc->total_flight = 0; - asoc->total_flight_count = 0; - return; - } - /* - * We init netAckSz and netAckSz2 to 0. These are used to track 2 - * things. The total byte count acked is tracked in netAckSz AND - * netAck2 is used to track the total bytes acked that are un- - * ambiguous and were never retransmitted. We track these on a per - * destination address basis. - */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (SCTP_TSN_GT(cum_ack, net->cwr_window_tsn)) { - /* Drag along the window_tsn for cwr's */ - net->cwr_window_tsn = cum_ack; - } - net->prev_cwnd = net->cwnd; - net->net_ack = 0; - net->net_ack2 = 0; - - /* - * CMT: Reset CUC and Fast recovery algo variables before - * SACK processing - */ - net->new_pseudo_cumack = 0; - net->will_exit_fast_recovery = 0; - if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) { - (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack)(stcb, net); - } - - /* - * CMT: SFR algo (and HTNA) - this_sack_highest_newack has - * to be greater than the cumack. Also reset saw_newack to 0 - * for all dests. - */ - net->saw_newack = 0; - net->this_sack_highest_newack = last_tsn; - } - /* process the new consecutive TSN first */ - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (SCTP_TSN_GE(last_tsn, tp1->rec.data.tsn)) { - if (tp1->sent != SCTP_DATAGRAM_UNSENT) { - accum_moved = 1; - if (tp1->sent < SCTP_DATAGRAM_ACKED) { - /* - * If it is less than ACKED, it is - * now no-longer in flight. Higher - * values may occur during marking - */ - if ((tp1->whoTo->dest_state & - SCTP_ADDR_UNCONFIRMED) && - (tp1->snd_count < 2)) { - /* - * If there was no retran - * and the address is - * un-confirmed and we sent - * there and are now - * sacked.. its confirmed, - * mark it so. - */ - tp1->whoTo->dest_state &= - ~SCTP_ADDR_UNCONFIRMED; - } - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } - sctp_flight_size_decrease(tp1); - sctp_total_flight_decrease(stcb, tp1); - if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) { - (*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged)(tp1->whoTo, - tp1); - } - } - tp1->whoTo->net_ack += tp1->send_size; - - /* CMT SFR and DAC algos */ - this_sack_lowest_newack = tp1->rec.data.tsn; - tp1->whoTo->saw_newack = 1; - - if (tp1->snd_count < 2) { - /* - * True non-retransmitted - * chunk - */ - tp1->whoTo->net_ack2 += - tp1->send_size; - - /* update RTO too? */ - if (tp1->do_rtt) { - if (rto_ok && - sctp_calculate_rto(stcb, - &stcb->asoc, - tp1->whoTo, - &tp1->sent_rcv_time, - SCTP_RTT_FROM_DATA)) { - rto_ok = 0; - } - if (tp1->whoTo->rto_needed == 0) { - tp1->whoTo->rto_needed = 1; - } - tp1->do_rtt = 0; - } - } - /* - * CMT: CUCv2 algorithm. From the - * cumack'd TSNs, for each TSN being - * acked for the first time, set the - * following variables for the - * corresp destination. - * new_pseudo_cumack will trigger a - * cwnd update. - * find_(rtx_)pseudo_cumack will - * trigger search for the next - * expected (rtx-)pseudo-cumack. - */ - tp1->whoTo->new_pseudo_cumack = 1; - tp1->whoTo->find_pseudo_cumack = 1; - tp1->whoTo->find_rtx_pseudo_cumack = 1; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(asoc->last_acked_seq, - cum_ack, - tp1->rec.data.tsn, - 0, - 0, - SCTP_LOG_TSN_ACKED); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK); - } - } - if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_decr(asoc->sent_queue_retran_cnt); -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xB3, - (asoc->sent_queue_retran_cnt & 0x000000ff)); -#endif - } - if (tp1->rec.data.chunk_was_revoked) { - /* deflate the cwnd */ - tp1->whoTo->cwnd -= tp1->book_size; - tp1->rec.data.chunk_was_revoked = 0; - } - if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) { - tp1->sent = SCTP_DATAGRAM_ACKED; - } - } - } else { - break; - } - } - biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn; - /* always set this up to cum-ack */ - asoc->this_sack_highest_gap = last_tsn; - - if ((num_seg > 0) || (num_nr_seg > 0)) { - /* - * thisSackHighestGap will increase while handling NEW - * segments this_sack_highest_newack will increase while - * handling NEWLY ACKED chunks. this_sack_lowest_newack is - * used for CMT DAC algo. saw_newack will also change. - */ - if (sctp_handle_segments(m, &offset_seg, stcb, asoc, last_tsn, &biggest_tsn_acked, - &biggest_tsn_newly_acked, &this_sack_lowest_newack, - num_seg, num_nr_seg, &rto_ok)) { - wake_him++; - } - /* - * validate the biggest_tsn_acked in the gap acks if - * strict adherence is wanted. - */ - if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) { - /* - * peer is either confused or we are under - * attack. We must abort. - */ - SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n", - biggest_tsn_acked, send_s); - goto hopeless_peer; - } - } - /*******************************************/ - /* cancel ALL T3-send timer if accum moved */ - /*******************************************/ - if (asoc->sctp_cmt_on_off > 0) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (net->new_pseudo_cumack) - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_31); - } - } else { - if (accum_moved) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); - } - } - } - /********************************************/ - /* drop the acked chunks from the sentqueue */ - /********************************************/ - asoc->last_acked_seq = cum_ack; - - TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) { - if (SCTP_TSN_GT(tp1->rec.data.tsn, cum_ack)) { - break; - } - if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) { - if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[tp1->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", tp1->rec.data.sid); -#endif - } - } - if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) && - (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && - TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) { - asoc->trigger_reset = 1; - } - TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); - if (PR_SCTP_ENABLED(tp1->flags)) { - if (asoc->pr_sctp_cnt != 0) - asoc->pr_sctp_cnt--; - } - asoc->sent_queue_cnt--; - if (tp1->data) { - /* sa_ignore NO_NULL_CHK */ - sctp_free_bufspace(stcb, asoc, tp1, 1); - sctp_m_freem(tp1->data); - tp1->data = NULL; - if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(tp1->flags)) { - asoc->sent_queue_cnt_removeable--; - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) { - sctp_log_sack(asoc->last_acked_seq, - cum_ack, - tp1->rec.data.tsn, - 0, - 0, - SCTP_LOG_FREE_SENT); - } - sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED); - wake_him++; - } - if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) { -#ifdef INVARIANTS - panic("Warning flight size is positive and should be 0"); -#else - SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n", - asoc->total_flight); -#endif - asoc->total_flight = 0; - } - -#if defined(__Userspace__) - if (stcb->sctp_ep->recv_callback) { - if (stcb->sctp_socket) { - uint32_t inqueue_bytes, sb_free_now; - struct sctp_inpcb *inp; - - inp = stcb->sctp_ep; - inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk)); - sb_free_now = SCTP_SB_LIMIT_SND(stcb->sctp_socket) - (inqueue_bytes + stcb->asoc.sb_send_resv); - - /* check if the amount free in the send socket buffer crossed the threshold */ - if (inp->send_callback && - (((inp->send_sb_threshold > 0) && (sb_free_now >= inp->send_sb_threshold)) || - (inp->send_sb_threshold == 0))) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - inp->send_callback(stcb->sctp_socket, sb_free_now, inp->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - } - } else if ((wake_him) && (stcb->sctp_socket)) { -#else - /* sa_ignore NO_NULL_CHK */ - if ((wake_him) && (stcb->sctp_socket)) { -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - -#endif - SOCKBUF_LOCK(&stcb->sctp_socket->so_snd); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { - sctp_wakeup_log(stcb, wake_him, SCTP_WAKESND_FROM_SACK); - } -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) { - sctp_wakeup_log(stcb, wake_him, SCTP_NOWAKE_FROM_SACK); - } - } - - if (asoc->fast_retran_loss_recovery && accum_moved) { - if (SCTP_TSN_GE(asoc->last_acked_seq, asoc->fast_recovery_tsn)) { - /* Setup so we will exit RFC2582 fast recovery */ - will_exit_fast_recovery = 1; - } - } - /* - * Check for revoked fragments: - * - * if Previous sack - Had no frags then we can't have any revoked if - * Previous sack - Had frag's then - If we now have frags aka - * num_seg > 0 call sctp_check_for_revoked() to tell if peer revoked - * some of them. else - The peer revoked all ACKED fragments, since - * we had some before and now we have NONE. - */ - - if (num_seg) { - sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked); - asoc->saw_sack_with_frags = 1; - } else if (asoc->saw_sack_with_frags) { - int cnt_revoked = 0; - - /* Peer revoked all dg's marked or acked */ - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (tp1->sent == SCTP_DATAGRAM_ACKED) { - tp1->sent = SCTP_DATAGRAM_SENT; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)tp1->whoTo, - tp1->rec.data.tsn); - } - sctp_flight_size_increase(tp1); - sctp_total_flight_increase(stcb, tp1); - tp1->rec.data.chunk_was_revoked = 1; - /* - * To ensure that this increase in - * flightsize, which is artificial, - * does not throttle the sender, we - * also increase the cwnd - * artificially. - */ - tp1->whoTo->cwnd += tp1->book_size; - cnt_revoked++; - } - } - if (cnt_revoked) { - reneged_all = 1; - } - asoc->saw_sack_with_frags = 0; - } - if (num_nr_seg > 0) - asoc->saw_sack_with_nr_frags = 1; - else - asoc->saw_sack_with_nr_frags = 0; - - /* JRS - Use the congestion control given in the CC module */ - if (ecne_seen == 0) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (net->net_ack2 > 0) { - /* - * Karn's rule applies to clearing error count, this - * is optional. - */ - net->error_count = 0; - if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { - /* addr came good */ - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, - 0, (void *)net, SCTP_SO_NOT_LOCKED); - } - - if (net == stcb->asoc.primary_destination) { - if (stcb->asoc.alternate) { - /* release the alternate, primary is good */ - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - } - - if (net->dest_state & SCTP_ADDR_PF) { - net->dest_state &= ~SCTP_ADDR_PF; - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_33); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); - /* Done with this net */ - net->net_ack = 0; - } - /* restore any doubled timers */ - net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - if (net->RTO < stcb->asoc.minrto) { - net->RTO = stcb->asoc.minrto; - } - if (net->RTO > stcb->asoc.maxrto) { - net->RTO = stcb->asoc.maxrto; - } - } - } - asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery); - } - - if (TAILQ_EMPTY(&asoc->sent_queue)) { - /* nothing left in-flight */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - /* stop all timers */ - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_34); - net->flight_size = 0; - net->partial_bytes_acked = 0; - } - asoc->total_flight = 0; - asoc->total_flight_count = 0; - } - - /**********************************/ - /* Now what about shutdown issues */ - /**********************************/ - if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) { - /* nothing left on sendqueue.. consider done */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { - sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, - asoc->peers_rwnd, 0, 0, a_rwnd); - } - asoc->peers_rwnd = a_rwnd; - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - /* clean up */ - if ((asoc->stream_queue_cnt == 1) && - ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) && - ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc))) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) && - (asoc->stream_queue_cnt == 1) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - - *abort_now = 1; - /* XXX */ - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return; - } - if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && - (asoc->stream_queue_cnt == 0)) { - struct sctp_nets *netp; - - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (asoc->alternate) { - netp = asoc->alternate; - } else { - netp = asoc->primary_destination; - } - sctp_send_shutdown(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); - return; - } else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) && - (asoc->stream_queue_cnt == 0)) { - struct sctp_nets *netp; - - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (asoc->alternate) { - netp = asoc->alternate; - } else { - netp = asoc->primary_destination; - } - sctp_send_shutdown_ack(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, - stcb->sctp_ep, stcb, netp); - return; - } - } - /* - * Now here we are going to recycle net_ack for a different use... - * HEADS UP. - */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - net->net_ack = 0; - } - - /* - * CMT DAC algorithm: If SACK DAC flag was 0, then no extra marking - * to be done. Setting this_sack_lowest_newack to the cum_ack will - * automatically ensure that. - */ - if ((asoc->sctp_cmt_on_off > 0) && - SCTP_BASE_SYSCTL(sctp_cmt_use_dac) && - (cmt_dac_flag == 0)) { - this_sack_lowest_newack = cum_ack; - } - if ((num_seg > 0) || (num_nr_seg > 0)) { - sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked, - biggest_tsn_newly_acked, this_sack_lowest_newack, accum_moved); - } - /* JRS - Use the congestion control given in the CC module */ - asoc->cc_functions.sctp_cwnd_update_after_fr(stcb, asoc); - - /* Now are we exiting loss recovery ? */ - if (will_exit_fast_recovery) { - /* Ok, we must exit fast recovery */ - asoc->fast_retran_loss_recovery = 0; - } - if ((asoc->sat_t3_loss_recovery) && - SCTP_TSN_GE(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn)) { - /* end satellite t3 loss recovery */ - asoc->sat_t3_loss_recovery = 0; - } - /* - * CMT Fast recovery - */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (net->will_exit_fast_recovery) { - /* Ok, we must exit fast recovery */ - net->fast_retran_loss_recovery = 0; - } - } - - /* Adjust and set the new rwnd value */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { - sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK, - asoc->peers_rwnd, asoc->total_flight, (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd); - } - asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd, - (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)))); - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - if (asoc->peers_rwnd > old_rwnd) { - win_probe_recovery = 1; - } - - /* - * Now we must setup so we have a timer up for anyone with - * outstanding data. - */ - done_once = 0; -again: - j = 0; - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (win_probe_recovery && (net->window_probe)) { - win_probe_recovered = 1; - /*- - * Find first chunk that was used with - * window probe and clear the event. Put - * it back into the send queue as if has - * not been sent. - */ - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (tp1->window_probe) { - sctp_window_probe_recovery(stcb, asoc, tp1); - break; - } - } - } - if (net->flight_size) { - j++; - if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net); - } - if (net->window_probe) { - net->window_probe = 0; - } - } else { - if (net->window_probe) { - /* In window probes we must assure a timer is still running there */ - if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net); - } - } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_36); - } - } - } - if ((j == 0) && - (!TAILQ_EMPTY(&asoc->sent_queue)) && - (asoc->sent_queue_retran_cnt == 0) && - (win_probe_recovered == 0) && - (done_once == 0)) { - /* huh, this should not happen unless all packets - * are PR-SCTP and marked to skip of course. - */ - if (sctp_fs_audit(asoc)) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - net->flight_size = 0; - } - asoc->total_flight = 0; - asoc->total_flight_count = 0; - asoc->sent_queue_retran_cnt = 0; - TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - sctp_flight_size_increase(tp1); - sctp_total_flight_increase(stcb, tp1); - } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - } - } - } - done_once = 1; - goto again; - } - /*********************************************/ - /* Here we perform PR-SCTP procedures */ - /* (section 4.2) */ - /*********************************************/ - /* C1. update advancedPeerAckPoint */ - if (SCTP_TSN_GT(cum_ack, asoc->advanced_peer_ack_point)) { - asoc->advanced_peer_ack_point = cum_ack; - } - /* C2. try to further move advancedPeerAckPoint ahead */ - if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) { - struct sctp_tmit_chunk *lchk; - uint32_t old_adv_peer_ack_point; - - old_adv_peer_ack_point = asoc->advanced_peer_ack_point; - lchk = sctp_try_advance_peer_ack_point(stcb, asoc); - /* C3. See if we need to send a Fwd-TSN */ - if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cum_ack)) { - /* - * ISSUE with ECN, see FWD-TSN processing. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xee, cum_ack, asoc->advanced_peer_ack_point, - old_adv_peer_ack_point); - } - if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) { - send_forward_tsn(stcb, asoc); - } else if (lchk) { - /* try to FR fwd-tsn's that get lost too */ - if (lchk->rec.data.fwd_tsn_cnt >= 3) { - send_forward_tsn(stcb, asoc); - } - } - } - for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) { - if (lchk->whoTo != NULL) { - break; - } - } - if (lchk != NULL) { - /* Assure a timer is up */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, lchk->whoTo); - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_SACK_RWND_UPDATE, - a_rwnd, - stcb->asoc.peers_rwnd, - stcb->asoc.total_flight, - stcb->asoc.total_output_queue_size); - } -} - -void -sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *abort_flag) -{ - /* Copy cum-ack */ - uint32_t cum_ack, a_rwnd; - - cum_ack = ntohl(cp->cumulative_tsn_ack); - /* Arrange so a_rwnd does NOT change */ - a_rwnd = stcb->asoc.peers_rwnd + stcb->asoc.total_flight; - - /* Now call the express sack handling */ - sctp_express_handle_sack(stcb, cum_ack, a_rwnd, abort_flag, 0); -} - -static void -sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, - struct sctp_stream_in *strmin) -{ - struct sctp_queued_to_read *control, *ncontrol; - struct sctp_association *asoc; - uint32_t mid; - int need_reasm_check = 0; - - asoc = &stcb->asoc; - mid = strmin->last_mid_delivered; - /* - * First deliver anything prior to and including the stream no that - * came in. - */ - TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) { - if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) { - /* this is deliverable now */ - if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { - if (control->on_strm_q) { - if (control->on_strm_q == SCTP_ON_ORDERED) { - TAILQ_REMOVE(&strmin->inqueue, control, next_instrm); - } else if (control->on_strm_q == SCTP_ON_UNORDERED) { - TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm); -#ifdef INVARIANTS - } else { - panic("strmin: %p ctl: %p unknown %d", - strmin, control, control->on_strm_q); -#endif - } - control->on_strm_q = 0; - } - /* subtract pending on streams */ - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - /* deliver it to at least the delivery-q */ - if (stcb->sctp_socket) { - sctp_mark_non_revokable(asoc, control->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, - 1, SCTP_READ_LOCK_HELD, - SCTP_SO_NOT_LOCKED); - } - } else { - /* Its a fragmented message */ - if (control->first_frag_seen) { - /* Make it so this is next to deliver, we restore later */ - strmin->last_mid_delivered = control->mid - 1; - need_reasm_check = 1; - break; - } - } - } else { - /* no more delivery now. */ - break; - } - } - if (need_reasm_check) { - int ret; - ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD); - if (SCTP_MID_GT(asoc->idata_supported, mid, strmin->last_mid_delivered)) { - /* Restore the next to deliver unless we are ahead */ - strmin->last_mid_delivered = mid; - } - if (ret == 0) { - /* Left the front Partial one on */ - return; - } - need_reasm_check = 0; - } - /* - * now we must deliver things in queue the normal way if any are - * now ready. - */ - mid = strmin->last_mid_delivered + 1; - TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) { - if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) { - if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { - /* this is deliverable now */ - if (control->on_strm_q) { - if (control->on_strm_q == SCTP_ON_ORDERED) { - TAILQ_REMOVE(&strmin->inqueue, control, next_instrm); - } else if (control->on_strm_q == SCTP_ON_UNORDERED) { - TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm); -#ifdef INVARIANTS - } else { - panic("strmin: %p ctl: %p unknown %d", - strmin, control, control->on_strm_q); -#endif - } - control->on_strm_q = 0; - } - /* subtract pending on streams */ - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - /* deliver it to at least the delivery-q */ - strmin->last_mid_delivered = control->mid; - if (stcb->sctp_socket) { - sctp_mark_non_revokable(asoc, control->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED); - } - mid = strmin->last_mid_delivered + 1; - } else { - /* Its a fragmented message */ - if (control->first_frag_seen) { - /* Make it so this is next to deliver */ - strmin->last_mid_delivered = control->mid - 1; - need_reasm_check = 1; - break; - } - } - } else { - break; - } - } - if (need_reasm_check) { - (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD); - } -} - -static void -sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, - struct sctp_association *asoc, struct sctp_stream_in *strm, - struct sctp_queued_to_read *control, int ordered, uint32_t cumtsn) -{ - struct sctp_tmit_chunk *chk, *nchk; - - /* - * For now large messages held on the stream reasm that are - * complete will be tossed too. We could in theory do more - * work to spin through and stop after dumping one msg aka - * seeing the start of a new msg at the head, and call the - * delivery function... to see if it can be delivered... But - * for now we just dump everything on the queue. - */ - if (!asoc->idata_supported && !ordered && - control->first_frag_seen && - SCTP_TSN_GT(control->fsn_included, cumtsn)) { - return; - } - TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { - /* Purge hanging chunks */ - if (!asoc->idata_supported && !ordered) { - if (SCTP_TSN_GT(chk->rec.data.tsn, cumtsn)) { - break; - } - } - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - if (asoc->size_on_reasm_queue >= chk->send_size) { - asoc->size_on_reasm_queue -= chk->send_size; - } else { -#ifdef INVARIANTS - panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size); -#else - asoc->size_on_reasm_queue = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - if (!TAILQ_EMPTY(&control->reasm)) { - /* This has to be old data, unordered */ - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_reset_a_control(control, stcb->sctp_ep, cumtsn); - chk = TAILQ_FIRST(&control->reasm); - if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - sctp_add_chk_to_control(control, strm, stcb, asoc, - chk, SCTP_READ_LOCK_HELD); - } - sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD); - return; - } - if (control->on_strm_q == SCTP_ON_ORDERED) { - TAILQ_REMOVE(&strm->inqueue, control, next_instrm); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - control->on_strm_q = 0; - } else if (control->on_strm_q == SCTP_ON_UNORDERED) { - TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); - control->on_strm_q = 0; -#ifdef INVARIANTS - } else if (control->on_strm_q) { - panic("strm: %p ctl: %p unknown %d", - strm, control, control->on_strm_q); -#endif - } - control->on_strm_q = 0; - if (control->on_read_q == 0) { - sctp_free_remote_addr(control->whoFrom); - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_free_a_readq(stcb, control); - } -} - -void -sctp_handle_forward_tsn(struct sctp_tcb *stcb, - struct sctp_forward_tsn_chunk *fwd, - int *abort_flag, struct mbuf *m , int offset) -{ - /* The pr-sctp fwd tsn */ - /* - * here we will perform all the data receiver side steps for - * processing FwdTSN, as required in by pr-sctp draft: - * - * Assume we get FwdTSN(x): - * - * 1) update local cumTSN to x - * 2) try to further advance cumTSN to x + others we have - * 3) examine and update re-ordering queue on pr-in-streams - * 4) clean up re-assembly queue - * 5) Send a sack to report where we are. - */ - struct sctp_association *asoc; - uint32_t new_cum_tsn, gap; - unsigned int i, fwd_sz, m_size; - struct sctp_stream_in *strm; - struct sctp_queued_to_read *control, *ncontrol; - - asoc = &stcb->asoc; - if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) { - SCTPDBG(SCTP_DEBUG_INDATA1, - "Bad size too small/big fwd-tsn\n"); - return; - } - m_size = (stcb->asoc.mapping_array_size << 3); - /*************************************************************/ - /* 1. Here we update local cumTSN and shift the bitmap array */ - /*************************************************************/ - new_cum_tsn = ntohl(fwd->new_cumulative_tsn); - - if (SCTP_TSN_GE(asoc->cumulative_tsn, new_cum_tsn)) { - /* Already got there ... */ - return; - } - /* - * now we know the new TSN is more advanced, let's find the actual - * gap - */ - SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn); - asoc->cumulative_tsn = new_cum_tsn; - if (gap >= m_size) { - if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - /* - * out of range (of single byte chunks in the rwnd I - * give out). This must be an attacker. - */ - *abort_flag = 1; - SCTP_SNPRINTF(msg, sizeof(msg), - "New cum ack %8.8x too high, highest TSN %8.8x", - new_cum_tsn, asoc->highest_tsn_inside_map); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_37; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - return; - } - SCTP_STAT_INCR(sctps_fwdtsn_map_over); - - memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size); - asoc->mapping_array_base_tsn = new_cum_tsn + 1; - asoc->highest_tsn_inside_map = new_cum_tsn; - - memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size); - asoc->highest_tsn_inside_nr_map = new_cum_tsn; - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); - } - } else { - SCTP_TCB_LOCK_ASSERT(stcb); - for (i = 0; i <= gap; i++) { - if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i) && - !SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, i)) { - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i); - if (SCTP_TSN_GT(asoc->mapping_array_base_tsn + i, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = asoc->mapping_array_base_tsn + i; - } - } - } - } - /*************************************************************/ - /* 2. Clear up re-assembly queue */ - /*************************************************************/ - - /* This is now done as part of clearing up the stream/seq */ - if (asoc->idata_supported == 0) { - uint16_t sid; - - /* Flush all the un-ordered data based on cum-tsn */ - SCTP_INP_READ_LOCK(stcb->sctp_ep); - for (sid = 0; sid < asoc->streamincnt; sid++) { - strm = &asoc->strmin[sid]; - if (!TAILQ_EMPTY(&strm->uno_inqueue)) { - sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), 0, new_cum_tsn); - } - } - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); - } - /*******************************************************/ - /* 3. Update the PR-stream re-ordering queues and fix */ - /* delivery issues as needed. */ - /*******************************************************/ - fwd_sz -= sizeof(*fwd); - if (m && fwd_sz) { - /* New method. */ - unsigned int num_str; - uint32_t mid; - uint16_t sid; - uint16_t ordered, flags; - struct sctp_strseq *stseq, strseqbuf; - struct sctp_strseq_mid *stseq_m, strseqbuf_m; - offset += sizeof(*fwd); - - SCTP_INP_READ_LOCK(stcb->sctp_ep); - if (asoc->idata_supported) { - num_str = fwd_sz / sizeof(struct sctp_strseq_mid); - } else { - num_str = fwd_sz / sizeof(struct sctp_strseq); - } - for (i = 0; i < num_str; i++) { - if (asoc->idata_supported) { - stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset, - sizeof(struct sctp_strseq_mid), - (uint8_t *)&strseqbuf_m); - offset += sizeof(struct sctp_strseq_mid); - if (stseq_m == NULL) { - break; - } - sid = ntohs(stseq_m->sid); - mid = ntohl(stseq_m->mid); - flags = ntohs(stseq_m->flags); - if (flags & PR_SCTP_UNORDERED_FLAG) { - ordered = 0; - } else { - ordered = 1; - } - } else { - stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset, - sizeof(struct sctp_strseq), - (uint8_t *)&strseqbuf); - offset += sizeof(struct sctp_strseq); - if (stseq == NULL) { - break; - } - sid = ntohs(stseq->sid); - mid = (uint32_t)ntohs(stseq->ssn); - ordered = 1; - } - /* Convert */ - - /* now process */ - - /* - * Ok we now look for the stream/seq on the read queue - * where its not all delivered. If we find it we transmute the - * read entry into a PDI_ABORTED. - */ - if (sid >= asoc->streamincnt) { - /* screwed up streams, stop! */ - break; - } - if ((asoc->str_of_pdapi == sid) && - (asoc->ssn_of_pdapi == mid)) { - /* If this is the one we were partially delivering - * now then we no longer are. Note this will change - * with the reassembly re-write. - */ - asoc->fragmented_delivery_inprogress = 0; - } - strm = &asoc->strmin[sid]; - if (ordered) { - TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, ncontrol) { - if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) { - sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn); - } - } - } else { - if (asoc->idata_supported) { - TAILQ_FOREACH_SAFE(control, &strm->uno_inqueue, next_instrm, ncontrol) { - if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) { - sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn); - } - } - } else { - if (!TAILQ_EMPTY(&strm->uno_inqueue)) { - sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), ordered, new_cum_tsn); - } - } - } - TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) { - if ((control->sinfo_stream == sid) && - (SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) { - control->pdapi_aborted = 1; - control->end_added = 1; - if (control->on_strm_q == SCTP_ON_ORDERED) { - TAILQ_REMOVE(&strm->inqueue, control, next_instrm); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - } else if (control->on_strm_q == SCTP_ON_UNORDERED) { - TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); -#ifdef INVARIANTS - } else if (control->on_strm_q) { - panic("strm: %p ctl: %p unknown %d", - strm, control, control->on_strm_q); -#endif - } - control->on_strm_q = 0; - sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, - stcb, - SCTP_PARTIAL_DELIVERY_ABORTED, - (void *)control, - SCTP_SO_NOT_LOCKED); - break; - } else if ((control->sinfo_stream == sid) && - SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) { - /* We are past our victim SSN */ - break; - } - } - if (SCTP_MID_GT(asoc->idata_supported, mid, strm->last_mid_delivered)) { - /* Update the sequence number */ - strm->last_mid_delivered = mid; - } - /* now kick the stream the new way */ - /*sa_ignore NO_NULL_CHK*/ - sctp_kick_prsctp_reorder_queue(stcb, strm); - } - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); - } - /* - * Now slide thing forward. - */ - sctp_slide_mapping_arrays(stcb); -} diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.h deleted file mode 100644 index c9b71054..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_indata.h +++ /dev/null @@ -1,121 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_INDATA_H_ -#define _NETINET_SCTP_INDATA_H_ - -#if defined(_KERNEL) || defined(__Userspace__) - -struct sctp_queued_to_read * -sctp_build_readq_entry(struct sctp_tcb *stcb, - struct sctp_nets *net, - uint32_t tsn, uint32_t ppid, - uint32_t context, uint16_t sid, - uint32_t mid, uint8_t flags, - struct mbuf *dm); - -#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, sid, flags, dm, tfsn, mid) do { \ - if (_ctl) { \ - atomic_add_int(&((net)->ref_count), 1); \ - memset(_ctl, 0, sizeof(struct sctp_queued_to_read)); \ - (_ctl)->sinfo_stream = sid; \ - TAILQ_INIT(&_ctl->reasm); \ - (_ctl)->top_fsn = tfsn; \ - (_ctl)->mid = mid; \ - (_ctl)->sinfo_flags = (flags << 8); \ - (_ctl)->sinfo_ppid = ppid; \ - (_ctl)->sinfo_context = context; \ - (_ctl)->fsn_included = 0xffffffff; \ - (_ctl)->sinfo_tsn = tsn; \ - (_ctl)->sinfo_cumtsn = tsn; \ - (_ctl)->sinfo_assoc_id = sctp_get_associd((in_it)); \ - (_ctl)->whoFrom = net; \ - (_ctl)->data = dm; \ - (_ctl)->stcb = (in_it); \ - (_ctl)->port_from = (in_it)->rport; \ - if ((in_it)->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { \ - (_ctl)->do_not_ref_stcb = 1; \ - }\ - } \ -} while (0) - -struct mbuf * -sctp_build_ctl_nchunk(struct sctp_inpcb *inp, - struct sctp_sndrcvinfo *sinfo); - -void sctp_set_rwnd(struct sctp_tcb *, struct sctp_association *); - -uint32_t -sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc); - -void -sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, - uint32_t rwnd, int *abort_now, int ecne_seen); - -void -sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, - struct sctp_tcb *stcb, - uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup, - int *abort_now, uint8_t flags, - uint32_t cum_ack, uint32_t rwnd, int ecne_seen); - -/* draft-ietf-tsvwg-usctp */ -void -sctp_handle_forward_tsn(struct sctp_tcb *, - struct sctp_forward_tsn_chunk *, int *, struct mbuf *, int); - -struct sctp_tmit_chunk * -sctp_try_advance_peer_ack_point(struct sctp_tcb *, struct sctp_association *); - -void sctp_service_queues(struct sctp_tcb *, struct sctp_association *); - -void -sctp_update_acked(struct sctp_tcb *, struct sctp_shutdown_chunk *, int *); - -int -sctp_process_data(struct mbuf **, int, int *, int, - struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *, uint32_t *); - -void sctp_slide_mapping_arrays(struct sctp_tcb *stcb); - -void sctp_sack_check(struct sctp_tcb *, int); - -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.c deleted file mode 100644 index 920d6be0..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.c +++ /dev/null @@ -1,6486 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#if defined(INET) || defined(INET6) -#if !defined(_WIN32) -#include -#endif -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif - -static void -sctp_stop_all_cookie_timers(struct sctp_tcb *stcb) -{ - struct sctp_nets *net; - - /* This now not only stops all cookie timers - * it also stops any INIT timers as well. This - * will make sure that the timers are stopped in - * all collision cases. - */ - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->rxt_timer.type == SCTP_TIMER_TYPE_COOKIE) { - sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, - stcb->sctp_ep, - stcb, - net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_1); - } else if (net->rxt_timer.type == SCTP_TIMER_TYPE_INIT) { - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, - stcb->sctp_ep, - stcb, - net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_2); - } - } -} - -/* INIT handler */ -static void -sctp_handle_init(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, - struct sctp_init_chunk *cp, struct sctp_inpcb *inp, - struct sctp_tcb *stcb, struct sctp_nets *net, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_init *init; - struct mbuf *op_err; - - SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_init: handling INIT tcb:%p\n", - (void *)stcb); - if (stcb == NULL) { - SCTP_INP_RLOCK(inp); - } - /* Validate parameters */ - init = &cp->init; - if (ntohl(init->initiate_tag) == 0) { - goto outnow; - } - if ((ntohl(init->a_rwnd) < SCTP_MIN_RWND) || - (ntohs(init->num_inbound_streams) == 0) || - (ntohs(init->num_outbound_streams) == 0)) { - /* protocol error... send abort */ - op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, ""); - sctp_send_abort(m, iphlen, src, dst, sh, init->initiate_tag, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - goto outnow; - } - if (sctp_validate_init_auth_params(m, offset + sizeof(*cp), - offset + ntohs(cp->ch.chunk_length))) { - /* auth parameter(s) error... send abort */ - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Problem with AUTH parameters"); - sctp_send_abort(m, iphlen, src, dst, sh, init->initiate_tag, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - goto outnow; - } - /* We are only accepting if we have a listening socket.*/ - if ((stcb == NULL) && - ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (!SCTP_IS_LISTENING(inp)))) { - /* - * FIX ME ?? What about TCP model and we have a - * match/restart case? Actually no fix is needed. - * the lookup will always find the existing assoc so stcb - * would not be NULL. It may be questionable to do this - * since we COULD just send back the INIT-ACK and hope that - * the app did accept()'s by the time the COOKIE was sent. But - * there is a price to pay for COOKIE generation and I don't - * want to pay it on the chance that the app will actually do - * some accepts(). The App just looses and should NOT be in - * this state :-) - */ - if (SCTP_BASE_SYSCTL(sctp_blackhole) == 0) { - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "No listener"); - sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - } - goto outnow; - } - if ((stcb != NULL) && - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT)) { - SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending SHUTDOWN-ACK\n"); - sctp_send_shutdown_ack(stcb, NULL); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); - } else { - SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n"); - sctp_send_initiate_ack(inp, stcb, net, m, iphlen, offset, - src, dst, sh, cp, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - } - outnow: - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); - } -} - -/* - * process peer "INIT/INIT-ACK" chunk returns value < 0 on error - */ - -int -sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) -{ - int unsent_data; - unsigned int i; - struct sctp_stream_queue_pending *sp; - struct sctp_association *asoc; - - SCTP_TCB_LOCK_ASSERT(stcb); - - /* This function returns if any stream has true unsent data on it. - * Note that as it looks through it will clean up any places that - * have old data that has been sent but left at top of stream queue. - */ - asoc = &stcb->asoc; - unsent_data = 0; - if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { - /* Check to see if some data queued */ - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - /*sa_ignore FREED_MEMORY*/ - sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue); - if (sp == NULL) { - continue; - } - if ((sp->msg_is_complete) && - (sp->length == 0) && - (sp->sender_all_done)) { - /* We are doing differed cleanup. Last - * time through when we took all the data - * the sender_all_done was not set. - */ - if (sp->put_last_out == 0) { - SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n"); - SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", - sp->sender_all_done, - sp->length, - sp->msg_is_complete, - sp->put_last_out); - } - atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1); - TAILQ_REMOVE(&stcb->asoc.strmout[i].outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, &asoc->strmout[i], sp); - if (sp->net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - } - sctp_free_a_strmoq(stcb, sp, so_locked); - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - unsent_data++; - } - } else { - unsent_data++; - } - if (unsent_data > 0) { - break; - } - } - } - return (unsent_data); -} - -static int -sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) -{ - struct sctp_init *init; - struct sctp_association *asoc; - struct sctp_nets *lnet; - unsigned int i; - - SCTP_TCB_LOCK_ASSERT(stcb); - - init = &cp->init; - asoc = &stcb->asoc; - /* save off parameters */ - asoc->peer_vtag = ntohl(init->initiate_tag); - asoc->peers_rwnd = ntohl(init->a_rwnd); - /* init tsn's */ - asoc->highest_tsn_inside_map = asoc->asconf_seq_in = ntohl(init->initial_tsn) - 1; - - if (!TAILQ_EMPTY(&asoc->nets)) { - /* update any ssthresh's that may have a default */ - TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { - lnet->ssthresh = asoc->peers_rwnd; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE|SCTP_CWND_LOGGING_ENABLE)) { - sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_INITIALIZATION); - } - } - } - if (asoc->pre_open_streams > ntohs(init->num_inbound_streams)) { - unsigned int newcnt; - struct sctp_stream_out *outs; - struct sctp_stream_queue_pending *sp, *nsp; - struct sctp_tmit_chunk *chk, *nchk; - - /* abandon the upper streams */ - newcnt = ntohs(init->num_inbound_streams); - TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { - if (chk->rec.data.sid >= newcnt) { - TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); - asoc->send_queue_cnt--; - if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[chk->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", chk->rec.data.sid); -#endif - } - if (chk->data != NULL) { - sctp_free_bufspace(stcb, asoc, chk, 1); - sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, - 0, chk, SCTP_SO_NOT_LOCKED); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - /*sa_ignore FREED_MEMORY*/ - } - } - if (asoc->strmout) { - for (i = newcnt; i < asoc->pre_open_streams; i++) { - outs = &asoc->strmout[i]; - TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { - atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1); - TAILQ_REMOVE(&outs->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp); - sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, - stcb, 0, sp, SCTP_SO_NOT_LOCKED); - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - } - if (sp->net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - /* Free the chunk */ - sctp_free_a_strmoq(stcb, sp, SCTP_SO_NOT_LOCKED); - /*sa_ignore FREED_MEMORY*/ - } - outs->state = SCTP_STREAM_CLOSED; - } - } - /* cut back the count */ - asoc->pre_open_streams = newcnt; - } - asoc->streamoutcnt = asoc->pre_open_streams; - if (asoc->strmout) { - for (i = 0; i < asoc->streamoutcnt; i++) { - asoc->strmout[i].state = SCTP_STREAM_OPEN; - } - } - /* EY - nr_sack: initialize highest tsn in nr_mapping_array */ - asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(0, 5, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); - } - /* This is the next one we expect */ - asoc->str_reset_seq_in = asoc->asconf_seq_in + 1; - - asoc->mapping_array_base_tsn = ntohl(init->initial_tsn); - asoc->tsn_last_delivered = asoc->cumulative_tsn = asoc->asconf_seq_in; - - asoc->advanced_peer_ack_point = asoc->last_acked_seq; - /* open the requested streams */ - - if (asoc->strmin != NULL) { - /* Free the old ones */ - for (i = 0; i < asoc->streamincnt; i++) { - sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue); - sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue); - } - SCTP_FREE(asoc->strmin, SCTP_M_STRMI); - } - if (asoc->max_inbound_streams > ntohs(init->num_outbound_streams)) { - asoc->streamincnt = ntohs(init->num_outbound_streams); - } else { - asoc->streamincnt = asoc->max_inbound_streams; - } - SCTP_MALLOC(asoc->strmin, struct sctp_stream_in *, asoc->streamincnt * - sizeof(struct sctp_stream_in), SCTP_M_STRMI); - if (asoc->strmin == NULL) { - /* we didn't get memory for the streams! */ - SCTPDBG(SCTP_DEBUG_INPUT2, "process_init: couldn't get memory for the streams!\n"); - return (-1); - } - for (i = 0; i < asoc->streamincnt; i++) { - asoc->strmin[i].sid = i; - asoc->strmin[i].last_mid_delivered = 0xffffffff; - TAILQ_INIT(&asoc->strmin[i].inqueue); - TAILQ_INIT(&asoc->strmin[i].uno_inqueue); - asoc->strmin[i].pd_api_started = 0; - asoc->strmin[i].delivery_started = 0; - } - /* - * load_address_from_init will put the addresses into the - * association when the COOKIE is processed or the INIT-ACK is - * processed. Both types of COOKIE's existing and new call this - * routine. It will remove addresses that are no longer in the - * association (for the restarting case where addresses are - * removed). Up front when the INIT arrives we will discard it if it - * is a restart and new addresses have been added. - */ - /* sa_ignore MEMLEAK */ - return (0); -} - -/* - * INIT-ACK message processing/consumption returns value < 0 on error - */ -static int -sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, - struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb, - struct sctp_nets *net, int *abort_no_unlock, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id) -{ - struct sctp_association *asoc; - struct mbuf *op_err; - int retval, abort_flag, cookie_found; - int initack_limit; - int nat_friendly = 0; - - /* First verify that we have no illegal param's */ - abort_flag = 0; - cookie_found = 0; - - op_err = sctp_arethere_unrecognized_parameters(m, - (offset + sizeof(struct sctp_init_chunk)), - &abort_flag, (struct sctp_chunkhdr *)cp, - &nat_friendly, &cookie_found); - if (abort_flag) { - /* Send an abort and notify peer */ - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - if (!cookie_found) { - uint16_t len; - - /* Only report the missing cookie parameter */ - if (op_err != NULL) { - sctp_m_freem(op_err); - } - len = (uint16_t)(sizeof(struct sctp_error_missing_param) + sizeof(uint16_t)); - /* We abort with an error of missing mandatory param */ - op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); - if (op_err != NULL) { - struct sctp_error_missing_param *cause; - - SCTP_BUF_LEN(op_err) = len; - cause = mtod(op_err, struct sctp_error_missing_param *); - /* Subtract the reserved param */ - cause->cause.code = htons(SCTP_CAUSE_MISSING_PARAM); - cause->cause.length = htons(len); - cause->num_missing_params = htonl(1); - cause->type[0] = htons(SCTP_STATE_COOKIE); - } - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-3); - } - asoc = &stcb->asoc; - asoc->peer_supports_nat = (uint8_t)nat_friendly; - /* process the peer's parameters in the INIT-ACK */ - if (sctp_process_init((struct sctp_init_chunk *)cp, stcb) < 0) { - if (op_err != NULL) { - sctp_m_freem(op_err); - } - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - initack_limit = offset + ntohs(cp->ch.chunk_length); - /* load all addresses */ - if ((retval = sctp_load_addresses_from_init(stcb, m, - offset + sizeof(struct sctp_init_chunk), - initack_limit, src, dst, NULL, stcb->asoc.port)) < 0) { - if (op_err != NULL) { - sctp_m_freem(op_err); - } - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Problem with address parameters"); - SCTPDBG(SCTP_DEBUG_INPUT1, - "Load addresses from INIT causes an abort %d\n", - retval); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - /* if the peer doesn't support asconf, flush the asconf queue */ - if (asoc->asconf_supported == 0) { - struct sctp_asconf_addr *param, *nparam; - - TAILQ_FOREACH_SAFE(param, &asoc->asconf_queue, next, nparam) { - TAILQ_REMOVE(&asoc->asconf_queue, param, next); - SCTP_FREE(param, SCTP_M_ASC_ADDR); - } - } - - stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs, - stcb->asoc.local_hmacs); - if (op_err) { - sctp_queue_op_err(stcb, op_err); - /* queuing will steal away the mbuf chain to the out queue */ - op_err = NULL; - } - /* extract the cookie and queue it to "echo" it back... */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INPUT, - __LINE__); - } - - /* - * Cancel the INIT timer, We do this first before queueing the - * cookie. We always cancel at the primary to assume that we are - * canceling the timer started by the INIT which always goes to the - * primary. - */ - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, stcb, - asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); - - /* calculate the RTO */ - if (asoc->overall_error_count == 0) { - sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, - SCTP_RTT_FROM_NON_DATA); - } - stcb->asoc.overall_error_count = 0; - net->error_count = 0; -#if defined(__Userspace__) - if (stcb->sctp_ep->recv_callback) { - if (stcb->sctp_socket) { - uint32_t inqueue_bytes, sb_free_now; - struct sctp_inpcb *inp; - - inp = stcb->sctp_ep; - inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk)); - sb_free_now = SCTP_SB_LIMIT_SND(stcb->sctp_socket) - (inqueue_bytes + stcb->asoc.sb_send_resv); - - /* check if the amount free in the send socket buffer crossed the threshold */ - if (inp->send_callback && - (((inp->send_sb_threshold > 0) && - (sb_free_now >= inp->send_sb_threshold) && - (stcb->asoc.chunks_on_out_queue <= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) || - (inp->send_sb_threshold == 0))) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - inp->send_callback(stcb->sctp_socket, sb_free_now, inp->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - } - } -#endif - retval = sctp_send_cookie_echo(m, offset, initack_limit, stcb, net); - return (retval); -} - -static void -sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, - struct sctp_tcb *stcb, struct sctp_nets *net) -{ - union sctp_sockstore store; - struct sctp_nets *r_net, *f_net; - struct timeval tv; - int req_prim = 0; - uint16_t old_error_counter; - - if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_heartbeat_chunk)) { - /* Invalid length */ - return; - } - - memset(&store, 0, sizeof(store)); - switch (cp->heartbeat.hb_info.addr_family) { -#ifdef INET - case AF_INET: - if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in)) { - store.sin.sin_family = cp->heartbeat.hb_info.addr_family; -#ifdef HAVE_SIN_LEN - store.sin.sin_len = cp->heartbeat.hb_info.addr_len; -#endif - store.sin.sin_port = stcb->rport; - memcpy(&store.sin.sin_addr, cp->heartbeat.hb_info.address, - sizeof(store.sin.sin_addr)); - } else { - return; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in6)) { - store.sin6.sin6_family = cp->heartbeat.hb_info.addr_family; -#ifdef HAVE_SIN6_LEN - store.sin6.sin6_len = cp->heartbeat.hb_info.addr_len; -#endif - store.sin6.sin6_port = stcb->rport; - memcpy(&store.sin6.sin6_addr, cp->heartbeat.hb_info.address, sizeof(struct in6_addr)); - } else { - return; - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_conn)) { - store.sconn.sconn_family = cp->heartbeat.hb_info.addr_family; -#ifdef HAVE_SCONN_LEN - store.sconn.sconn_len = cp->heartbeat.hb_info.addr_len; -#endif - store.sconn.sconn_port = stcb->rport; - memcpy(&store.sconn.sconn_addr, cp->heartbeat.hb_info.address, sizeof(void *)); - } else { - return; - } - break; -#endif - default: - return; - } - r_net = sctp_findnet(stcb, &store.sa); - if (r_net == NULL) { - SCTPDBG(SCTP_DEBUG_INPUT1, "Huh? I can't find the address I sent it to, discard\n"); - return; - } - if ((r_net && (r_net->dest_state & SCTP_ADDR_UNCONFIRMED)) && - (r_net->heartbeat_random1 == cp->heartbeat.hb_info.random_value1) && - (r_net->heartbeat_random2 == cp->heartbeat.hb_info.random_value2)) { - /* - * If the its a HB and it's random value is correct when can - * confirm the destination. - */ - r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; - if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) { - stcb->asoc.primary_destination = r_net; - r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; - f_net = TAILQ_FIRST(&stcb->asoc.nets); - if (f_net != r_net) { - /* first one on the list is NOT the primary - * sctp_cmpaddr() is much more efficient if - * the primary is the first on the list, make it - * so. - */ - TAILQ_REMOVE(&stcb->asoc.nets, r_net, sctp_next); - TAILQ_INSERT_HEAD(&stcb->asoc.nets, r_net, sctp_next); - } - req_prim = 1; - } - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, - stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, - r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_4); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INPUT, - __LINE__); - } - stcb->asoc.overall_error_count = 0; - old_error_counter = r_net->error_count; - r_net->error_count = 0; - r_net->hb_responded = 1; - tv.tv_sec = cp->heartbeat.hb_info.time_value_1; - tv.tv_usec = cp->heartbeat.hb_info.time_value_2; - /* Now lets do a RTO with this */ - sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, - SCTP_RTT_FROM_NON_DATA); - if ((r_net->dest_state & SCTP_ADDR_REACHABLE) == 0) { - r_net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, - 0, (void *)r_net, SCTP_SO_NOT_LOCKED); - } - if (r_net->dest_state & SCTP_ADDR_PF) { - r_net->dest_state &= ~SCTP_ADDR_PF; - stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net); - } - if (old_error_counter > 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, - stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_5); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); - } - if (r_net == stcb->asoc.primary_destination) { - if (stcb->asoc.alternate) { - /* release the alternate, primary is good */ - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - } - /* Mobility adaptation */ - if (req_prim) { - if ((sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_BASE) || - sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) && - sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_PRIM_DELETED)) { - sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, - stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) { - sctp_assoc_immediate_retrans(stcb, - stcb->asoc.primary_destination); - } - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_BASE)) { - sctp_move_chunks_from_net(stcb, - stcb->asoc.deleted_primary); - } - sctp_delete_prim_timer(stcb->sctp_ep, stcb); - } - } -} - -static int -sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) -{ - /* - * Return 0 means we want you to proceed with the abort - * non-zero means no abort processing. - */ - uint32_t new_vtag; - struct sctpasochead *head; - - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_INFO_WLOCK(); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } else { - return (0); - } - new_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1); - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { - /* generate a new vtag and send init */ - LIST_REMOVE(stcb, sctp_asocs); - stcb->asoc.my_vtag = new_vtag; - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; - /* put it in the bucket in the vtag hash of assoc's for the system */ - LIST_INSERT_HEAD(head, stcb, sctp_asocs); - SCTP_INP_INFO_WUNLOCK(); - sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - return (1); - } else { - /* treat like a case where the cookie expired i.e.: - * - dump current cookie. - * - generate a new vtag. - * - resend init. - */ - /* generate a new vtag and send init */ - LIST_REMOVE(stcb, sctp_asocs); - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - sctp_stop_all_cookie_timers(stcb); - sctp_toss_old_cookies(stcb, &stcb->asoc); - stcb->asoc.my_vtag = new_vtag; - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; - /* put it in the bucket in the vtag hash of assoc's for the system */ - LIST_INSERT_HEAD(head, stcb, sctp_asocs); - SCTP_INP_INFO_WUNLOCK(); - sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - return (1); - } - return (0); -} - -static int -sctp_handle_nat_missing_state(struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - /* return 0 means we want you to proceed with the abort - * non-zero means no abort processing - */ - if (stcb->asoc.auth_supported == 0) { - SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_nat_missing_state: Peer does not support AUTH, cannot send an asconf\n"); - return (0); - } - sctp_asconf_send_nat_state_update(stcb, net); - return (1); -} - -/* Returns 1 if the stcb was aborted, 0 otherwise */ -static int -sctp_handle_abort(struct sctp_abort_chunk *abort, - struct sctp_tcb *stcb, struct sctp_nets *net) -{ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - uint16_t len; - uint16_t error; - - SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: handling ABORT\n"); - if (stcb == NULL) - return (0); - - len = ntohs(abort->ch.chunk_length); - if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause)) { - /* Need to check the cause codes for our - * two magic nat aborts which don't kill the assoc - * necessarily. - */ - struct sctp_error_cause *cause; - - cause = (struct sctp_error_cause *)(abort + 1); - error = ntohs(cause->code); - if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) { - SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state, ABORT flags:%x\n", - abort->ch.chunk_flags); - if (sctp_handle_nat_colliding_state(stcb)) { - return (0); - } - } else if (error == SCTP_CAUSE_NAT_MISSING_STATE) { - SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state, ABORT flags:%x\n", - abort->ch.chunk_flags); - if (sctp_handle_nat_missing_state(stcb, net)) { - return (0); - } - } - } else { - error = 0; - } - /* stop any receive timers */ - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_7); - /* notify user of the abort and clean up... */ - sctp_abort_notification(stcb, true, false, error, abort, SCTP_SO_NOT_LOCKED); - /* free the tcb */ - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } -#ifdef SCTP_ASOCLOG_OF_TSNS - sctp_print_out_track_log(stcb); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_8); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n"); - return (1); -} - -static void -sctp_start_net_timers(struct sctp_tcb *stcb) -{ - uint32_t cnt_hb_sent; - struct sctp_nets *net; - - cnt_hb_sent = 0; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* For each network start: - * 1) A pmtu timer. - * 2) A HB timer - * 3) If the dest in unconfirmed send - * a hb as well if under max_hb_burst have - * been sent. - */ - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && - (cnt_hb_sent < SCTP_BASE_SYSCTL(sctp_hb_maxburst))) { - sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - cnt_hb_sent++; - } - } - if (cnt_hb_sent) { - sctp_chunk_output(stcb->sctp_ep, stcb, - SCTP_OUTPUT_FROM_COOKIE_ACK, - SCTP_SO_NOT_LOCKED); - } -} - -static void -sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, - struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag) -{ - struct sctp_association *asoc; - int some_on_streamwheel; - int old_state; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown: handling SHUTDOWN\n"); - if (stcb == NULL) - return; - asoc = &stcb->asoc; - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - return; - } - if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_shutdown_chunk)) { - /* Shutdown NOT the expected size */ - return; - } - old_state = SCTP_GET_STATE(stcb); - sctp_update_acked(stcb, cp, abort_flag); - if (*abort_flag) { - return; - } - if (asoc->control_pdapi) { - /* With a normal shutdown - * we assume the end of last record. - */ - SCTP_INP_READ_LOCK(stcb->sctp_ep); - if (asoc->control_pdapi->on_strm_q) { - struct sctp_stream_in *strm; - - strm = &asoc->strmin[asoc->control_pdapi->sinfo_stream]; - if (asoc->control_pdapi->on_strm_q == SCTP_ON_UNORDERED) { - /* Unordered */ - TAILQ_REMOVE(&strm->uno_inqueue, asoc->control_pdapi, next_instrm); - asoc->control_pdapi->on_strm_q = 0; - } else if (asoc->control_pdapi->on_strm_q == SCTP_ON_ORDERED) { - /* Ordered */ - TAILQ_REMOVE(&strm->inqueue, asoc->control_pdapi, next_instrm); - asoc->control_pdapi->on_strm_q = 0; -#ifdef INVARIANTS - } else { - panic("Unknown state on ctrl:%p on_strm_q:%d", - asoc->control_pdapi, - asoc->control_pdapi->on_strm_q); -#endif - } - } - asoc->control_pdapi->end_added = 1; - asoc->control_pdapi->pdapi_aborted = 1; - asoc->control_pdapi = NULL; - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - if (stcb->sctp_socket) { - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - /* goto SHUTDOWN_RECEIVED state to block new requests */ - if (stcb->sctp_socket) { - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT)) { - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_RECEIVED); - /* notify upper layer that peer has initiated a shutdown */ - sctp_ulp_notify(SCTP_NOTIFY_PEER_SHUTDOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - - /* reset time */ - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); - } - } - if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) { - /* - * stop the shutdown timer, since we WILL move to - * SHUTDOWN-ACK-SENT. - */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_9); - } - /* Now is there unsent data on a stream somewhere? */ - some_on_streamwheel = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED); - - if (!TAILQ_EMPTY(&asoc->send_queue) || - !TAILQ_EMPTY(&asoc->sent_queue) || - some_on_streamwheel) { - /* By returning we will push more data out */ - return; - } else { - /* no outstanding data to send, so move on... */ - /* send SHUTDOWN-ACK */ - /* move to SHUTDOWN-ACK-SENT state */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) { - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT); - sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown_ack(stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, - stcb->sctp_ep, stcb, net); - } else if (old_state == SCTP_STATE_SHUTDOWN_ACK_SENT) { - sctp_send_shutdown_ack(stcb, net); - } - } -} - -static void -sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, - struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_association *asoc; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); -#endif - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown_ack: handling SHUTDOWN ACK\n"); - if (stcb == NULL) - return; - - asoc = &stcb->asoc; - /* process according to association state */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - /* unexpected SHUTDOWN-ACK... do OOTB handling... */ - sctp_send_shutdown_complete(stcb, net, 1); - SCTP_TCB_UNLOCK(stcb); - return; - } - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - /* unexpected SHUTDOWN-ACK... so ignore... */ - SCTP_TCB_UNLOCK(stcb); - return; - } - if (asoc->control_pdapi) { - /* With a normal shutdown - * we assume the end of last record. - */ - SCTP_INP_READ_LOCK(stcb->sctp_ep); - asoc->control_pdapi->end_added = 1; - asoc->control_pdapi->pdapi_aborted = 1; - asoc->control_pdapi = NULL; - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } -#ifdef INVARIANTS - if (!TAILQ_EMPTY(&asoc->send_queue) || - !TAILQ_EMPTY(&asoc->sent_queue) || - sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) { - panic("Queues are not empty when handling SHUTDOWN-ACK"); - } -#endif - /* stop the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_10); - /* send SHUTDOWN-COMPLETE */ - sctp_send_shutdown_complete(stcb, net, 0); - /* notify upper layer protocol */ - if (stcb->sctp_socket) { - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_SB_CLEAR(stcb->sctp_socket->so_snd); - } - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - } - SCTP_STAT_INCR_COUNTER32(sctps_shutdown); - /* free the TCB but first save off the ep */ -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif -} - -static void -sctp_process_unrecog_chunk(struct sctp_tcb *stcb, uint8_t chunk_type) -{ - switch (chunk_type) { - case SCTP_ASCONF_ACK: - case SCTP_ASCONF: - sctp_asconf_cleanup(stcb); - break; - case SCTP_IFORWARD_CUM_TSN: - case SCTP_FORWARD_CUM_TSN: - stcb->asoc.prsctp_supported = 0; - break; - default: - SCTPDBG(SCTP_DEBUG_INPUT2, - "Peer does not support chunk type %d (0x%x).\n", - chunk_type, chunk_type); - break; - } -} - -/* - * Skip past the param header and then we will find the param that caused the - * problem. There are a number of param's in a ASCONF OR the prsctp param - * these will turn of specific features. - * XXX: Is this the right thing to do? - */ -static void -sctp_process_unrecog_param(struct sctp_tcb *stcb, uint16_t parameter_type) -{ - switch (parameter_type) { - /* pr-sctp draft */ - case SCTP_PRSCTP_SUPPORTED: - stcb->asoc.prsctp_supported = 0; - break; - case SCTP_SUPPORTED_CHUNK_EXT: - break; - /* draft-ietf-tsvwg-addip-sctp */ - case SCTP_HAS_NAT_SUPPORT: - stcb->asoc.peer_supports_nat = 0; - break; - case SCTP_ADD_IP_ADDRESS: - case SCTP_DEL_IP_ADDRESS: - case SCTP_SET_PRIM_ADDR: - stcb->asoc.asconf_supported = 0; - break; - case SCTP_SUCCESS_REPORT: - case SCTP_ERROR_CAUSE_IND: - SCTPDBG(SCTP_DEBUG_INPUT2, "Huh, the peer does not support success? or error cause?\n"); - SCTPDBG(SCTP_DEBUG_INPUT2, - "Turning off ASCONF to this strange peer\n"); - stcb->asoc.asconf_supported = 0; - break; - default: - SCTPDBG(SCTP_DEBUG_INPUT2, - "Peer does not support param type %d (0x%x)??\n", - parameter_type, parameter_type); - break; - } -} - -static int -sctp_handle_error(struct sctp_chunkhdr *ch, - struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t limit) -{ - struct sctp_error_cause *cause; - struct sctp_association *asoc; - uint32_t remaining_length, adjust; - uint16_t code, cause_code, cause_length; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - - /* parse through all of the errors and process */ - asoc = &stcb->asoc; - cause = (struct sctp_error_cause *)((caddr_t)ch + - sizeof(struct sctp_chunkhdr)); - remaining_length = ntohs(ch->chunk_length); - if (remaining_length > limit) { - remaining_length = limit; - } - if (remaining_length >= sizeof(struct sctp_chunkhdr)) { - remaining_length -= sizeof(struct sctp_chunkhdr); - } else { - remaining_length = 0; - } - code = 0; - while (remaining_length >= sizeof(struct sctp_error_cause)) { - /* Process an Error Cause */ - cause_code = ntohs(cause->code); - cause_length = ntohs(cause->length); - if ((cause_length > remaining_length) || (cause_length == 0)) { - /* Invalid cause length, possibly due to truncation. */ - SCTPDBG(SCTP_DEBUG_INPUT1, "Bogus length in cause - bytes left: %u cause length: %u\n", - remaining_length, cause_length); - return (0); - } - if (code == 0) { - /* report the first error cause */ - code = cause_code; - } - switch (cause_code) { - case SCTP_CAUSE_INVALID_STREAM: - case SCTP_CAUSE_MISSING_PARAM: - case SCTP_CAUSE_INVALID_PARAM: - case SCTP_CAUSE_NO_USER_DATA: - SCTPDBG(SCTP_DEBUG_INPUT1, "Software error we got a %u back? We have a bug :/ (or do they?)\n", - cause_code); - break; - case SCTP_CAUSE_NAT_COLLIDING_STATE: - SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state, ERROR flags: %x\n", - ch->chunk_flags); - if (sctp_handle_nat_colliding_state(stcb)) { - return (0); - } - break; - case SCTP_CAUSE_NAT_MISSING_STATE: - SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state, ERROR flags: %x\n", - ch->chunk_flags); - if (sctp_handle_nat_missing_state(stcb, net)) { - return (0); - } - break; - case SCTP_CAUSE_STALE_COOKIE: - /* - * We only act if we have echoed a cookie and are - * waiting. - */ - if ((cause_length >= sizeof(struct sctp_error_stale_cookie)) && - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - struct timeval now; - struct sctp_error_stale_cookie *stale_cookie; - uint64_t stale_time; - - asoc->stale_cookie_count++; - if (asoc->stale_cookie_count > asoc->max_init_times) { - sctp_abort_notification(stcb, false, true, 0, NULL, SCTP_SO_NOT_LOCKED); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_12); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (-1); - } - stale_cookie = (struct sctp_error_stale_cookie *)cause; - stale_time = ntohl(stale_cookie->stale_time); - if (stale_time == 0) { - /* Use an RTT as an approximation. */ - (void)SCTP_GETTIME_TIMEVAL(&now); - timevalsub(&now, &asoc->time_entered); - stale_time = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec; - if (stale_time == 0) { - stale_time = 1; - } - } - /* - * stale_time is in usec, convert it to msec. - * Round upwards, to ensure that it is non-zero. - */ - stale_time = (stale_time + 999) / 1000; - /* Double it, to be more robust on RTX. */ - stale_time = 2 * stale_time; - asoc->cookie_preserve_req = (uint32_t)stale_time; - if (asoc->overall_error_count == 0) { - sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, - SCTP_RTT_FROM_NON_DATA); - } - asoc->overall_error_count = 0; - /* Blast back to INIT state */ - sctp_toss_old_cookies(stcb, &stcb->asoc); - sctp_stop_all_cookie_timers(stcb); - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); - sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - } - break; - case SCTP_CAUSE_UNRESOLVABLE_ADDR: - /* - * Nothing we can do here, we don't do hostname - * addresses so if the peer does not like my IPv6 - * (or IPv4 for that matter) it does not matter. If - * they don't support that type of address, they can - * NOT possibly get that packet type... i.e. with no - * IPv6 you can't receive a IPv6 packet. so we can - * safely ignore this one. If we ever added support - * for HOSTNAME Addresses, then we would need to do - * something here. - */ - break; - case SCTP_CAUSE_UNRECOG_CHUNK: - if (cause_length >= sizeof(struct sctp_error_unrecognized_chunk)) { - struct sctp_error_unrecognized_chunk *unrec_chunk; - - unrec_chunk = (struct sctp_error_unrecognized_chunk *)cause; - sctp_process_unrecog_chunk(stcb, unrec_chunk->ch.chunk_type); - } - break; - case SCTP_CAUSE_UNRECOG_PARAM: - /* XXX: We only consider the first parameter */ - if (cause_length >= sizeof(struct sctp_error_cause) + sizeof(struct sctp_paramhdr)) { - struct sctp_paramhdr *unrec_parameter; - - unrec_parameter = (struct sctp_paramhdr *)(cause + 1); - sctp_process_unrecog_param(stcb, ntohs(unrec_parameter->param_type)); - } - break; - case SCTP_CAUSE_COOKIE_IN_SHUTDOWN: - /* - * We ignore this since the timer will drive out a - * new cookie anyway and there timer will drive us - * to send a SHUTDOWN_COMPLETE. We can't send one - * here since we don't have their tag. - */ - break; - case SCTP_CAUSE_DELETING_LAST_ADDR: - case SCTP_CAUSE_RESOURCE_SHORTAGE: - case SCTP_CAUSE_DELETING_SRC_ADDR: - /* - * We should NOT get these here, but in a - * ASCONF-ACK. - */ - SCTPDBG(SCTP_DEBUG_INPUT2, "Peer sends ASCONF errors in a error cause with code %u.\n", - cause_code); - break; - case SCTP_CAUSE_OUT_OF_RESC: - /* - * And what, pray tell do we do with the fact that - * the peer is out of resources? Not really sure we - * could do anything but abort. I suspect this - * should have came WITH an abort instead of in a - * OP-ERROR. - */ - break; - default: - SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_handle_error: unknown code 0x%x\n", - cause_code); - break; - } - adjust = SCTP_SIZE32(cause_length); - if (remaining_length >= adjust) { - remaining_length -= adjust; - } else { - remaining_length = 0; - } - cause = (struct sctp_error_cause *)((caddr_t)cause + adjust); - } - sctp_ulp_notify(SCTP_NOTIFY_REMOTE_ERROR, stcb, code, ch, SCTP_SO_NOT_LOCKED); - return (0); -} - -static int -sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, - struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb, - struct sctp_nets *net, int *abort_no_unlock, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id) -{ - struct sctp_init_ack *init_ack; - struct mbuf *op_err; - - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_init_ack: handling INIT-ACK\n"); - - if (stcb == NULL) { - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_init_ack: TCB is null\n"); - return (-1); - } - /* Only process the INIT-ACK chunk in COOKIE WAIT state.*/ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { - init_ack = &cp->init; - /* Validate parameters. */ - if ((ntohl(init_ack->initiate_tag) == 0) || - (ntohl(init_ack->a_rwnd) < SCTP_MIN_RWND) || - (ntohs(init_ack->num_inbound_streams) == 0) || - (ntohs(init_ack->num_outbound_streams) == 0)) { - /* One of the mandatory parameters is illegal. */ - op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, ""); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, - #if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, - #endif - vrf_id, net->port); - *abort_no_unlock = 1; - return (-1); - } - if (stcb->asoc.primary_destination->dest_state & - SCTP_ADDR_UNCONFIRMED) { - /* - * The primary is where we sent the INIT, we can - * always consider it confirmed when the INIT-ACK is - * returned. Do this before we load addresses - * though. - */ - stcb->asoc.primary_destination->dest_state &= - ~SCTP_ADDR_UNCONFIRMED; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, - stcb, 0, (void *)stcb->asoc.primary_destination, SCTP_SO_NOT_LOCKED); - } - if (sctp_process_init_ack(m, iphlen, offset, src, dst, sh, cp, stcb, - net, abort_no_unlock, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id) < 0) { - /* error in parsing parameters */ - return (-1); - } - /* Update our state. */ - SCTPDBG(SCTP_DEBUG_INPUT2, "moving to COOKIE-ECHOED state\n"); - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_ECHOED); - - /* Reset the RTO calculation. */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INPUT, - __LINE__); - } - stcb->asoc.overall_error_count = 0; - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - /* - * Collapse the init timer back in case of a exponential - * backoff. - */ - sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep, - stcb, net); - /* - * The output routine at the end of the inbound data processing - * will cause the cookie to be sent. - */ - SCTPDBG(SCTP_DEBUG_INPUT1, "Leaving handle-init-ack end\n"); - return (0); - } else { - return (-1); - } -} - -static struct sctp_tcb * -sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len, - struct sctp_inpcb *inp, struct sctp_nets **netp, - struct sockaddr *init_src, int *notification, - int auth_skipped, uint32_t auth_offset, uint32_t auth_len, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port); - -/* - * handle a state cookie for an existing association m: input packet mbuf - * chain-- assumes a pullup on IP/SCTP/COOKIE-ECHO chunk note: this is a - * "split" mbuf and the cookie signature does not exist offset: offset into - * mbuf to the cookie-echo chunk - */ -static struct sctp_tcb * -sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len, - struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets **netp, - struct sockaddr *init_src, int *notification, - int auth_skipped, uint32_t auth_offset, uint32_t auth_len, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_association *asoc; - struct sctp_init_chunk *init_cp, init_buf; - struct sctp_init_ack_chunk *initack_cp, initack_buf; - struct sctp_asconf_addr *aparam, *naparam; - struct sctp_asconf_ack *aack, *naack; - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_stream_reset_list *strrst, *nstrrst; - struct sctp_queued_to_read *sq, *nsq; - struct sctp_nets *net; - struct mbuf *op_err; - int init_offset, initack_offset, i; - int retval; - int spec_flag = 0; - uint32_t how_indx; -#if defined(SCTP_DETAILED_STR_STATS) - int j; -#endif - - net = *netp; - /* I know that the TCB is non-NULL from the caller */ - asoc = &stcb->asoc; - for (how_indx = 0; how_indx < sizeof(asoc->cookie_how); how_indx++) { - if (asoc->cookie_how[how_indx] == 0) - break; - } - if (how_indx < sizeof(asoc->cookie_how)) { - asoc->cookie_how[how_indx] = 1; - } - if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) { - /* SHUTDOWN came in after sending INIT-ACK */ - sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination); - op_err = sctp_generate_cause(SCTP_CAUSE_COOKIE_IN_SHUTDOWN, ""); - sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, net->port); - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 2; - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - /* - * find and validate the INIT chunk in the cookie (peer's info) the - * INIT should start after the cookie-echo header struct (chunk - * header, state cookie header struct) - */ - init_offset = offset += sizeof(struct sctp_cookie_echo_chunk); - - init_cp = (struct sctp_init_chunk *) - sctp_m_getptr(m, init_offset, sizeof(struct sctp_init_chunk), - (uint8_t *) & init_buf); - if (init_cp == NULL) { - /* could not pull a INIT chunk in cookie */ - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - if (init_cp->ch.chunk_type != SCTP_INITIATION) { - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - /* - * find and validate the INIT-ACK chunk in the cookie (my info) the - * INIT-ACK follows the INIT chunk - */ - initack_offset = init_offset + SCTP_SIZE32(ntohs(init_cp->ch.chunk_length)); - initack_cp = (struct sctp_init_ack_chunk *) - sctp_m_getptr(m, initack_offset, sizeof(struct sctp_init_ack_chunk), - (uint8_t *) & initack_buf); - if (initack_cp == NULL) { - /* could not pull INIT-ACK chunk in cookie */ - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - if (initack_cp->ch.chunk_type != SCTP_INITIATION_ACK) { - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && - (ntohl(init_cp->init.initiate_tag) == asoc->peer_vtag)) { - /* - * case D in Section 5.2.4 Table 2: MMAA process accordingly - * to get into the OPEN state - */ - if (ntohl(initack_cp->init.initial_tsn) != asoc->init_seq_number) { - /*- - * Opps, this means that we somehow generated two vtag's - * the same. I.e. we did: - * Us Peer - * <---INIT(tag=a)------ - * ----INIT-ACK(tag=t)--> - * ----INIT(tag=t)------> *1 - * <---INIT-ACK(tag=a)--- - * <----CE(tag=t)------------- *2 - * - * At point *1 we should be generating a different - * tag t'. Which means we would throw away the CE and send - * ours instead. Basically this is case C (throw away side). - */ - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 17; - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - switch (SCTP_GET_STATE(stcb)) { - case SCTP_STATE_COOKIE_WAIT: - case SCTP_STATE_COOKIE_ECHOED: - /* - * INIT was sent but got a COOKIE_ECHO with the - * correct tags... just accept it...but we must - * process the init so that we can make sure we - * have the right seq no's. - */ - /* First we must process the INIT !! */ - if (sctp_process_init(init_cp, stcb) < 0) { - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 3; - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - return (NULL); - } - /* we have already processed the INIT so no problem */ - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, - stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_13); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, - stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_14); - /* update current state */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) - SCTP_STAT_INCR_COUNTER32(sctps_activeestab); - else - SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); - - SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - SCTP_STAT_INCR_GAUGE32(sctps_currestab); - sctp_stop_all_cookie_timers(stcb); - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && - (!SCTP_IS_LISTENING(inp))) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - /* - * Here is where collision would go if we - * did a connect() and instead got a - * init/init-ack/cookie done before the - * init-ack came back.. - */ - sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_CONNECTED); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_UNLOCK(so, 1); - return (NULL); - } -#endif - soisconnected(stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - /* notify upper layer */ - *notification = SCTP_NOTIFY_ASSOC_UP; - net->hb_responded = 1; - if (stcb->asoc.sctp_autoclose_ticks && - (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))) { - sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, - inp, stcb, NULL); - } - break; - default: - /* - * we're in the OPEN state (or beyond), so - * peer must have simply lost the COOKIE-ACK - */ - break; - } /* end switch */ - sctp_stop_all_cookie_timers(stcb); - if ((retval = sctp_load_addresses_from_init(stcb, m, - init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) { - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 4; - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Problem with address parameters"); - SCTPDBG(SCTP_DEBUG_INPUT1, - "Load addresses from INIT causes an abort %d\n", - retval); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - return (NULL); - } - /* respond with a COOKIE-ACK */ - sctp_toss_old_cookies(stcb, asoc); - sctp_send_cookie_ack(stcb); - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 5; - return (stcb); - } - - if (ntohl(initack_cp->init.initiate_tag) != asoc->my_vtag && - ntohl(init_cp->init.initiate_tag) == asoc->peer_vtag && - cookie->tie_tag_my_vtag == 0 && - cookie->tie_tag_peer_vtag == 0) { - /* - * case C in Section 5.2.4 Table 2: XMOO silently discard - */ - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 6; - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - /* If nat support, and the below and stcb is established, - * send back a ABORT(colliding state) if we are established. - */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) && - (asoc->peer_supports_nat) && - ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && - ((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) || - (asoc->peer_vtag == 0)))) { - /* Special case - Peer's support nat. We may have - * two init's that we gave out the same tag on since - * one was not established.. i.e. we get INIT from host-1 - * behind the nat and we respond tag-a, we get a INIT from - * host-2 behind the nat and we get tag-a again. Then we - * bring up host-1 (or 2's) assoc, Then comes the cookie - * from hsot-2 (or 1). Now we have colliding state. We must - * send an abort here with colliding state indication. - */ - op_err = sctp_generate_cause(SCTP_CAUSE_NAT_COLLIDING_STATE, ""); - sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && - ((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) || - (asoc->peer_vtag == 0))) { - /* - * case B in Section 5.2.4 Table 2: MXAA or MOAA my info - * should be ok, re-accept peer info - */ - if (ntohl(initack_cp->init.initial_tsn) != asoc->init_seq_number) { - /* Extension of case C. - * If we hit this, then the random number - * generator returned the same vtag when we - * first sent our INIT-ACK and when we later sent - * our INIT. The side with the seq numbers that are - * different will be the one that normally would - * have hit case C. This in effect "extends" our vtags - * in this collision case to be 64 bits. The same collision - * could occur aka you get both vtag and seq number the - * same twice in a row.. but is much less likely. If it - * did happen then we would proceed through and bring - * up the assoc.. we may end up with the wrong stream - * setup however.. which would be bad.. but there is - * no way to tell.. until we send on a stream that does - * not exist :-) - */ - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 7; - - SCTP_TCB_UNLOCK(stcb); - return (NULL); - } - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 8; - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_15); - sctp_stop_all_cookie_timers(stcb); - /* - * since we did not send a HB make sure we don't double - * things - */ - net->hb_responded = 1; - if (stcb->asoc.sctp_autoclose_ticks && - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { - sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, - NULL); - } - asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); - if (asoc->pre_open_streams < asoc->streamoutcnt) { - asoc->pre_open_streams = asoc->streamoutcnt; - } - - if (ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) { - /* Ok the peer probably discarded our - * data (if we echoed a cookie+data). So anything - * on the sent_queue should be marked for - * retransmit, we may not get something to - * kick us so it COULD still take a timeout - * to move these.. but it can't hurt to mark them. - */ - - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->sent < SCTP_DATAGRAM_RESEND) { - chk->sent = SCTP_DATAGRAM_RESEND; - sctp_flight_size_decrease(chk); - sctp_total_flight_decrease(stcb, chk); - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - spec_flag++; - } - } - } - /* process the INIT info (peer's info) */ - if (sctp_process_init(init_cp, stcb) < 0) { - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 9; - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - return (NULL); - } - if ((retval = sctp_load_addresses_from_init(stcb, m, - init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) { - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 10; - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Problem with address parameters"); - SCTPDBG(SCTP_DEBUG_INPUT1, - "Load addresses from INIT causes an abort %d\n", - retval); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - return (NULL); - } - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - *notification = SCTP_NOTIFY_ASSOC_UP; - - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && - (!SCTP_IS_LISTENING(inp))) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_CONNECTED); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_UNLOCK(so, 1); - return (NULL); - } -#endif - soisconnected(stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) - SCTP_STAT_INCR_COUNTER32(sctps_activeestab); - else - SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); - SCTP_STAT_INCR_GAUGE32(sctps_currestab); - } else if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - SCTP_STAT_INCR_COUNTER32(sctps_restartestab); - } else { - SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - sctp_stop_all_cookie_timers(stcb); - sctp_toss_old_cookies(stcb, asoc); - sctp_send_cookie_ack(stcb); - if (spec_flag) { - /* only if we have retrans set do we do this. What - * this call does is get only the COOKIE-ACK out - * and then when we return the normal call to - * sctp_chunk_output will get the retrans out - * behind this. - */ - sctp_chunk_output(inp,stcb, SCTP_OUTPUT_FROM_COOKIE_ACK, SCTP_SO_NOT_LOCKED); - } - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 11; - - return (stcb); - } - if ((ntohl(initack_cp->init.initiate_tag) != asoc->my_vtag && - ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) && - cookie->tie_tag_my_vtag == asoc->my_vtag_nonce && - cookie->tie_tag_peer_vtag == asoc->peer_vtag_nonce && - cookie->tie_tag_peer_vtag != 0) { - struct sctpasochead *head; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - - if (asoc->peer_supports_nat) { - struct sctp_tcb *local_stcb; - - /* This is a gross gross hack. - * Just call the cookie_new code since we - * are allowing a duplicate association. - * I hope this works... - */ - local_stcb = sctp_process_cookie_new(m, iphlen, offset, src, dst, - sh, cookie, cookie_len, - inp, netp, init_src,notification, - auth_skipped, auth_offset, auth_len, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - if (local_stcb == NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return (local_stcb); - } - /* - * case A in Section 5.2.4 Table 2: XXMM (peer restarted) - */ - /* temp code */ - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 12; - sctp_stop_association_timers(stcb, false); - /* notify upper layer */ - *notification = SCTP_NOTIFY_ASSOC_RESTART; - atomic_add_int(&stcb->asoc.refcnt, 1); - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT)) { - SCTP_STAT_INCR_GAUGE32(sctps_currestab); - } - if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - SCTP_STAT_INCR_GAUGE32(sctps_restartestab); - } else if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) { - SCTP_STAT_INCR_GAUGE32(sctps_collisionestab); - } - if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { - SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - - } else if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) { - /* move to OPEN state, if not in SHUTDOWN_SENT */ - SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - } - if (asoc->pre_open_streams < asoc->streamoutcnt) { - asoc->pre_open_streams = asoc->streamoutcnt; - } - asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn); - asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number; - asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; - asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1; - asoc->str_reset_seq_in = asoc->init_seq_number; - asoc->advanced_peer_ack_point = asoc->last_acked_seq; - asoc->send_sack = 1; - asoc->data_pkts_seen = 0; - asoc->last_data_chunk_from = NULL; - asoc->last_control_chunk_from = NULL; - asoc->last_net_cmt_send_started = NULL; - if (asoc->mapping_array) { - memset(asoc->mapping_array, 0, - asoc->mapping_array_size); - } - if (asoc->nr_mapping_array) { - memset(asoc->nr_mapping_array, 0, - asoc->mapping_array_size); - } - SCTP_TCB_UNLOCK(stcb); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - SCTP_SOCKET_LOCK(so, 1); -#endif - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(stcb->sctp_ep); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - /* send up all the data */ - sctp_report_all_outbound(stcb, 0, SCTP_SO_LOCKED); - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - stcb->asoc.strmout[i].chunks_on_queues = 0; -#if defined(SCTP_DETAILED_STR_STATS) - for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { - asoc->strmout[i].abandoned_sent[j] = 0; - asoc->strmout[i].abandoned_unsent[j] = 0; - } -#else - asoc->strmout[i].abandoned_sent[0] = 0; - asoc->strmout[i].abandoned_unsent[0] = 0; -#endif - stcb->asoc.strmout[i].next_mid_ordered = 0; - stcb->asoc.strmout[i].next_mid_unordered = 0; - stcb->asoc.strmout[i].sid = i; - stcb->asoc.strmout[i].last_msg_incomplete = 0; - } - TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) { - TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp); - SCTP_FREE(strrst, SCTP_M_STRESET); - } - TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) { - TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next); - if (sq->data) { - sctp_m_freem(sq->data); - sq->data = NULL; - } - sctp_free_remote_addr(sq->whoFrom); - sq->whoFrom = NULL; - sq->stcb = NULL; - sctp_free_a_readq(stcb, sq); - } - TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - } - asoc->ctrl_queue_cnt = 0; - asoc->str_reset = NULL; - asoc->stream_reset_outstanding = 0; - TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - } - TAILQ_FOREACH_SAFE(aparam, &asoc->asconf_queue, next, naparam) { - TAILQ_REMOVE(&asoc->asconf_queue, aparam, next); - SCTP_FREE(aparam,SCTP_M_ASC_ADDR); - } - TAILQ_FOREACH_SAFE(aack, &asoc->asconf_ack_sent, next, naack) { - TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next); - if (aack->data != NULL) { - sctp_m_freem(aack->data); - } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), aack); - } - asoc->rcv_edmid = cookie->rcv_edmid; - - /* process the INIT-ACK info (my info) */ - asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); - asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); - - /* pull from vtag hash */ - LIST_REMOVE(stcb, sctp_asocs); - /* re-insert to new vtag position */ - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, - SCTP_BASE_INFO(hashasocmark))]; - /* - * put it in the bucket in the vtag hash of assoc's for the - * system - */ - LIST_INSERT_HEAD(head, stcb, sctp_asocs); - - SCTP_INP_WUNLOCK(stcb->sctp_ep); - SCTP_INP_INFO_WUNLOCK(); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - asoc->total_flight = 0; - asoc->total_flight_count = 0; - /* process the INIT info (peer's info) */ - if (sctp_process_init(init_cp, stcb) < 0) { - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 13; - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n"); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - return (NULL); - } - /* - * since we did not send a HB make sure we don't double - * things - */ - net->hb_responded = 1; - - if ((retval = sctp_load_addresses_from_init(stcb, m, - init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) { - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 14; - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Problem with address parameters"); - SCTPDBG(SCTP_DEBUG_INPUT1, - "Load addresses from INIT causes an abort %d\n", - retval); - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, net->port); - return (NULL); - } - /* respond with a COOKIE-ACK */ - sctp_send_cookie_ack(stcb); - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 15; - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE) && - (asoc->sctp_autoclose_ticks > 0)) { - sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); - } - return (stcb); - } - if (how_indx < sizeof(asoc->cookie_how)) - asoc->cookie_how[how_indx] = 16; - /* all other cases... */ - SCTP_TCB_UNLOCK(stcb); - return (NULL); -} - -/* - * handle a state cookie for a new association m: input packet mbuf chain-- - * assumes a pullup on IP/SCTP/COOKIE-ECHO chunk note: this is a "split" mbuf - * and the cookie signature does not exist offset: offset into mbuf to the - * cookie-echo chunk length: length of the cookie chunk to: where the init - * was from returns a new TCB - */ -static struct sctp_tcb * -sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len, - struct sctp_inpcb *inp, struct sctp_nets **netp, - struct sockaddr *init_src, int *notification, - int auth_skipped, uint32_t auth_offset, uint32_t auth_len, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_tcb *stcb; - struct sctp_init_chunk *init_cp, init_buf; - struct sctp_init_ack_chunk *initack_cp, initack_buf; - union sctp_sockstore store; - struct sctp_association *asoc; - int init_offset, initack_offset, initack_limit; - int error = 0; - uint8_t auth_chunk_buf[SCTP_CHUNK_BUFFER_SIZE]; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(inp); -#endif - - /* - * find and validate the INIT chunk in the cookie (peer's info) the - * INIT should start after the cookie-echo header struct (chunk - * header, state cookie header struct) - */ - init_offset = offset + sizeof(struct sctp_cookie_echo_chunk); - init_cp = (struct sctp_init_chunk *) - sctp_m_getptr(m, init_offset, sizeof(struct sctp_init_chunk), - (uint8_t *) & init_buf); - if (init_cp == NULL) { - /* could not pull a INIT chunk in cookie */ - SCTPDBG(SCTP_DEBUG_INPUT1, - "process_cookie_new: could not pull INIT chunk hdr\n"); - return (NULL); - } - if (init_cp->ch.chunk_type != SCTP_INITIATION) { - SCTPDBG(SCTP_DEBUG_INPUT1, "HUH? process_cookie_new: could not find INIT chunk!\n"); - return (NULL); - } - initack_offset = init_offset + SCTP_SIZE32(ntohs(init_cp->ch.chunk_length)); - /* - * find and validate the INIT-ACK chunk in the cookie (my info) the - * INIT-ACK follows the INIT chunk - */ - initack_cp = (struct sctp_init_ack_chunk *) - sctp_m_getptr(m, initack_offset, sizeof(struct sctp_init_ack_chunk), - (uint8_t *) & initack_buf); - if (initack_cp == NULL) { - /* could not pull INIT-ACK chunk in cookie */ - SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: could not pull INIT-ACK chunk hdr\n"); - return (NULL); - } - if (initack_cp->ch.chunk_type != SCTP_INITIATION_ACK) { - return (NULL); - } - /* - * NOTE: We can't use the INIT_ACK's chk_length to determine the - * "initack_limit" value. This is because the chk_length field - * includes the length of the cookie, but the cookie is omitted when - * the INIT and INIT_ACK are tacked onto the cookie... - */ - initack_limit = offset + cookie_len; - - /* - * now that we know the INIT/INIT-ACK are in place, create a new TCB - * and populate - */ - - /* - * Here we do a trick, we set in NULL for the proc/thread argument. We - * do this since in effect we only use the p argument when - * the socket is unbound and we must do an implicit bind. - * Since we are getting a cookie, we cannot be unbound. - */ - stcb = sctp_aloc_assoc(inp, init_src, &error, - ntohl(initack_cp->init.initiate_tag), - ntohl(initack_cp->init.initial_tsn), vrf_id, - ntohs(initack_cp->init.num_outbound_streams), - port, -#if defined(__FreeBSD__) && !defined(__Userspace__) - (struct thread *)NULL, -#elif defined(_WIN32) && !defined(__Userspace__) - (PKTHREAD)NULL, -#else - (struct proc *)NULL, -#endif - SCTP_DONT_INITIALIZE_AUTH_PARAMS); - if (stcb == NULL) { - struct mbuf *op_err; - - /* memory problem? */ - SCTPDBG(SCTP_DEBUG_INPUT1, - "process_cookie_new: no room for another TCB!\n"); - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - return (NULL); - } - asoc = &stcb->asoc; - /* get scope variables out of cookie */ - asoc->scope.ipv4_local_scope = cookie->ipv4_scope; - asoc->scope.site_scope = cookie->site_scope; - asoc->scope.local_scope = cookie->local_scope; - asoc->scope.loopback_scope = cookie->loopback_scope; - -#if defined(__Userspace__) - if ((asoc->scope.ipv4_addr_legal != cookie->ipv4_addr_legal) || - (asoc->scope.ipv6_addr_legal != cookie->ipv6_addr_legal) || - (asoc->scope.conn_addr_legal != cookie->conn_addr_legal)) { -#else - if ((asoc->scope.ipv4_addr_legal != cookie->ipv4_addr_legal) || - (asoc->scope.ipv6_addr_legal != cookie->ipv6_addr_legal)) { -#endif - struct mbuf *op_err; - - /* - * Houston we have a problem. The EP changed while the - * cookie was in flight. Only recourse is to abort the - * association. - */ - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_18); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (NULL); - } - asoc->rcv_edmid = cookie->rcv_edmid; - /* process the INIT-ACK info (my info) */ - asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); - - /* process the INIT info (peer's info) */ - if (sctp_process_init(init_cp, stcb) < 0) { -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_19); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (NULL); - } - /* load all addresses */ - if (sctp_load_addresses_from_init(stcb, m, - init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src, port) < 0) { -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_20); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (NULL); - } - /* - * verify any preceding AUTH chunk that was skipped - */ - /* pull the local authentication parameters from the cookie/init-ack */ - sctp_auth_get_cookie_params(stcb, m, - initack_offset + sizeof(struct sctp_init_ack_chunk), - initack_limit - (initack_offset + sizeof(struct sctp_init_ack_chunk))); - if (auth_skipped) { - struct sctp_auth_chunk *auth; - - if (auth_len <= SCTP_CHUNK_BUFFER_SIZE) { - auth = (struct sctp_auth_chunk *)sctp_m_getptr(m, auth_offset, auth_len, auth_chunk_buf); - } else { - auth = NULL; - } - if ((auth == NULL) || sctp_handle_auth(stcb, auth, m, auth_offset)) { - /* auth HMAC failed, dump the assoc and packet */ - SCTPDBG(SCTP_DEBUG_AUTH1, - "COOKIE-ECHO: AUTH failed\n"); -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_21); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (NULL); - } else { - /* remaining chunks checked... good to go */ - stcb->asoc.authenticated = 1; - } - } - - /* - * if we're doing ASCONFs, check to see if we have any new local - * addresses that need to get added to the peer (eg. addresses - * changed while cookie echo in flight). This needs to be done - * after we go to the OPEN state to do the correct asconf - * processing. else, make sure we have the correct addresses in our - * lists - */ - - /* warning, we re-use sin, sin6, sa_store here! */ - /* pull in local_address (our "from" address) */ - switch (cookie->laddr_type) { -#ifdef INET - case SCTP_IPV4_ADDRESS: - /* source addr is IPv4 */ - memset(&store.sin, 0, sizeof(struct sockaddr_in)); - store.sin.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - store.sin.sin_len = sizeof(struct sockaddr_in); -#endif - store.sin.sin_addr.s_addr = cookie->laddress[0]; - break; -#endif -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - /* source addr is IPv6 */ - memset(&store.sin6, 0, sizeof(struct sockaddr_in6)); - store.sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - store.sin6.sin6_len = sizeof(struct sockaddr_in6); -#endif - store.sin6.sin6_scope_id = cookie->scope_id; - memcpy(&store.sin6.sin6_addr, cookie->laddress, sizeof(struct in6_addr)); - break; -#endif -#if defined(__Userspace__) - case SCTP_CONN_ADDRESS: - /* source addr is conn */ - memset(&store.sconn, 0, sizeof(struct sockaddr_conn)); - store.sconn.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - store.sconn.sconn_len = sizeof(struct sockaddr_conn); -#endif - memcpy(&store.sconn.sconn_addr, cookie->laddress, sizeof(void *)); - break; -#endif - default: -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_22); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (NULL); - } - - /* update current state */ - SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); - SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - sctp_stop_all_cookie_timers(stcb); - SCTP_STAT_INCR_COUNTER32(sctps_passiveestab); - SCTP_STAT_INCR_GAUGE32(sctps_currestab); - - /* set up to notify upper layer */ - *notification = SCTP_NOTIFY_ASSOC_UP; - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && - (!SCTP_IS_LISTENING(inp))) { - /* - * This is an endpoint that called connect() how it got a - * cookie that is NEW is a bit of a mystery. It must be that - * the INIT was sent, but before it got there.. a complete - * INIT/INIT-ACK/COOKIE arrived. But of course then it - * should have went to the other code.. not here.. oh well.. - * a bit of protection is worth having.. - * - * XXXMJ unlocked - */ - sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_CONNECTED); -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - SCTP_SOCKET_UNLOCK(so, 1); - return (NULL); - } -#endif - soisconnected(stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } else if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (SCTP_IS_LISTENING(inp))) { - /* - * We don't want to do anything with this one. Since it is - * the listening guy. The timer will get started for - * accepted connections in the caller. - */ - ; - } - if (stcb->asoc.sctp_autoclose_ticks && - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { - sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); - } - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - *netp = sctp_findnet(stcb, init_src); - if (*netp != NULL) { - /* - * Since we did not send a HB, make sure we don't double - * things. - */ - (*netp)->hb_responded = 1; - } - /* respond with a COOKIE-ACK */ - sctp_send_cookie_ack(stcb); - - /* - * check the address lists for any ASCONFs that need to be sent - * AFTER the cookie-ack is sent - */ - sctp_check_address_list(stcb, m, - initack_offset + sizeof(struct sctp_init_ack_chunk), - initack_limit - (initack_offset + sizeof(struct sctp_init_ack_chunk)), - &store.sa, cookie->local_scope, cookie->site_scope, - cookie->ipv4_scope, cookie->loopback_scope); - - return (stcb); -} - -/* - * CODE LIKE THIS NEEDS TO RUN IF the peer supports the NAT extension, i.e - * we NEED to make sure we are not already using the vtag. If so we - * need to send back an ABORT-TRY-AGAIN-WITH-NEW-TAG No middle box bit! - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, - SCTP_BASE_INFO(hashasocmark))]; - LIST_FOREACH(stcb, head, sctp_asocs) { - if ((stcb->asoc.my_vtag == tag) && (stcb->rport == rport) && (inp == stcb->sctp_ep)) { - -- SEND ABORT - TRY AGAIN -- - } - } -*/ - -/* - * handles a COOKIE-ECHO message stcb: modified to either a new or left as - * existing (non-NULL) TCB - */ -static struct mbuf * -sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp, - struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp, - int auth_skipped, uint32_t auth_offset, uint32_t auth_len, - struct sctp_tcb **locked_tcb, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_state_cookie *cookie; - struct sctp_tcb *l_stcb = *stcb; - struct sctp_inpcb *l_inp; - struct sockaddr *to; - struct sctp_pcb *ep; - struct mbuf *m_sig; - uint8_t calc_sig[SCTP_SIGNATURE_SIZE], tmp_sig[SCTP_SIGNATURE_SIZE]; - uint8_t *sig; -#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) - uint8_t cookie_ok = 1; -#else - uint8_t cookie_ok = 0; -#endif - unsigned int sig_offset, cookie_offset; - unsigned int cookie_len; - struct timeval now; - struct timeval time_entered, time_expires; - int notification = 0; - struct sctp_nets *netl; - int had_a_existing_tcb = 0; - int send_int_conf = 0; -#ifdef INET - struct sockaddr_in sin; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif -#if defined(__Userspace__) - struct sockaddr_conn sconn; -#endif - - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_cookie: handling COOKIE-ECHO\n"); - - if (inp_p == NULL) { - return (NULL); - } - cookie = &cp->cookie; - cookie_offset = offset + sizeof(struct sctp_chunkhdr); - cookie_len = ntohs(cp->ch.chunk_length); - - if (cookie_len < sizeof(struct sctp_cookie_echo_chunk) + - sizeof(struct sctp_init_chunk) + - sizeof(struct sctp_init_ack_chunk) + SCTP_SIGNATURE_SIZE) { - /* cookie too small */ - return (NULL); - } - if ((cookie->peerport != sh->src_port) || - (cookie->myport != sh->dest_port) || - (cookie->my_vtag != sh->v_tag)) { - /* - * invalid ports or bad tag. Note that we always leave the - * v_tag in the header in network order and when we stored - * it in the my_vtag slot we also left it in network order. - * This maintains the match even though it may be in the - * opposite byte order of the machine :-> - */ - return (NULL); - } -#if defined(__Userspace__) - /* - * Recover the AF_CONN addresses within the cookie. - * This needs to be done in the buffer provided for later processing - * of the cookie and in the mbuf chain for HMAC validation. - */ - if ((cookie->addr_type == SCTP_CONN_ADDRESS) && (src->sa_family == AF_CONN)) { - struct sockaddr_conn *sconnp = (struct sockaddr_conn *)src; - - memcpy(cookie->address, &sconnp->sconn_addr , sizeof(void *)); - m_copyback(m, cookie_offset + offsetof(struct sctp_state_cookie, address), - (int)sizeof(void *), (caddr_t)&sconnp->sconn_addr); - } - if ((cookie->laddr_type == SCTP_CONN_ADDRESS) && (dst->sa_family == AF_CONN)) { - struct sockaddr_conn *sconnp = (struct sockaddr_conn *)dst; - - memcpy(cookie->laddress, &sconnp->sconn_addr , sizeof(void *)); - m_copyback(m, cookie_offset + offsetof(struct sctp_state_cookie, laddress), - (int)sizeof(void *), (caddr_t)&sconnp->sconn_addr); - } -#endif - /* - * split off the signature into its own mbuf (since it should not be - * calculated in the sctp_hmac_m() call). - */ - sig_offset = offset + cookie_len - SCTP_SIGNATURE_SIZE; - m_sig = m_split(m, sig_offset, M_NOWAIT); - if (m_sig == NULL) { - /* out of memory or ?? */ - return (NULL); - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(m_sig, SCTP_MBUF_SPLIT); - } -#endif - - /* - * compute the signature/digest for the cookie - */ - if (l_stcb != NULL) { - atomic_add_int(&l_stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(l_stcb); - } - l_inp = *inp_p; - SCTP_INP_RLOCK(l_inp); - if (l_stcb != NULL) { - SCTP_TCB_LOCK(l_stcb); - atomic_subtract_int(&l_stcb->asoc.refcnt, 1); - } - if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - SCTP_INP_RUNLOCK(l_inp); - sctp_m_freem(m_sig); - return (NULL); - } - ep = &(*inp_p)->sctp_ep; - /* which cookie is it? */ - if ((cookie->time_entered.tv_sec < (long)ep->time_of_secret_change) && - (ep->current_secret_number != ep->last_secret_number)) { - /* it's the old cookie */ - (void)sctp_hmac_m(SCTP_HMAC, - (uint8_t *)ep->secret_key[(int)ep->last_secret_number], - SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0); - } else { - /* it's the current cookie */ - (void)sctp_hmac_m(SCTP_HMAC, - (uint8_t *)ep->secret_key[(int)ep->current_secret_number], - SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0); - } - /* get the signature */ - SCTP_INP_RUNLOCK(l_inp); - sig = (uint8_t *) sctp_m_getptr(m_sig, 0, SCTP_SIGNATURE_SIZE, (uint8_t *) & tmp_sig); - if (sig == NULL) { - /* couldn't find signature */ - sctp_m_freem(m_sig); - return (NULL); - } - /* compare the received digest with the computed digest */ - if (timingsafe_bcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) != 0) { - /* try the old cookie? */ - if ((cookie->time_entered.tv_sec == (long)ep->time_of_secret_change) && - (ep->current_secret_number != ep->last_secret_number)) { - /* compute digest with old */ - (void)sctp_hmac_m(SCTP_HMAC, - (uint8_t *)ep->secret_key[(int)ep->last_secret_number], - SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0); - /* compare */ - if (timingsafe_bcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) == 0) - cookie_ok = 1; - } - } else { - cookie_ok = 1; - } - - /* - * Now before we continue we must reconstruct our mbuf so that - * normal processing of any other chunks will work. - */ - { - struct mbuf *m_at; - - m_at = m; - while (SCTP_BUF_NEXT(m_at) != NULL) { - m_at = SCTP_BUF_NEXT(m_at); - } - SCTP_BUF_NEXT(m_at) = m_sig; - } - - if (cookie_ok == 0) { - SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: cookie signature validation failed!\n"); - SCTPDBG(SCTP_DEBUG_INPUT2, - "offset = %u, cookie_offset = %u, sig_offset = %u\n", - (uint32_t) offset, cookie_offset, sig_offset); - return (NULL); - } - - if (sctp_ticks_to_msecs(cookie->cookie_life) > SCTP_MAX_COOKIE_LIFE) { - SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: Invalid cookie lifetime\n"); - return (NULL); - } - time_entered.tv_sec = cookie->time_entered.tv_sec; - time_entered.tv_usec = cookie->time_entered.tv_usec; - if ((time_entered.tv_sec < 0) || - (time_entered.tv_usec < 0) || - (time_entered.tv_usec >= 1000000)) { - /* Invalid time stamp. Cookie must have been modified. */ - SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: Invalid time stamp\n"); - return (NULL); - } - (void)SCTP_GETTIME_TIMEVAL(&now); -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (timercmp(&now, &time_entered, <)) { -#else - if (timevalcmp(&now, &time_entered, <)) { -#endif - SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: cookie generated in the future!\n"); - return (NULL); - } - /* - * Check the cookie timestamps to be sure it's not stale. - * cookie_life is in ticks, so we convert to seconds. - */ - time_expires.tv_sec = time_entered.tv_sec + sctp_ticks_to_secs(cookie->cookie_life); - time_expires.tv_usec = time_entered.tv_usec; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (timercmp(&now, &time_expires, >)) -#else - if (timevalcmp(&now, &time_expires, >)) -#endif - { - /* cookie is stale! */ - struct mbuf *op_err; - struct sctp_error_stale_cookie *cause; - struct timeval diff; - uint32_t staleness; - - op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_stale_cookie), - 0, M_NOWAIT, 1, MT_DATA); - if (op_err == NULL) { - /* FOOBAR */ - return (NULL); - } - /* Set the len */ - SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_stale_cookie); - cause = mtod(op_err, struct sctp_error_stale_cookie *); - cause->cause.code = htons(SCTP_CAUSE_STALE_COOKIE); - cause->cause.length = htons(sizeof(struct sctp_error_stale_cookie)); -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - timersub(&now, &time_expires, &diff); -#else - diff = now; - timevalsub(&diff, &time_expires); -#endif - if ((uint32_t)diff.tv_sec > UINT32_MAX / 1000000) { - staleness = UINT32_MAX; - } else { - staleness = (uint32_t)diff.tv_sec * 1000000; - } - if (UINT32_MAX - staleness >= (uint32_t)diff.tv_usec) { - staleness += (uint32_t)diff.tv_usec; - } else { - staleness = UINT32_MAX; - } - cause->stale_time = htonl(staleness); - sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, l_inp->fibnum, -#endif - vrf_id, port); - return (NULL); - } - /* - * Now we must see with the lookup address if we have an existing - * asoc. This will only happen if we were in the COOKIE-WAIT state - * and a INIT collided with us and somewhere the peer sent the - * cookie on another address besides the single address our assoc - * had for him. In this case we will have one of the tie-tags set at - * least AND the address field in the cookie can be used to look it - * up. - */ - to = NULL; - switch (cookie->addr_type) { -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6.sin6_len = sizeof(sin6); -#endif - sin6.sin6_port = sh->src_port; - sin6.sin6_scope_id = cookie->scope_id; - memcpy(&sin6.sin6_addr.s6_addr, cookie->address, - sizeof(sin6.sin6_addr.s6_addr)); - to = (struct sockaddr *)&sin6; - break; -#endif -#ifdef INET - case SCTP_IPV4_ADDRESS: - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin.sin_len = sizeof(sin); -#endif - sin.sin_port = sh->src_port; - sin.sin_addr.s_addr = cookie->address[0]; - to = (struct sockaddr *)&sin; - break; -#endif -#if defined(__Userspace__) - case SCTP_CONN_ADDRESS: - memset(&sconn, 0, sizeof(struct sockaddr_conn)); - sconn.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - sconn.sconn_len = sizeof(struct sockaddr_conn); -#endif - sconn.sconn_port = sh->src_port; - memcpy(&sconn.sconn_addr, cookie->address, sizeof(void *)); - to = (struct sockaddr *)&sconn; - break; -#endif - default: - /* This should not happen */ - return (NULL); - } - if (*stcb == NULL) { - /* Yep, lets check */ - *stcb = sctp_findassociation_ep_addr(inp_p, to, netp, dst, NULL); - if (*stcb == NULL) { - /* - * We should have only got back the same inp. If we - * got back a different ep we have a problem. The - * original findep got back l_inp and now - */ - if (l_inp != *inp_p) { - SCTP_PRINTF("Bad problem find_ep got a diff inp then special_locate?\n"); - } - } else { - if (*locked_tcb == NULL) { - /* In this case we found the assoc only - * after we locked the create lock. This means - * we are in a colliding case and we must make - * sure that we unlock the tcb if its one of the - * cases where we throw away the incoming packets. - */ - *locked_tcb = *stcb; - - /* We must also increment the inp ref count - * since the ref_count flags was set when we - * did not find the TCB, now we found it which - * reduces the refcount.. we must raise it back - * out to balance it all :-) - */ - SCTP_INP_INCR_REF((*stcb)->sctp_ep); - if ((*stcb)->sctp_ep != l_inp) { - SCTP_PRINTF("Huh? ep:%p diff then l_inp:%p?\n", - (void *)(*stcb)->sctp_ep, (void *)l_inp); - } - } - } - } - - cookie_len -= SCTP_SIGNATURE_SIZE; - if (*stcb == NULL) { - /* this is the "normal" case... get a new TCB */ - *stcb = sctp_process_cookie_new(m, iphlen, offset, src, dst, sh, - cookie, cookie_len, *inp_p, - netp, to, ¬ification, - auth_skipped, auth_offset, auth_len, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - } else { - /* this is abnormal... cookie-echo on existing TCB */ - had_a_existing_tcb = 1; - *stcb = sctp_process_cookie_existing(m, iphlen, offset, - src, dst, sh, - cookie, cookie_len, *inp_p, *stcb, netp, to, - ¬ification, auth_skipped, auth_offset, auth_len, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - if (*stcb == NULL) { - *locked_tcb = NULL; - } - } - - if (*stcb == NULL) { - /* still no TCB... must be bad cookie-echo */ - return (NULL); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (*netp != NULL) { - (*netp)->flowtype = mflowtype; - (*netp)->flowid = mflowid; - } -#endif - /* - * Ok, we built an association so confirm the address we sent the - * INIT-ACK to. - */ - netl = sctp_findnet(*stcb, to); - /* - * This code should in theory NOT run but - */ - if (netl == NULL) { - /* TSNH! Huh, why do I need to add this address here? */ - if (sctp_add_remote_addr(*stcb, to, NULL, port, - SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC)) { - return (NULL); - } - netl = sctp_findnet(*stcb, to); - } - if (netl) { - if (netl->dest_state & SCTP_ADDR_UNCONFIRMED) { - netl->dest_state &= ~SCTP_ADDR_UNCONFIRMED; - (void)sctp_set_primary_addr((*stcb), (struct sockaddr *)NULL, - netl); - send_int_conf = 1; - } - } - sctp_start_net_timers(*stcb); - if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { - if (!had_a_existing_tcb || - (((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { - /* - * If we have a NEW cookie or the connect never - * reached the connected state during collision we - * must do the TCP accept thing. - */ - struct socket *so, *oso; - struct sctp_inpcb *inp; - - if (notification == SCTP_NOTIFY_ASSOC_RESTART) { - /* - * For a restart we will keep the same - * socket, no need to do anything. I THINK!! - */ - sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - if (send_int_conf) { - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, - (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED); - } - return (m); - } - oso = (*inp_p)->sctp_socket; - atomic_add_int(&(*stcb)->asoc.refcnt, 1); - SCTP_TCB_UNLOCK((*stcb)); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_SET(oso->so_vnet); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(oso, 1); -#endif - so = sonewconn(oso, 0 -#if defined(__APPLE__) && !defined(__Userspace__) - ,NULL -#endif - ); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(oso, 1); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_RESTORE(); -#endif - SCTP_TCB_LOCK((*stcb)); - atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); - - if (so == NULL) { - struct mbuf *op_err; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *pcb_so; -#endif - /* Too many sockets */ - SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: no room for another socket!\n"); - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_abort_association(*inp_p, NULL, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); -#if defined(__APPLE__) && !defined(__Userspace__) - pcb_so = SCTP_INP_SO(*inp_p); - atomic_add_int(&(*stcb)->asoc.refcnt, 1); - SCTP_TCB_UNLOCK((*stcb)); - SCTP_SOCKET_LOCK(pcb_so, 1); - SCTP_TCB_LOCK((*stcb)); - atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_23); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(pcb_so, 1); -#endif - return (NULL); - } - inp = (struct sctp_inpcb *)so->so_pcb; - SCTP_INP_INCR_REF(inp); - /* - * We add the unbound flag here so that - * if we get an soabort() before we get the - * move_pcb done, we will properly cleanup. - */ - inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE | - SCTP_PCB_FLAGS_CONNECTED | - SCTP_PCB_FLAGS_IN_TCPPOOL | - SCTP_PCB_FLAGS_UNBOUND | - (SCTP_PCB_COPY_FLAGS & (*inp_p)->sctp_flags) | - SCTP_PCB_FLAGS_DONT_WAKE); - inp->sctp_features = (*inp_p)->sctp_features; - inp->sctp_mobility_features = (*inp_p)->sctp_mobility_features; - inp->sctp_socket = so; - inp->sctp_frag_point = (*inp_p)->sctp_frag_point; - inp->max_cwnd = (*inp_p)->max_cwnd; - inp->sctp_cmt_on_off = (*inp_p)->sctp_cmt_on_off; - inp->ecn_supported = (*inp_p)->ecn_supported; - inp->prsctp_supported = (*inp_p)->prsctp_supported; - inp->auth_supported = (*inp_p)->auth_supported; - inp->asconf_supported = (*inp_p)->asconf_supported; - inp->reconfig_supported = (*inp_p)->reconfig_supported; - inp->nrsack_supported = (*inp_p)->nrsack_supported; - inp->pktdrop_supported = (*inp_p)->pktdrop_supported; - inp->partial_delivery_point = (*inp_p)->partial_delivery_point; - inp->sctp_context = (*inp_p)->sctp_context; - inp->local_strreset_support = (*inp_p)->local_strreset_support; - inp->fibnum = (*inp_p)->fibnum; -#if defined(__Userspace__) - inp->ulp_info = (*inp_p)->ulp_info; - inp->recv_callback = (*inp_p)->recv_callback; - inp->send_callback = (*inp_p)->send_callback; - inp->send_sb_threshold = (*inp_p)->send_sb_threshold; -#endif - /* - * copy in the authentication parameters from the - * original endpoint - */ - if (inp->sctp_ep.local_hmacs) - sctp_free_hmaclist(inp->sctp_ep.local_hmacs); - inp->sctp_ep.local_hmacs = - sctp_copy_hmaclist((*inp_p)->sctp_ep.local_hmacs); - if (inp->sctp_ep.local_auth_chunks) - sctp_free_chunklist(inp->sctp_ep.local_auth_chunks); - inp->sctp_ep.local_auth_chunks = - sctp_copy_chunklist((*inp_p)->sctp_ep.local_auth_chunks); - - /* - * Now we must move it from one hash table to - * another and get the tcb in the right place. - */ - - /* This is where the one-2-one socket is put into - * the accept state waiting for the accept! - */ - if (*stcb) { - SCTP_ADD_SUBSTATE(*stcb, SCTP_STATE_IN_ACCEPT_QUEUE); - } - sctp_move_pcb_and_assoc(*inp_p, inp, *stcb); - - atomic_add_int(&(*stcb)->asoc.refcnt, 1); - SCTP_TCB_UNLOCK((*stcb)); - -#if defined(__FreeBSD__) && !defined(__Userspace__) - sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, - 0); -#else - sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT); -#endif - SCTP_TCB_LOCK((*stcb)); - atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); - - /* now we must check to see if we were aborted while - * the move was going on and the lock/unlock happened. - */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* yep it was, we leave the - * assoc attached to the socket since - * the sctp_inpcb_free() call will send - * an abort for us. - */ - SCTP_INP_DECR_REF(inp); - return (NULL); - } - SCTP_INP_DECR_REF(inp); - /* Switch over to the new guy */ - *inp_p = inp; - sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - if (send_int_conf) { - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, - (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED); - } - - /* Pull it from the incomplete queue and wake the guy */ -#if defined(__APPLE__) && !defined(__Userspace__) - atomic_add_int(&(*stcb)->asoc.refcnt, 1); - SCTP_TCB_UNLOCK((*stcb)); - SCTP_SOCKET_LOCK(so, 1); -#endif - soisconnected(so); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_TCB_LOCK((*stcb)); - atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (m); - } - } - if (notification) { - sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - } - if (send_int_conf) { - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, - (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED); - } - return (m); -} - -static void -sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, - struct sctp_tcb *stcb, struct sctp_nets *net) -{ - /* cp must not be used, others call this without a c-ack :-) */ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_cookie_ack: handling COOKIE-ACK\n"); - if ((stcb == NULL) || (net == NULL)) { - return; - } - - asoc = &stcb->asoc; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - asoc->overall_error_count, - 0, - SCTP_FROM_SCTP_INPUT, - __LINE__); - } - sctp_stop_all_cookie_timers(stcb); - sctp_toss_old_cookies(stcb, asoc); - /* process according to association state */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) { - /* state change only needed when I am in right state */ - SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); - SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); - sctp_start_net_timers(stcb); - /* update RTO */ - SCTP_STAT_INCR_COUNTER32(sctps_activeestab); - SCTP_STAT_INCR_GAUGE32(sctps_currestab); - if (asoc->overall_error_count == 0) { - sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, - SCTP_RTT_FROM_NON_DATA); - } - /* - * Since we did not send a HB make sure we don't double - * things. - */ - asoc->overall_error_count = 0; - net->hb_responded = 1; - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_UP, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - -#endif - sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_CONNECTED); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - if ((stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) == 0) { - soisconnected(stcb->sctp_socket); - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - - if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && - TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->stream_queue_cnt == 0)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); - } - - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* We don't need to do the asconf thing, - * nor hb or autoclose if the socket is closed. - */ - goto closed_socket; - } - - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, - stcb, net); - - if (stcb->asoc.sctp_autoclose_ticks && - sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_AUTOCLOSE)) { - sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, - stcb->sctp_ep, stcb, NULL); - } - /* - * send ASCONF if parameters are pending and ASCONFs are - * allowed (eg. addresses changed when init/cookie echo were - * in flight) - */ - if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DO_ASCONF)) && - (stcb->asoc.asconf_supported == 1) && - (!TAILQ_EMPTY(&stcb->asoc.asconf_queue))) { -#ifdef SCTP_TIMER_BASED_ASCONF - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, - stcb->sctp_ep, stcb, - stcb->asoc.primary_destination); -#else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); -#endif - } - } -closed_socket: - /* Restart the timer if we have pending data */ - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - if (chk->whoTo != NULL) { - break; - } - } - if (chk != NULL) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo); - } -} - -static void -sctp_handle_ecn_echo(struct sctp_ecne_chunk *cp, - struct sctp_tcb *stcb) -{ - struct sctp_nets *net; - struct sctp_tmit_chunk *lchk; - struct sctp_ecne_chunk bkup; - uint8_t override_bit; - uint32_t tsn, window_data_tsn; - int len; - unsigned int pkt_cnt; - - len = ntohs(cp->ch.chunk_length); - if (len == sizeof(struct old_sctp_ecne_chunk)) { - /* Its the old format */ - memcpy(&bkup, cp, sizeof(struct old_sctp_ecne_chunk)); - bkup.num_pkts_since_cwr = htonl(1); - cp = &bkup; - } - SCTP_STAT_INCR(sctps_recvecne); - tsn = ntohl(cp->tsn); - pkt_cnt = ntohl(cp->num_pkts_since_cwr); - lchk = TAILQ_LAST(&stcb->asoc.send_queue, sctpchunk_listhead); - if (lchk == NULL) { - window_data_tsn = stcb->asoc.sending_seq - 1; - } else { - window_data_tsn = lchk->rec.data.tsn; - } - - /* Find where it was sent to if possible. */ - net = NULL; - TAILQ_FOREACH(lchk, &stcb->asoc.sent_queue, sctp_next) { - if (lchk->rec.data.tsn == tsn) { - net = lchk->whoTo; - net->ecn_prev_cwnd = lchk->rec.data.cwnd_at_send; - break; - } - if (SCTP_TSN_GT(lchk->rec.data.tsn, tsn)) { - break; - } - } - if (net == NULL) { - /* - * What to do. A previous send of a - * CWR was possibly lost. See how old it is, we - * may have it marked on the actual net. - */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (tsn == net->last_cwr_tsn) { - /* Found him, send it off */ - break; - } - } - if (net == NULL) { - /* - * If we reach here, we need to send a special - * CWR that says hey, we did this a long time - * ago and you lost the response. - */ - net = TAILQ_FIRST(&stcb->asoc.nets); - if (net == NULL) { - /* TSNH */ - return; - } - override_bit = SCTP_CWR_REDUCE_OVERRIDE; - } else { - override_bit = 0; - } - } else { - override_bit = 0; - } - if (SCTP_TSN_GT(tsn, net->cwr_window_tsn) && - ((override_bit&SCTP_CWR_REDUCE_OVERRIDE) == 0)) { - /* JRS - Use the congestion control given in the pluggable CC module */ - stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo(stcb, net, 0, pkt_cnt); - /* - * We reduce once every RTT. So we will only lower cwnd at - * the next sending seq i.e. the window_data_tsn - */ - net->cwr_window_tsn = window_data_tsn; - net->ecn_ce_pkt_cnt += pkt_cnt; - net->lost_cnt = pkt_cnt; - net->last_cwr_tsn = tsn; - } else { - override_bit |= SCTP_CWR_IN_SAME_WINDOW; - if (SCTP_TSN_GT(tsn, net->last_cwr_tsn) && - ((override_bit&SCTP_CWR_REDUCE_OVERRIDE) == 0)) { - /* - * Another loss in the same window update how - * many marks/packets lost we have had. - */ - int cnt = 1; - if (pkt_cnt > net->lost_cnt) { - /* Should be the case */ - cnt = (pkt_cnt - net->lost_cnt); - net->ecn_ce_pkt_cnt += cnt; - } - net->lost_cnt = pkt_cnt; - net->last_cwr_tsn = tsn; - /* - * Most CC functions will ignore this call, since we are in-window - * yet of the initial CE the peer saw. - */ - stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo(stcb, net, 1, cnt); - } - } - /* - * We always send a CWR this way if our previous one was lost our - * peer will get an update, or if it is not time again to reduce we - * still get the cwr to the peer. Note we set the override when we - * could not find the TSN on the chunk or the destination network. - */ - sctp_send_cwr(stcb, net, net->last_cwr_tsn, override_bit); -} - -static void -sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sctp_nets *net) -{ - /* - * Here we get a CWR from the peer. We must look in the outqueue and - * make sure that we have a covered ECNE in the control chunk part. - * If so remove it. - */ - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_ecne_chunk *ecne; - int override; - uint32_t cwr_tsn; - - cwr_tsn = ntohl(cp->tsn); - override = cp->ch.chunk_flags & SCTP_CWR_REDUCE_OVERRIDE; - TAILQ_FOREACH_SAFE(chk, &stcb->asoc.control_send_queue, sctp_next, nchk) { - if (chk->rec.chunk_id.id != SCTP_ECN_ECHO) { - continue; - } - if ((override == 0) && (chk->whoTo != net)) { - /* Must be from the right src unless override is set */ - continue; - } - ecne = mtod(chk->data, struct sctp_ecne_chunk *); - if (SCTP_TSN_GE(cwr_tsn, ntohl(ecne->tsn))) { - /* this covers this ECNE, we can remove it */ - stcb->asoc.ecn_echo_cnt_onq--; - TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, - sctp_next); - stcb->asoc.ctrl_queue_cnt--; - sctp_m_freem(chk->data); - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - if (override == 0) { - break; - } - } - } -} - -static void -sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSED, - struct sctp_tcb *stcb, struct sctp_nets *net) -{ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown_complete: handling SHUTDOWN-COMPLETE\n"); - if (stcb == NULL) - return; - - /* process according to association state */ - if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) { - /* unexpected SHUTDOWN-COMPLETE... so ignore... */ - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown_complete: not in SCTP_STATE_SHUTDOWN_ACK_SENT --- ignore\n"); - SCTP_TCB_UNLOCK(stcb); - return; - } - /* notify upper layer protocol */ - if (stcb->sctp_socket) { - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - } -#ifdef INVARIANTS - if (!TAILQ_EMPTY(&stcb->asoc.send_queue) || - !TAILQ_EMPTY(&stcb->asoc.sent_queue) || - sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) { - panic("Queues are not empty when handling SHUTDOWN-COMPLETE"); - } -#endif - /* stop the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_24); - SCTP_STAT_INCR_COUNTER32(sctps_shutdown); - /* free the TCB */ - SCTPDBG(SCTP_DEBUG_INPUT2, - "sctp_handle_shutdown_complete: calls free-asoc\n"); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_25); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return; -} - -static int -process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, - struct sctp_nets *net, uint8_t flg) -{ - switch (desc->chunk_type) { - case SCTP_DATA: - case SCTP_IDATA: - /* find the tsn to resend (possibly) */ - { - uint32_t tsn; - struct sctp_tmit_chunk *tp1; - - tsn = ntohl(desc->tsn_ifany); - TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) { - if (tp1->rec.data.tsn == tsn) { - /* found it */ - break; - } - if (SCTP_TSN_GT(tp1->rec.data.tsn, tsn)) { - /* not found */ - tp1 = NULL; - break; - } - } - if (tp1 == NULL) { - /* - * Do it the other way , aka without paying - * attention to queue seq order. - */ - SCTP_STAT_INCR(sctps_pdrpdnfnd); - TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) { - if (tp1->rec.data.tsn == tsn) { - /* found it */ - break; - } - } - } - if (tp1 == NULL) { - SCTP_STAT_INCR(sctps_pdrptsnnf); - } - if ((tp1) && (tp1->sent < SCTP_DATAGRAM_ACKED)) { - if (((flg & SCTP_BADCRC) == 0) && - ((flg & SCTP_FROM_MIDDLE_BOX) == 0)) { - return (0); - } - if ((stcb->asoc.peers_rwnd == 0) && - ((flg & SCTP_FROM_MIDDLE_BOX) == 0)) { - SCTP_STAT_INCR(sctps_pdrpdiwnp); - return (0); - } - if (stcb->asoc.peers_rwnd == 0 && - (flg & SCTP_FROM_MIDDLE_BOX)) { - SCTP_STAT_INCR(sctps_pdrpdizrw); - return (0); - } - if ((uint32_t)SCTP_BUF_LEN(tp1->data) < - SCTP_DATA_CHUNK_OVERHEAD(stcb) + SCTP_NUM_DB_TO_VERIFY) { - /* Payload not matching. */ - SCTP_STAT_INCR(sctps_pdrpbadd); - return (-1); - } - if (memcmp(mtod(tp1->data, caddr_t) + SCTP_DATA_CHUNK_OVERHEAD(stcb), - desc->data_bytes, SCTP_NUM_DB_TO_VERIFY) != 0) { - /* Payload not matching. */ - SCTP_STAT_INCR(sctps_pdrpbadd); - return (-1); - } - if (tp1->do_rtt) { - /* - * this guy had a RTO calculation - * pending on it, cancel it - */ - if (tp1->whoTo->rto_needed == 0) { - tp1->whoTo->rto_needed = 1; - } - tp1->do_rtt = 0; - } - SCTP_STAT_INCR(sctps_pdrpmark); - if (tp1->sent != SCTP_DATAGRAM_RESEND) - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - /* - * mark it as if we were doing a FR, since - * we will be getting gap ack reports behind - * the info from the router. - */ - tp1->rec.data.doing_fast_retransmit = 1; - /* - * mark the tsn with what sequences can - * cause a new FR. - */ - if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { - tp1->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; - } else { - tp1->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.tsn; - } - - /* restart the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, tp1->whoTo, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_26); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, tp1->whoTo); - - /* fix counts and things */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PDRP, - tp1->whoTo->flight_size, - tp1->book_size, - (uint32_t)(uintptr_t)stcb, - tp1->rec.data.tsn); - } - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - sctp_flight_size_decrease(tp1); - sctp_total_flight_decrease(stcb, tp1); - } - tp1->sent = SCTP_DATAGRAM_RESEND; - } { - /* audit code */ - unsigned int audit; - - audit = 0; - TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) { - if (tp1->sent == SCTP_DATAGRAM_RESEND) - audit++; - } - TAILQ_FOREACH(tp1, &stcb->asoc.control_send_queue, - sctp_next) { - if (tp1->sent == SCTP_DATAGRAM_RESEND) - audit++; - } - if (audit != stcb->asoc.sent_queue_retran_cnt) { - SCTP_PRINTF("**Local Audit finds cnt:%d asoc cnt:%d\n", - audit, stcb->asoc.sent_queue_retran_cnt); -#ifndef SCTP_AUDITING_ENABLED - stcb->asoc.sent_queue_retran_cnt = audit; -#endif - } - } - } - break; - case SCTP_ASCONF: - { - struct sctp_tmit_chunk *asconf; - - TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue, - sctp_next) { - if (asconf->rec.chunk_id.id == SCTP_ASCONF) { - break; - } - } - if (asconf) { - if (asconf->sent != SCTP_DATAGRAM_RESEND) - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - asconf->sent = SCTP_DATAGRAM_RESEND; - asconf->snd_count--; - } - } - break; - case SCTP_INITIATION: - /* resend the INIT */ - stcb->asoc.dropped_special_cnt++; - if (stcb->asoc.dropped_special_cnt < SCTP_RETRY_DROPPED_THRESH) { - /* - * If we can get it in, in a few attempts we do - * this, otherwise we let the timer fire. - */ - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, - stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); - sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - } - break; - case SCTP_SELECTIVE_ACK: - case SCTP_NR_SELECTIVE_ACK: - /* resend the sack */ - sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); - break; - case SCTP_HEARTBEAT_REQUEST: - /* resend a demand HB */ - if ((stcb->asoc.overall_error_count + 3) < stcb->asoc.max_send_times) { - /* Only retransmit if we KNOW we wont destroy the tcb */ - sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - } - break; - case SCTP_SHUTDOWN: - sctp_send_shutdown(stcb, net); - break; - case SCTP_SHUTDOWN_ACK: - sctp_send_shutdown_ack(stcb, net); - break; - case SCTP_COOKIE_ECHO: - { - struct sctp_tmit_chunk *cookie; - - cookie = NULL; - TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, - sctp_next) { - if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { - break; - } - } - if (cookie) { - if (cookie->sent != SCTP_DATAGRAM_RESEND) - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - cookie->sent = SCTP_DATAGRAM_RESEND; - sctp_stop_all_cookie_timers(stcb); - } - } - break; - case SCTP_COOKIE_ACK: - sctp_send_cookie_ack(stcb); - break; - case SCTP_ASCONF_ACK: - /* resend last asconf ack */ - sctp_send_asconf_ack(stcb); - break; - case SCTP_IFORWARD_CUM_TSN: - case SCTP_FORWARD_CUM_TSN: - send_forward_tsn(stcb, &stcb->asoc); - break; - /* can't do anything with these */ - case SCTP_PACKET_DROPPED: - case SCTP_INITIATION_ACK: /* this should not happen */ - case SCTP_HEARTBEAT_ACK: - case SCTP_ABORT_ASSOCIATION: - case SCTP_OPERATION_ERROR: - case SCTP_SHUTDOWN_COMPLETE: - case SCTP_ECN_ECHO: - case SCTP_ECN_CWR: - default: - break; - } - return (0); -} - -void -sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *list) -{ - uint32_t i; - uint16_t temp; - - /* - * We set things to 0xffffffff since this is the last delivered sequence - * and we will be sending in 0 after the reset. - */ - - if (number_entries) { - for (i = 0; i < number_entries; i++) { - temp = ntohs(list[i]); - if (temp >= stcb->asoc.streamincnt) { - continue; - } - stcb->asoc.strmin[temp].last_mid_delivered = 0xffffffff; - } - } else { - list = NULL; - for (i = 0; i < stcb->asoc.streamincnt; i++) { - stcb->asoc.strmin[i].last_mid_delivered = 0xffffffff; - } - } - sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED); -} - -static void -sctp_reset_out_streams(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *list) -{ - uint32_t i; - uint16_t temp; - - if (number_entries > 0) { - for (i = 0; i < number_entries; i++) { - temp = ntohs(list[i]); - if (temp >= stcb->asoc.streamoutcnt) { - /* no such stream */ - continue; - } - stcb->asoc.strmout[temp].next_mid_ordered = 0; - stcb->asoc.strmout[temp].next_mid_unordered = 0; - } - } else { - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - stcb->asoc.strmout[i].next_mid_ordered = 0; - stcb->asoc.strmout[i].next_mid_unordered = 0; - } - } - sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_SEND, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED); -} - -static void -sctp_reset_clear_pending(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *list) -{ - uint32_t i; - uint16_t temp; - - if (number_entries > 0) { - for (i = 0; i < number_entries; i++) { - temp = ntohs(list[i]); - if (temp >= stcb->asoc.streamoutcnt) { - /* no such stream */ - continue; - } - stcb->asoc.strmout[temp].state = SCTP_STREAM_OPEN; - } - } else { - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - stcb->asoc.strmout[i].state = SCTP_STREAM_OPEN; - } - } -} - -struct sctp_stream_reset_request * -sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chunk **bchk) -{ - struct sctp_association *asoc; - struct sctp_chunkhdr *ch; - struct sctp_stream_reset_request *r; - struct sctp_tmit_chunk *chk; - int len, clen; - - asoc = &stcb->asoc; - chk = asoc->str_reset; - if (TAILQ_EMPTY(&asoc->control_send_queue) || - (chk == NULL)) { - asoc->stream_reset_outstanding = 0; - return (NULL); - } - if (chk->data == NULL) { - return (NULL); - } - if (bchk != NULL) { - /* he wants a copy of the chk pointer */ - *bchk = chk; - } - clen = chk->send_size; - ch = mtod(chk->data, struct sctp_chunkhdr *); - r = (struct sctp_stream_reset_request *)(ch + 1); - if (ntohl(r->request_seq) == seq) { - /* found it */ - return (r); - } - len = SCTP_SIZE32(ntohs(r->ph.param_length)); - if (clen > (len + (int)sizeof(struct sctp_chunkhdr))) { - /* move to the next one, there can only be a max of two */ - r = (struct sctp_stream_reset_request *)((caddr_t)r + len); - if (ntohl(r->request_seq) == seq) { - return (r); - } - } - /* that seq is not here */ - return (NULL); -} - -static void -sctp_clean_up_stream_reset(struct sctp_tcb *stcb) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - - asoc = &stcb->asoc; - chk = asoc->str_reset; - if (chk == NULL) { - return; - } - asoc->str_reset = NULL; - sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, - NULL, SCTP_FROM_SCTP_INPUT + SCTP_LOC_28); - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt--; - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); -} - -static int -sctp_handle_stream_reset_response(struct sctp_tcb *stcb, - uint32_t seq, uint32_t action, - struct sctp_stream_reset_response *respin) -{ - uint16_t type; - int lparam_len; - struct sctp_association *asoc = &stcb->asoc; - struct sctp_tmit_chunk *chk; - struct sctp_stream_reset_request *req_param; - struct sctp_stream_reset_out_request *req_out_param; - struct sctp_stream_reset_in_request *req_in_param; - uint32_t number_entries; - - if (asoc->stream_reset_outstanding == 0) { - /* duplicate */ - return (0); - } - if (seq == stcb->asoc.str_reset_seq_out) { - req_param = sctp_find_stream_reset(stcb, seq, &chk); - if (req_param != NULL) { - stcb->asoc.str_reset_seq_out++; - type = ntohs(req_param->ph.param_type); - lparam_len = ntohs(req_param->ph.param_length); - if (type == SCTP_STR_RESET_OUT_REQUEST) { - int no_clear = 0; - - req_out_param = (struct sctp_stream_reset_out_request *)req_param; - number_entries = (lparam_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t); - asoc->stream_reset_out_is_outstanding = 0; - if (asoc->stream_reset_outstanding) - asoc->stream_reset_outstanding--; - if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { - /* do it */ - sctp_reset_out_streams(stcb, number_entries, req_out_param->list_of_streams); - } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_OUT, stcb, number_entries, req_out_param->list_of_streams, SCTP_SO_NOT_LOCKED); - } else if (action == SCTP_STREAM_RESET_RESULT_IN_PROGRESS) { - /* Set it up so we don't stop retransmitting */ - asoc->stream_reset_outstanding++; - stcb->asoc.str_reset_seq_out--; - asoc->stream_reset_out_is_outstanding = 1; - no_clear = 1; - } else { - sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, req_out_param->list_of_streams, SCTP_SO_NOT_LOCKED); - } - if (no_clear == 0) { - sctp_reset_clear_pending(stcb, number_entries, req_out_param->list_of_streams); - } - } else if (type == SCTP_STR_RESET_IN_REQUEST) { - req_in_param = (struct sctp_stream_reset_in_request *)req_param; - number_entries = (lparam_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t); - if (asoc->stream_reset_outstanding) - asoc->stream_reset_outstanding--; - if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_IN, stcb, - number_entries, req_in_param->list_of_streams, SCTP_SO_NOT_LOCKED); - } else if (action != SCTP_STREAM_RESET_RESULT_PERFORMED) { - sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb, - number_entries, req_in_param->list_of_streams, SCTP_SO_NOT_LOCKED); - } - } else if (type == SCTP_STR_RESET_ADD_OUT_STREAMS) { - /* Ok we now may have more streams */ - int num_stream; - - num_stream = stcb->asoc.strm_pending_add_size; - if (num_stream > (stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt)) { - /* TSNH */ - num_stream = stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt; - } - stcb->asoc.strm_pending_add_size = 0; - if (asoc->stream_reset_outstanding) - asoc->stream_reset_outstanding--; - if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { - /* Put the new streams into effect */ - int i; - for (i = asoc->streamoutcnt; i < (asoc->streamoutcnt + num_stream); i++) { - asoc->strmout[i].state = SCTP_STREAM_OPEN; - } - asoc->streamoutcnt += num_stream; - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0); - } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_DENIED); - } else { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_FAILED); - } - } else if (type == SCTP_STR_RESET_ADD_IN_STREAMS) { - if (asoc->stream_reset_outstanding) - asoc->stream_reset_outstanding--; - if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_DENIED); - } else if (action != SCTP_STREAM_RESET_RESULT_PERFORMED) { - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, - SCTP_STREAM_CHANGE_FAILED); - } - } else if (type == SCTP_STR_RESET_TSN_REQUEST) { - /** - * a) Adopt the new in tsn. - * b) reset the map - * c) Adopt the new out-tsn - */ - struct sctp_stream_reset_response_tsn *resp; - struct sctp_forward_tsn_chunk fwdtsn; - int abort_flag = 0; - if (respin == NULL) { - /* huh ? */ - return (0); - } - if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) { - return (0); - } - if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { - resp = (struct sctp_stream_reset_response_tsn *)respin; - asoc->stream_reset_outstanding--; - fwdtsn.ch.chunk_length = htons(sizeof(struct sctp_forward_tsn_chunk)); - fwdtsn.ch.chunk_type = SCTP_FORWARD_CUM_TSN; - fwdtsn.new_cumulative_tsn = htonl(ntohl(resp->senders_next_tsn) - 1); - sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag, NULL, 0); - if (abort_flag) { - return (1); - } - stcb->asoc.highest_tsn_inside_map = (ntohl(resp->senders_next_tsn) - 1); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(0, 7, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); - } - - stcb->asoc.tsn_last_delivered = stcb->asoc.cumulative_tsn = stcb->asoc.highest_tsn_inside_map; - stcb->asoc.mapping_array_base_tsn = ntohl(resp->senders_next_tsn); - memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size); - - stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map; - memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size); - - stcb->asoc.sending_seq = ntohl(resp->receivers_next_tsn); - stcb->asoc.last_acked_seq = stcb->asoc.cumulative_tsn; - - sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL); - sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL); - sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0); - } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { - sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), - SCTP_ASSOC_RESET_DENIED); - } else { - sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), - SCTP_ASSOC_RESET_FAILED); - } - } - /* get rid of the request and get the request flags */ - if (asoc->stream_reset_outstanding == 0) { - sctp_clean_up_stream_reset(stcb); - } - } - } - if (asoc->stream_reset_outstanding == 0) { - sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_NOT_LOCKED); - } - return (0); -} - -static void -sctp_handle_str_reset_request_in(struct sctp_tcb *stcb, - struct sctp_tmit_chunk *chk, - struct sctp_stream_reset_in_request *req, int trunc) -{ - uint32_t seq; - int len, i; - int number_entries; - uint16_t temp; - - /* - * peer wants me to send a str-reset to him for my outgoing seq's if - * seq_in is right. - */ - struct sctp_association *asoc = &stcb->asoc; - - seq = ntohl(req->request_seq); - if (asoc->str_reset_seq_in == seq) { - asoc->last_reset_action[1] = asoc->last_reset_action[0]; - if ((asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ) == 0) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else if (trunc) { - /* Can't do it, since they exceeded our buffer size */ - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else if (stcb->asoc.stream_reset_out_is_outstanding == 0) { - len = ntohs(req->ph.param_length); - number_entries = ((len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t)); - if (number_entries) { - for (i = 0; i < number_entries; i++) { - temp = ntohs(req->list_of_streams[i]); - if (temp >= stcb->asoc.streamoutcnt) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - goto bad_boy; - } - req->list_of_streams[i] = temp; - } - for (i = 0; i < number_entries; i++) { - if (stcb->asoc.strmout[req->list_of_streams[i]].state == SCTP_STREAM_OPEN) { - stcb->asoc.strmout[req->list_of_streams[i]].state = SCTP_STREAM_RESET_PENDING; - } - } - } else { - /* Its all */ - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) - stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING; - } - } - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - } else { - /* Can't do it, since we have sent one out */ - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_ERR_IN_PROGRESS; - } - bad_boy: - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - asoc->str_reset_seq_in++; - } else if (asoc->str_reset_seq_in - 1 == seq) { - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - } else if (asoc->str_reset_seq_in - 2 == seq) { - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); - } else { - sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); - } - sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_NOT_LOCKED); -} - -static int -sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb, - struct sctp_tmit_chunk *chk, - struct sctp_stream_reset_tsn_request *req) -{ - /* reset all in and out and update the tsn */ - /* - * A) reset my str-seq's on in and out. B) Select a receive next, - * and set cum-ack to it. Also process this selected number as a - * fwd-tsn as well. C) set in the response my next sending seq. - */ - struct sctp_forward_tsn_chunk fwdtsn; - struct sctp_association *asoc = &stcb->asoc; - int abort_flag = 0; - uint32_t seq; - - seq = ntohl(req->request_seq); - if (asoc->str_reset_seq_in == seq) { - asoc->last_reset_action[1] = stcb->asoc.last_reset_action[0]; - if ((asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ) == 0) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else { - fwdtsn.ch.chunk_length = htons(sizeof(struct sctp_forward_tsn_chunk)); - fwdtsn.ch.chunk_type = SCTP_FORWARD_CUM_TSN; - fwdtsn.ch.chunk_flags = 0; - fwdtsn.new_cumulative_tsn = htonl(stcb->asoc.highest_tsn_inside_map + 1); - sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag, NULL, 0); - if (abort_flag) { - return (1); - } - asoc->highest_tsn_inside_map += SCTP_STREAM_RESET_TSN_DELTA; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(0, 10, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); - } - asoc->tsn_last_delivered = asoc->cumulative_tsn = asoc->highest_tsn_inside_map; - asoc->mapping_array_base_tsn = asoc->highest_tsn_inside_map + 1; - memset(asoc->mapping_array, 0, asoc->mapping_array_size); - asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map; - memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); - atomic_add_int(&asoc->sending_seq, 1); - /* save off historical data for retrans */ - asoc->last_sending_seq[1] = asoc->last_sending_seq[0]; - asoc->last_sending_seq[0] = asoc->sending_seq; - asoc->last_base_tsnsent[1] = asoc->last_base_tsnsent[0]; - asoc->last_base_tsnsent[0] = asoc->mapping_array_base_tsn; - sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL); - sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL); - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - sctp_notify_stream_reset_tsn(stcb, asoc->sending_seq, (asoc->mapping_array_base_tsn + 1), 0); - } - sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0], - asoc->last_sending_seq[0], asoc->last_base_tsnsent[0]); - asoc->str_reset_seq_in++; - } else if (asoc->str_reset_seq_in - 1 == seq) { - sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0], - asoc->last_sending_seq[0], asoc->last_base_tsnsent[0]); - } else if (asoc->str_reset_seq_in - 2 == seq) { - sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[1], - asoc->last_sending_seq[1], asoc->last_base_tsnsent[1]); - } else { - sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); - } - return (0); -} - -static void -sctp_handle_str_reset_request_out(struct sctp_tcb *stcb, - struct sctp_tmit_chunk *chk, - struct sctp_stream_reset_out_request *req, int trunc) -{ - uint32_t seq, tsn; - int number_entries, len; - struct sctp_association *asoc = &stcb->asoc; - - seq = ntohl(req->request_seq); - - /* now if its not a duplicate we process it */ - if (asoc->str_reset_seq_in == seq) { - len = ntohs(req->ph.param_length); - number_entries = ((len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t)); - /* - * the sender is resetting, handle the list issue.. we must - * a) verify if we can do the reset, if so no problem b) If - * we can't do the reset we must copy the request. c) queue - * it, and setup the data in processor to trigger it off - * when needed and dequeue all the queued data. - */ - tsn = ntohl(req->send_reset_at_tsn); - - /* move the reset action back one */ - asoc->last_reset_action[1] = asoc->last_reset_action[0]; - if ((asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ) == 0) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else if (trunc) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) { - /* we can do it now */ - sctp_reset_in_stream(stcb, number_entries, req->list_of_streams); - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - } else { - /* - * we must queue it up and thus wait for the TSN's - * to arrive that are at or before tsn - */ - struct sctp_stream_reset_list *liste; - int siz; - - siz = sizeof(struct sctp_stream_reset_list) + (number_entries * sizeof(uint16_t)); - SCTP_MALLOC(liste, struct sctp_stream_reset_list *, - siz, SCTP_M_STRESET); - if (liste == NULL) { - /* gak out of memory */ - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - return; - } - liste->seq = seq; - liste->tsn = tsn; - liste->number_entries = number_entries; - memcpy(&liste->list_of_streams, req->list_of_streams, number_entries * sizeof(uint16_t)); - TAILQ_INSERT_TAIL(&asoc->resetHead, liste, next_resp); - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_IN_PROGRESS; - } - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - asoc->str_reset_seq_in++; - } else if ((asoc->str_reset_seq_in - 1) == seq) { - /* - * one seq back, just echo back last action since my - * response was lost. - */ - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - } else if ((asoc->str_reset_seq_in - 2) == seq) { - /* - * two seq back, just echo back last action since my - * response was lost. - */ - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); - } else { - sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); - } -} - -static void -sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, - struct sctp_stream_reset_add_strm *str_add) -{ - /* - * Peer is requesting to add more streams. - * If its within our max-streams we will - * allow it. - */ - uint32_t num_stream, i; - uint32_t seq; - struct sctp_association *asoc = &stcb->asoc; - struct sctp_queued_to_read *ctl, *nctl; - - /* Get the number. */ - seq = ntohl(str_add->request_seq); - num_stream = ntohs(str_add->number_of_streams); - /* Now what would be the new total? */ - if (asoc->str_reset_seq_in == seq) { - num_stream += stcb->asoc.streamincnt; - stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0]; - if ((asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ) == 0) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else if ((num_stream > stcb->asoc.max_inbound_streams) || - (num_stream > 0xffff)) { - /* We must reject it they ask for to many */ - denied: - stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else { - /* Ok, we can do that :-) */ - struct sctp_stream_in *oldstrm; - - /* save off the old */ - oldstrm = stcb->asoc.strmin; - SCTP_MALLOC(stcb->asoc.strmin, struct sctp_stream_in *, - (num_stream * sizeof(struct sctp_stream_in)), - SCTP_M_STRMI); - if (stcb->asoc.strmin == NULL) { - stcb->asoc.strmin = oldstrm; - goto denied; - } - /* copy off the old data */ - for (i = 0; i < stcb->asoc.streamincnt; i++) { - TAILQ_INIT(&stcb->asoc.strmin[i].inqueue); - TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue); - stcb->asoc.strmin[i].sid = i; - stcb->asoc.strmin[i].last_mid_delivered = oldstrm[i].last_mid_delivered; - stcb->asoc.strmin[i].delivery_started = oldstrm[i].delivery_started; - stcb->asoc.strmin[i].pd_api_started = oldstrm[i].pd_api_started; - /* now anything on those queues? */ - TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next_instrm, nctl) { - TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next_instrm); - TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next_instrm); - } - TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].uno_inqueue, next_instrm, nctl) { - TAILQ_REMOVE(&oldstrm[i].uno_inqueue, ctl, next_instrm); - TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].uno_inqueue, ctl, next_instrm); - } - } - /* Init the new streams */ - for (i = stcb->asoc.streamincnt; i < num_stream; i++) { - TAILQ_INIT(&stcb->asoc.strmin[i].inqueue); - TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue); - stcb->asoc.strmin[i].sid = i; - stcb->asoc.strmin[i].last_mid_delivered = 0xffffffff; - stcb->asoc.strmin[i].pd_api_started = 0; - stcb->asoc.strmin[i].delivery_started = 0; - } - SCTP_FREE(oldstrm, SCTP_M_STRMI); - /* update the size */ - stcb->asoc.streamincnt = num_stream; - stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0); - } - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - asoc->str_reset_seq_in++; - } else if ((asoc->str_reset_seq_in - 1) == seq) { - /* - * one seq back, just echo back last action since my - * response was lost. - */ - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - } else if ((asoc->str_reset_seq_in - 2) == seq) { - /* - * two seq back, just echo back last action since my - * response was lost. - */ - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); - } else { - sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); - } -} - -static void -sctp_handle_str_reset_add_out_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, - struct sctp_stream_reset_add_strm *str_add) -{ - /* - * Peer is requesting to add more streams. - * If its within our max-streams we will - * allow it. - */ - uint16_t num_stream; - uint32_t seq; - struct sctp_association *asoc = &stcb->asoc; - - /* Get the number. */ - seq = ntohl(str_add->request_seq); - num_stream = ntohs(str_add->number_of_streams); - /* Now what would be the new total? */ - if (asoc->str_reset_seq_in == seq) { - stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0]; - if ((asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ) == 0) { - asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } else if (stcb->asoc.stream_reset_outstanding) { - /* We must reject it we have something pending */ - stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_ERR_IN_PROGRESS; - } else { - /* Ok, we can do that :-) */ - int mychk; - mychk = stcb->asoc.streamoutcnt; - mychk += num_stream; - if (mychk < 0x10000) { - stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; - if (sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, num_stream, 0, 1)) { - stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } - } else { - stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; - } - } - sctp_add_stream_reset_result(chk, seq, stcb->asoc.last_reset_action[0]); - asoc->str_reset_seq_in++; - } else if ((asoc->str_reset_seq_in - 1) == seq) { - /* - * one seq back, just echo back last action since my - * response was lost. - */ - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); - } else if ((asoc->str_reset_seq_in - 2) == seq) { - /* - * two seq back, just echo back last action since my - * response was lost. - */ - sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); - } else { - sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); - } -} - -#ifdef __GNUC__ -__attribute__ ((noinline)) -#endif -static int -sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, - struct sctp_chunkhdr *ch_req) -{ - uint16_t remaining_length, param_len, ptype; - struct sctp_paramhdr pstore; - uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; - uint32_t seq = 0; - int num_req = 0; - int trunc = 0; - struct sctp_tmit_chunk *chk; - struct sctp_chunkhdr *ch; - struct sctp_paramhdr *ph; - int ret_code = 0; - int num_param = 0; - - /* now it may be a reset or a reset-response */ - remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr); - - /* setup for adding the response */ - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - return (ret_code); - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_STREAM_RESET; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->no_fr_allowed = 0; - chk->book_size = chk->send_size = sizeof(struct sctp_chunkhdr); - chk->book_size_scale = 0; - chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (chk->data == NULL) { - strres_nochunk: - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return (ret_code); - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - - /* setup chunk parameters */ - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->whoTo = NULL; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - ch->chunk_type = SCTP_STREAM_RESET; - ch->chunk_flags = 0; - ch->chunk_length = htons(chk->send_size); - SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); - offset += sizeof(struct sctp_chunkhdr); - while (remaining_length >= sizeof(struct sctp_paramhdr)) { - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *)&pstore); - if (ph == NULL) { - /* TSNH */ - break; - } - param_len = ntohs(ph->param_length); - if ((param_len > remaining_length) || - (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) { - /* bad parameter length */ - break; - } - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)), - (uint8_t *)&cstore); - if (ph == NULL) { - /* TSNH */ - break; - } - ptype = ntohs(ph->param_type); - num_param++; - if (param_len > sizeof(cstore)) { - trunc = 1; - } else { - trunc = 0; - } - if (num_param > SCTP_MAX_RESET_PARAMS) { - /* hit the max of parameters already sorry.. */ - break; - } - if (ptype == SCTP_STR_RESET_OUT_REQUEST) { - struct sctp_stream_reset_out_request *req_out; - - if (param_len < sizeof(struct sctp_stream_reset_out_request)) { - break; - } - req_out = (struct sctp_stream_reset_out_request *)ph; - num_req++; - if (stcb->asoc.stream_reset_outstanding) { - seq = ntohl(req_out->response_seq); - if (seq == stcb->asoc.str_reset_seq_out) { - /* implicit ack */ - (void)sctp_handle_stream_reset_response(stcb, seq, SCTP_STREAM_RESET_RESULT_PERFORMED, NULL); - } - } - sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc); - } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { - struct sctp_stream_reset_add_strm *str_add; - - if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { - break; - } - str_add = (struct sctp_stream_reset_add_strm *)ph; - num_req++; - sctp_handle_str_reset_add_strm(stcb, chk, str_add); - } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { - struct sctp_stream_reset_add_strm *str_add; - - if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { - break; - } - str_add = (struct sctp_stream_reset_add_strm *)ph; - num_req++; - sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); - } else if (ptype == SCTP_STR_RESET_IN_REQUEST) { - struct sctp_stream_reset_in_request *req_in; - - num_req++; - req_in = (struct sctp_stream_reset_in_request *)ph; - sctp_handle_str_reset_request_in(stcb, chk, req_in, trunc); - } else if (ptype == SCTP_STR_RESET_TSN_REQUEST) { - struct sctp_stream_reset_tsn_request *req_tsn; - - num_req++; - req_tsn = (struct sctp_stream_reset_tsn_request *)ph; - if (sctp_handle_str_reset_request_tsn(stcb, chk, req_tsn)) { - ret_code = 1; - goto strres_nochunk; - } - /* no more */ - break; - } else if (ptype == SCTP_STR_RESET_RESPONSE) { - struct sctp_stream_reset_response *resp; - uint32_t result; - - if (param_len < sizeof(struct sctp_stream_reset_response)) { - break; - } - resp = (struct sctp_stream_reset_response *)ph; - seq = ntohl(resp->response_seq); - result = ntohl(resp->result); - if (sctp_handle_stream_reset_response(stcb, seq, result, resp)) { - ret_code = 1; - goto strres_nochunk; - } - } else { - break; - } - offset += SCTP_SIZE32(param_len); - if (remaining_length >= SCTP_SIZE32(param_len)) { - remaining_length -= SCTP_SIZE32(param_len); - } else { - remaining_length = 0; - } - } - if (num_req == 0) { - /* we have no response free the stuff */ - goto strres_nochunk; - } - /* ok we have a chunk to link in */ - TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, - chk, - sctp_next); - stcb->asoc.ctrl_queue_cnt++; - return (ret_code); -} - -/* - * Handle a router or endpoints report of a packet loss, there are two ways - * to handle this, either we get the whole packet and must disect it - * ourselves (possibly with truncation and or corruption) or it is a summary - * from a middle box that did the disecting for us. - */ -static void -sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp, - struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t limit) -{ - struct sctp_chunk_desc desc; - struct sctp_chunkhdr *chk_hdr; - struct sctp_data_chunk *data_chunk; - struct sctp_idata_chunk *idata_chunk; - uint32_t bottle_bw, on_queue; - uint32_t offset, chk_len; - uint16_t pktdrp_len; - uint8_t pktdrp_flags; - - KASSERT(sizeof(struct sctp_pktdrop_chunk) <= limit, - ("PKTDROP chunk too small")); - pktdrp_flags = cp->ch.chunk_flags; - pktdrp_len = ntohs(cp->ch.chunk_length); - KASSERT(limit <= pktdrp_len, ("Inconsistent limit")); - if (pktdrp_flags & SCTP_PACKET_TRUNCATED) { - if (ntohs(cp->trunc_len) <= pktdrp_len - sizeof(struct sctp_pktdrop_chunk)) { - /* The peer plays games with us. */ - return; - } - } - limit -= sizeof(struct sctp_pktdrop_chunk); - offset = 0; - if (offset == limit) { - if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) { - SCTP_STAT_INCR(sctps_pdrpbwrpt); - } - } else if (offset + sizeof(struct sctphdr) > limit) { - /* Only a partial SCTP common header. */ - SCTP_STAT_INCR(sctps_pdrpcrupt); - offset = limit; - } else { - /* XXX: Check embedded SCTP common header. */ - offset += sizeof(struct sctphdr); - } - /* Now parse through the chunks themselves. */ - while (offset < limit) { - if (offset + sizeof(struct sctp_chunkhdr) > limit) { - SCTP_STAT_INCR(sctps_pdrpcrupt); - break; - } - chk_hdr = (struct sctp_chunkhdr *)(cp->data + offset); - desc.chunk_type = chk_hdr->chunk_type; - /* get amount we need to move */ - chk_len = (uint32_t)ntohs(chk_hdr->chunk_length); - if (chk_len < sizeof(struct sctp_chunkhdr)) { - /* Someone is lying... */ - break; - } - if (desc.chunk_type == SCTP_DATA) { - if (stcb->asoc.idata_supported) { - /* Some is playing games with us. */ - break; - } - if (chk_len <= sizeof(struct sctp_data_chunk)) { - /* Some is playing games with us. */ - break; - } - if (chk_len < sizeof(struct sctp_data_chunk) + SCTP_NUM_DB_TO_VERIFY) { - /* Not enough data bytes available in the chunk. */ - SCTP_STAT_INCR(sctps_pdrpnedat); - goto next_chunk; - } - if (offset + sizeof(struct sctp_data_chunk) + SCTP_NUM_DB_TO_VERIFY > limit) { - /* Not enough data in buffer. */ - break; - } - data_chunk = (struct sctp_data_chunk *)(cp->data + offset); - memcpy(desc.data_bytes, data_chunk + 1, SCTP_NUM_DB_TO_VERIFY); - desc.tsn_ifany = data_chunk->dp.tsn; - if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) { - SCTP_STAT_INCR(sctps_pdrpmbda); - } - } else if (desc.chunk_type == SCTP_IDATA) { - if (!stcb->asoc.idata_supported) { - /* Some is playing games with us. */ - break; - } - if (chk_len <= sizeof(struct sctp_idata_chunk)) { - /* Some is playing games with us. */ - break; - } - if (chk_len < sizeof(struct sctp_idata_chunk) + SCTP_NUM_DB_TO_VERIFY) { - /* Not enough data bytes available in the chunk. */ - SCTP_STAT_INCR(sctps_pdrpnedat); - goto next_chunk; - } - if (offset + sizeof(struct sctp_idata_chunk) + SCTP_NUM_DB_TO_VERIFY > limit) { - /* Not enough data in buffer. */ - break; - } - idata_chunk = (struct sctp_idata_chunk *)(cp->data + offset); - memcpy(desc.data_bytes, idata_chunk + 1, SCTP_NUM_DB_TO_VERIFY); - desc.tsn_ifany = idata_chunk->dp.tsn; - if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) { - SCTP_STAT_INCR(sctps_pdrpmbda); - } - } else { - if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) { - SCTP_STAT_INCR(sctps_pdrpmbct); - } - } - if (process_chunk_drop(stcb, &desc, net, pktdrp_flags)) { - SCTP_STAT_INCR(sctps_pdrppdbrk); - break; - } -next_chunk: - offset += SCTP_SIZE32(chk_len); - } - /* Now update any rwnd --- possibly */ - if ((pktdrp_flags & SCTP_FROM_MIDDLE_BOX) == 0) { - /* From a peer, we get a rwnd report */ - uint32_t a_rwnd; - - SCTP_STAT_INCR(sctps_pdrpfehos); - - bottle_bw = ntohl(cp->bottle_bw); - on_queue = ntohl(cp->current_onq); - if (bottle_bw && on_queue) { - /* a rwnd report is in here */ - if (bottle_bw > on_queue) - a_rwnd = bottle_bw - on_queue; - else - a_rwnd = 0; - - if (a_rwnd == 0) - stcb->asoc.peers_rwnd = 0; - else { - if (a_rwnd > stcb->asoc.total_flight) { - stcb->asoc.peers_rwnd = - a_rwnd - stcb->asoc.total_flight; - } else { - stcb->asoc.peers_rwnd = 0; - } - if (stcb->asoc.peers_rwnd < - stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - stcb->asoc.peers_rwnd = 0; - } - } - } - } else { - SCTP_STAT_INCR(sctps_pdrpfmbox); - } - - /* now middle boxes in sat networks get a cwnd bump */ - if ((pktdrp_flags & SCTP_FROM_MIDDLE_BOX) && - (stcb->asoc.sat_t3_loss_recovery == 0) && - (stcb->asoc.sat_network)) { - /* - * This is debatable but for sat networks it makes sense - * Note if a T3 timer has went off, we will prohibit any - * changes to cwnd until we exit the t3 loss recovery. - */ - stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped(stcb, - net, cp, &bottle_bw, &on_queue); - } -} - -/* - * handles all control chunks in a packet inputs: - m: mbuf chain, assumed to - * still contain IP/SCTP header - stcb: is the tcb found for this packet - - * offset: offset into the mbuf chain to first chunkhdr - length: is the - * length of the complete packet outputs: - length: modified to remaining - * length after control processing - netp: modified to new sctp_nets after - * cookie-echo processing - return NULL to discard the packet (ie. no asoc, - * bad packet,...) otherwise return the tcb for this packet - */ -#ifdef __GNUC__ -__attribute__ ((noinline)) -#endif -static struct sctp_tcb * -sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb *inp, - struct sctp_tcb *stcb, struct sctp_nets **netp, int *fwd_tsn_seen, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_association *asoc; - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - uint32_t vtag_in; - int num_chunks = 0; /* number of control chunks processed */ - uint32_t chk_length, contiguous; - int ret; - int abort_no_unlock = 0; - int ecne_seen = 0; - int abort_flag; - /* - * How big should this be, and should it be alloc'd? Lets try the - * d-mtu-ceiling for now (2k) and that should hopefully work ... - * until we get into jumbo grams and such.. - */ - uint8_t chunk_buf[SCTP_CHUNK_BUFFER_SIZE]; - int got_auth = 0; - uint32_t auth_offset = 0, auth_len = 0; - int auth_skipped = 0; - int asconf_cnt = 0; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - - SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_control: iphlen=%u, offset=%u, length=%u stcb:%p\n", - iphlen, *offset, length, (void *)stcb); - - if (stcb) { - SCTP_TCB_LOCK_ASSERT(stcb); - } - /* validate chunk header length... */ - if (ntohs(ch->chunk_length) < sizeof(*ch)) { - SCTPDBG(SCTP_DEBUG_INPUT1, "Invalid header length %d\n", - ntohs(ch->chunk_length)); - *offset = length; - return (stcb); - } - /* - * validate the verification tag - */ - vtag_in = ntohl(sh->v_tag); - - if (ch->chunk_type == SCTP_INITIATION) { - SCTPDBG(SCTP_DEBUG_INPUT1, "Its an INIT of len:%d vtag:%x\n", - ntohs(ch->chunk_length), vtag_in); - if (vtag_in != 0) { - /* protocol error- silently discard... */ - SCTP_STAT_INCR(sctps_badvtag); - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return (NULL); - } - } else if (ch->chunk_type != SCTP_COOKIE_ECHO) { - /* - * If there is no stcb, skip the AUTH chunk and process - * later after a stcb is found (to validate the lookup was - * valid. - */ - if ((ch->chunk_type == SCTP_AUTHENTICATION) && - (stcb == NULL) && - (inp->auth_supported == 1)) { - /* save this chunk for later processing */ - auth_skipped = 1; - auth_offset = *offset; - auth_len = ntohs(ch->chunk_length); - - /* (temporarily) move past this chunk */ - *offset += SCTP_SIZE32(auth_len); - if (*offset >= length) { - /* no more data left in the mbuf chain */ - *offset = length; - return (NULL); - } - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_chunkhdr), chunk_buf); - } - if (ch == NULL) { - /* Help */ - *offset = length; - return (stcb); - } - if (ch->chunk_type == SCTP_COOKIE_ECHO) { - goto process_control_chunks; - } - /* - * first check if it's an ASCONF with an unknown src addr we - * need to look inside to find the association - */ - if (ch->chunk_type == SCTP_ASCONF && stcb == NULL) { - struct sctp_chunkhdr *asconf_ch = ch; - uint32_t asconf_offset = 0, asconf_len = 0; - - /* inp's refcount may be reduced */ - SCTP_INP_INCR_REF(inp); - - asconf_offset = *offset; - do { - asconf_len = ntohs(asconf_ch->chunk_length); - if (asconf_len < sizeof(struct sctp_asconf_paramhdr)) - break; - stcb = sctp_findassociation_ep_asconf(m, - *offset, - dst, - sh, &inp, netp, vrf_id); - if (stcb != NULL) - break; - asconf_offset += SCTP_SIZE32(asconf_len); - asconf_ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, asconf_offset, - sizeof(struct sctp_chunkhdr), chunk_buf); - } while (asconf_ch != NULL && asconf_ch->chunk_type == SCTP_ASCONF); - if (stcb == NULL) { - /* - * reduce inp's refcount if not reduced in - * sctp_findassociation_ep_asconf(). - */ - SCTP_INP_DECR_REF(inp); - } - - /* now go back and verify any auth chunk to be sure */ - if (auth_skipped && (stcb != NULL)) { - struct sctp_auth_chunk *auth; - - if (auth_len <= SCTP_CHUNK_BUFFER_SIZE) { - auth = (struct sctp_auth_chunk *)sctp_m_getptr(m, auth_offset, auth_len, chunk_buf); - got_auth = 1; - auth_skipped = 0; - } else { - auth = NULL; - } - if ((auth == NULL) || sctp_handle_auth(stcb, auth, m, - auth_offset)) { - /* auth HMAC failed so dump it */ - *offset = length; - return (stcb); - } else { - /* remaining chunks are HMAC checked */ - stcb->asoc.authenticated = 1; - } - } - } - if (stcb == NULL) { - SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - /* no association, so it's out of the blue... */ - sctp_handle_ootb(m, iphlen, *offset, src, dst, sh, inp, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - *offset = length; - return (NULL); - } - asoc = &stcb->asoc; - /* ABORT and SHUTDOWN can use either v_tag... */ - if ((ch->chunk_type == SCTP_ABORT_ASSOCIATION) || - (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) || - (ch->chunk_type == SCTP_PACKET_DROPPED)) { - /* Take the T-bit always into account. */ - if ((((ch->chunk_flags & SCTP_HAD_NO_TCB) == 0) && - (vtag_in == asoc->my_vtag)) || - (((ch->chunk_flags & SCTP_HAD_NO_TCB) == SCTP_HAD_NO_TCB) && - (asoc->peer_vtag != htonl(0)) && - (vtag_in == asoc->peer_vtag))) { - /* this is valid */ - } else { - /* drop this packet... */ - SCTP_STAT_INCR(sctps_badvtag); - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return (NULL); - } - } else { - /* for all other chunks, vtag must match */ - if (vtag_in != asoc->my_vtag) { - /* invalid vtag... */ - SCTPDBG(SCTP_DEBUG_INPUT3, - "invalid vtag: %xh, expect %xh\n", - vtag_in, asoc->my_vtag); - SCTP_STAT_INCR(sctps_badvtag); - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - *offset = length; - return (NULL); - } - } - } /* end if !SCTP_COOKIE_ECHO */ - /* - * process all control chunks... - */ - if (((ch->chunk_type == SCTP_SELECTIVE_ACK) || - (ch->chunk_type == SCTP_NR_SELECTIVE_ACK) || - (ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) && - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - /* implied cookie-ack.. we must have lost the ack */ - sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, - *netp); - } - - process_control_chunks: - while (IS_SCTP_CONTROL(ch)) { - /* validate chunk length */ - chk_length = ntohs(ch->chunk_length); - SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_process_control: processing a chunk type=%u, len=%u\n", - ch->chunk_type, chk_length); - SCTP_LTRACE_CHK(inp, stcb, ch->chunk_type, chk_length); - if (chk_length < sizeof(*ch) || - (*offset + (int)chk_length) > length) { - *offset = length; - return (stcb); - } - SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks); - /* - * INIT and INIT-ACK only gets the init ack "header" portion - * only because we don't have to process the peer's COOKIE. - * All others get a complete chunk. - */ - switch (ch->chunk_type) { - case SCTP_INITIATION: - contiguous = sizeof(struct sctp_init_chunk); - break; - case SCTP_INITIATION_ACK: - contiguous = sizeof(struct sctp_init_ack_chunk); - break; - default: - contiguous = min(chk_length, sizeof(chunk_buf)); - break; - } - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, - contiguous, - chunk_buf); - if (ch == NULL) { - *offset = length; - return (stcb); - } - - num_chunks++; - /* Save off the last place we got a control from */ - if (stcb != NULL) { - if (((netp != NULL) && (*netp != NULL)) || (ch->chunk_type == SCTP_ASCONF)) { - /* - * allow last_control to be NULL if - * ASCONF... ASCONF processing will find the - * right net later - */ - if ((netp != NULL) && (*netp != NULL)) - stcb->asoc.last_control_chunk_from = *netp; - } - } -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xB0, ch->chunk_type); -#endif - - /* check to see if this chunk required auth, but isn't */ - if ((stcb != NULL) && - sctp_auth_is_required_chunk(ch->chunk_type, stcb->asoc.local_auth_chunks) && - !stcb->asoc.authenticated) { - /* "silently" ignore */ - SCTP_STAT_INCR(sctps_recvauthmissing); - goto next_chunk; - } - switch (ch->chunk_type) { - case SCTP_INITIATION: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_INIT\n"); - /* The INIT chunk must be the only chunk. */ - if ((num_chunks > 1) || - (length - *offset > (int)SCTP_SIZE32(chk_length))) { - /* - * RFC 4960bis requires stopping the - * processing of the packet. - */ - *offset = length; - return (stcb); - } - /* Honor our resource limit. */ - if (chk_length > SCTP_LARGEST_INIT_ACCEPTED) { - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - *offset = length; - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return (NULL); - } - sctp_handle_init(m, iphlen, *offset, src, dst, sh, - (struct sctp_init_chunk *)ch, inp, - stcb, *netp, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - *offset = length; - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return (NULL); - break; - case SCTP_PAD_CHUNK: - break; - case SCTP_INITIATION_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_INIT_ACK\n"); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* We are not interested anymore */ - if ((stcb != NULL) && (stcb->asoc.total_output_queue_size)) { - ; - } else { - *offset = length; - if (stcb != NULL) { -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - return (NULL); - } - } - /* The INIT-ACK chunk must be the only chunk. */ - if ((num_chunks > 1) || - (length - *offset > (int)SCTP_SIZE32(chk_length))) { - *offset = length; - return (stcb); - } - if ((netp != NULL) && (*netp != NULL)) { - ret = sctp_handle_init_ack(m, iphlen, *offset, - src, dst, sh, - (struct sctp_init_ack_chunk *)ch, - stcb, *netp, - &abort_no_unlock, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id); - } else { - ret = -1; - } - *offset = length; - if (abort_no_unlock) { - return (NULL); - } - /* - * Special case, I must call the output routine to - * get the cookie echoed - */ - if ((stcb != NULL) && (ret == 0)) { - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); - } - return (stcb); - break; - case SCTP_SELECTIVE_ACK: - case SCTP_NR_SELECTIVE_ACK: - { - int abort_now = 0; - uint32_t a_rwnd, cum_ack; - uint16_t num_seg, num_nr_seg, num_dup; - uint8_t flags; - int offset_seg, offset_dup; - - SCTPDBG(SCTP_DEBUG_INPUT3, "%s\n", - ch->chunk_type == SCTP_SELECTIVE_ACK ? "SCTP_SACK" : "SCTP_NR_SACK"); - SCTP_STAT_INCR(sctps_recvsacks); - if (stcb == NULL) { - SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing %s chunk\n", - (ch->chunk_type == SCTP_SELECTIVE_ACK) ? "SCTP_SACK" : "SCTP_NR_SACK"); - break; - } - if (ch->chunk_type == SCTP_SELECTIVE_ACK) { - if (chk_length < sizeof(struct sctp_sack_chunk)) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on SACK chunk, too small\n"); - break; - } - } else { - if (stcb->asoc.nrsack_supported == 0) { - goto unknown_chunk; - } - if (chk_length < sizeof(struct sctp_nr_sack_chunk)) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on NR_SACK chunk, too small\n"); - break; - } - } - if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) { - /*- - * If we have sent a shutdown-ack, we will pay no - * attention to a sack sent in to us since - * we don't care anymore. - */ - break; - } - flags = ch->chunk_flags; - if (ch->chunk_type == SCTP_SELECTIVE_ACK) { - struct sctp_sack_chunk *sack; - - sack = (struct sctp_sack_chunk *)ch; - cum_ack = ntohl(sack->sack.cum_tsn_ack); - num_seg = ntohs(sack->sack.num_gap_ack_blks); - num_nr_seg = 0; - num_dup = ntohs(sack->sack.num_dup_tsns); - a_rwnd = ntohl(sack->sack.a_rwnd); - if (sizeof(struct sctp_sack_chunk) + - num_seg * sizeof(struct sctp_gap_ack_block) + - num_dup * sizeof(uint32_t) != chk_length) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size of SACK chunk\n"); - break; - } - offset_seg = *offset + sizeof(struct sctp_sack_chunk); - offset_dup = offset_seg + num_seg * sizeof(struct sctp_gap_ack_block); - } else { - struct sctp_nr_sack_chunk *nr_sack; - - nr_sack = (struct sctp_nr_sack_chunk *)ch; - cum_ack = ntohl(nr_sack->nr_sack.cum_tsn_ack); - num_seg = ntohs(nr_sack->nr_sack.num_gap_ack_blks); - num_nr_seg = ntohs(nr_sack->nr_sack.num_nr_gap_ack_blks); - num_dup = ntohs(nr_sack->nr_sack.num_dup_tsns); - a_rwnd = ntohl(nr_sack->nr_sack.a_rwnd); - if (sizeof(struct sctp_nr_sack_chunk) + - (num_seg + num_nr_seg) * sizeof(struct sctp_gap_ack_block) + - num_dup * sizeof(uint32_t) != chk_length) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size of NR_SACK chunk\n"); - break; - } - offset_seg = *offset + sizeof(struct sctp_nr_sack_chunk); - offset_dup = offset_seg + (num_seg + num_nr_seg) * sizeof(struct sctp_gap_ack_block); - } - SCTPDBG(SCTP_DEBUG_INPUT3, "%s process cum_ack:%x num_seg:%d a_rwnd:%d\n", - (ch->chunk_type == SCTP_SELECTIVE_ACK) ? "SCTP_SACK" : "SCTP_NR_SACK", - cum_ack, num_seg, a_rwnd); - stcb->asoc.seen_a_sack_this_pkt = 1; - if ((stcb->asoc.pr_sctp_cnt == 0) && - (num_seg == 0) && (num_nr_seg == 0) && - SCTP_TSN_GE(cum_ack, stcb->asoc.last_acked_seq) && - (stcb->asoc.saw_sack_with_frags == 0) && - (stcb->asoc.saw_sack_with_nr_frags == 0) && - (!TAILQ_EMPTY(&stcb->asoc.sent_queue))) { - /* - * We have a SIMPLE sack having no - * prior segments and data on sent - * queue to be acked. Use the - * faster path sack processing. We - * also allow window update sacks - * with no missing segments to go - * this way too. - */ - sctp_express_handle_sack(stcb, cum_ack, a_rwnd, - &abort_now, ecne_seen); - } else { - if ((netp != NULL) && (*netp != NULL)) { - sctp_handle_sack(m, offset_seg, offset_dup, stcb, - num_seg, num_nr_seg, num_dup, &abort_now, flags, - cum_ack, a_rwnd, ecne_seen); - } - } - if (abort_now) { - /* ABORT signal from sack processing */ - *offset = length; - return (NULL); - } - if (TAILQ_EMPTY(&stcb->asoc.send_queue) && - TAILQ_EMPTY(&stcb->asoc.sent_queue) && - (stcb->asoc.stream_queue_cnt == 0)) { - sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); - } - break; - } - case SCTP_HEARTBEAT_REQUEST: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT\n"); - if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) { - SCTP_STAT_INCR(sctps_recvheartbeat); - sctp_send_heartbeat_ack(stcb, m, *offset, - chk_length, *netp); - } - break; - case SCTP_HEARTBEAT_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT_ACK\n"); - if ((stcb == NULL) || (chk_length != sizeof(struct sctp_heartbeat_chunk))) { - /* Its not ours */ - break; - } - SCTP_STAT_INCR(sctps_recvheartbeatack); - if ((netp != NULL) && (*netp != NULL)) { - sctp_handle_heartbeat_ack((struct sctp_heartbeat_chunk *)ch, - stcb, *netp); - } - break; - case SCTP_ABORT_ASSOCIATION: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ABORT, stcb %p\n", - (void *)stcb); - *offset = length; - if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) { - if (sctp_handle_abort((struct sctp_abort_chunk *)ch, stcb, *netp)) { - return (NULL); - } else { - return (stcb); - } - } else { - return (NULL); - } - break; - case SCTP_SHUTDOWN: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN, stcb %p\n", - (void *)stcb); - if ((stcb == NULL) || (chk_length != sizeof(struct sctp_shutdown_chunk))) { - break; - } - if ((netp != NULL) && (*netp != NULL)) { - abort_flag = 0; - sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch, - stcb, *netp, &abort_flag); - if (abort_flag) { - *offset = length; - return (NULL); - } - } - break; - case SCTP_SHUTDOWN_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN_ACK, stcb %p\n", (void *)stcb); - if ((chk_length == sizeof(struct sctp_shutdown_ack_chunk)) && - (stcb != NULL) && (netp != NULL) && (*netp != NULL)) { - sctp_handle_shutdown_ack((struct sctp_shutdown_ack_chunk *)ch, stcb, *netp); - *offset = length; - return (NULL); - } - break; - case SCTP_OPERATION_ERROR: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_OP_ERR\n"); - if ((stcb != NULL) && (netp != NULL) && (*netp != NULL) && - sctp_handle_error(ch, stcb, *netp, contiguous) < 0) { - *offset = length; - return (NULL); - } - break; - case SCTP_COOKIE_ECHO: - SCTPDBG(SCTP_DEBUG_INPUT3, - "SCTP_COOKIE_ECHO, stcb %p\n", (void *)stcb); - if ((stcb != NULL) && (stcb->asoc.total_output_queue_size > 0)) { - ; - } else { - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* We are not interested anymore */ - abend: - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - *offset = length; - return (NULL); - } - } - /*- - * First are we accepting? We do this again here - * since it is possible that a previous endpoint WAS - * listening responded to a INIT-ACK and then - * closed. We opened and bound.. and are now no - * longer listening. - * - * XXXGL: notes on checking listen queue length. - * 1) SCTP_IS_LISTENING() doesn't necessarily mean - * SOLISTENING(), because a listening "UDP type" - * socket isn't listening in terms of the socket - * layer. It is a normal data flow socket, that - * can fork off new connections. Thus, we should - * look into sol_qlen only in case we are !UDP. - * 2) Checking sol_qlen in general requires locking - * the socket, and this code lacks that. - */ - if ((stcb == NULL) && - (!SCTP_IS_LISTENING(inp) || - (((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) && -#if defined(__FreeBSD__) && !defined(__Userspace__) - inp->sctp_socket->sol_qlen >= inp->sctp_socket->sol_qlimit))) { -#else - inp->sctp_socket->so_qlen >= inp->sctp_socket->so_qlimit))) { -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit))) { - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - sctp_abort_association(inp, stcb, m, iphlen, - src, dst, sh, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - vrf_id, port); - } - *offset = length; - return (NULL); - } else { - struct mbuf *ret_buf; - struct sctp_inpcb *linp; - struct sctp_tmit_chunk *chk; - - if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | - SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - goto abend; - } - - if (stcb) { - linp = NULL; - } else { - linp = inp; - } - - if (linp != NULL) { - SCTP_ASOC_CREATE_LOCK(linp); - } - - if (netp != NULL) { - struct sctp_tcb *locked_stcb; - - locked_stcb = stcb; - ret_buf = - sctp_handle_cookie_echo(m, iphlen, - *offset, - src, dst, - sh, - (struct sctp_cookie_echo_chunk *)ch, - &inp, &stcb, netp, - auth_skipped, - auth_offset, - auth_len, - &locked_stcb, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, - mflowid, -#endif - vrf_id, - port); - if ((locked_stcb != NULL) && (locked_stcb != stcb)) { - SCTP_TCB_UNLOCK(locked_stcb); - } - if (stcb != NULL) { - SCTP_TCB_LOCK_ASSERT(stcb); - } - } else { - ret_buf = NULL; - } - if (linp != NULL) { - SCTP_ASOC_CREATE_UNLOCK(linp); - } - if (ret_buf == NULL) { - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - SCTPDBG(SCTP_DEBUG_INPUT3, - "GAK, null buffer\n"); - *offset = length; - return (NULL); - } - /* if AUTH skipped, see if it verified... */ - if (auth_skipped) { - got_auth = 1; - auth_skipped = 0; - } - /* Restart the timer if we have pending data */ - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->whoTo != NULL) { - break; - } - } - if (chk != NULL) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo); - } - } - break; - case SCTP_COOKIE_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_COOKIE_ACK, stcb %p\n", (void *)stcb); - if ((stcb == NULL) || chk_length != sizeof(struct sctp_cookie_ack_chunk)) { - break; - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* We are not interested anymore */ - if ((stcb) && (stcb->asoc.total_output_queue_size)) { - ; - } else if (stcb) { -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_30); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - *offset = length; - return (NULL); - } - } - if ((netp != NULL) && (*netp != NULL)) { - sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, *netp); - } - break; - case SCTP_ECN_ECHO: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_ECHO\n"); - if (stcb == NULL) { - break; - } - if (stcb->asoc.ecn_supported == 0) { - goto unknown_chunk; - } - if ((chk_length != sizeof(struct sctp_ecne_chunk)) && - (chk_length != sizeof(struct old_sctp_ecne_chunk))) { - break; - } - sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch, stcb); - ecne_seen = 1; - break; - case SCTP_ECN_CWR: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_CWR\n"); - if (stcb == NULL) { - break; - } - if (stcb->asoc.ecn_supported == 0) { - goto unknown_chunk; - } - if (chk_length != sizeof(struct sctp_cwr_chunk)) { - break; - } - sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb, *netp); - break; - case SCTP_SHUTDOWN_COMPLETE: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN_COMPLETE, stcb %p\n", (void *)stcb); - /* must be first and only chunk */ - if ((num_chunks > 1) || - (length - *offset > (int)SCTP_SIZE32(chk_length))) { - *offset = length; - return (stcb); - } - if ((chk_length == sizeof(struct sctp_shutdown_complete_chunk)) && - (stcb != NULL) && (netp != NULL) && (*netp != NULL)) { - sctp_handle_shutdown_complete((struct sctp_shutdown_complete_chunk *)ch, - stcb, *netp); - *offset = length; - return (NULL); - } - break; - case SCTP_ASCONF: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n"); - if (stcb != NULL) { - if (stcb->asoc.asconf_supported == 0) { - goto unknown_chunk; - } - sctp_handle_asconf(m, *offset, src, - (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0); - asconf_cnt++; - } - break; - case SCTP_ASCONF_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF_ACK\n"); - if (stcb == NULL) { - break; - } - if (stcb->asoc.asconf_supported == 0) { - goto unknown_chunk; - } - if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) { - break; - } - if ((netp != NULL) && (*netp != NULL)) { - /* He's alive so give him credit */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_CLEAR, - stcb->asoc.overall_error_count, - 0, - SCTP_FROM_SCTP_INPUT, - __LINE__); - } - stcb->asoc.overall_error_count = 0; - sctp_handle_asconf_ack(m, *offset, - (struct sctp_asconf_ack_chunk *)ch, stcb, *netp, &abort_no_unlock); - if (abort_no_unlock) - return (NULL); - } - break; - case SCTP_FORWARD_CUM_TSN: - case SCTP_IFORWARD_CUM_TSN: - SCTPDBG(SCTP_DEBUG_INPUT3, "%s\n", - ch->chunk_type == SCTP_FORWARD_CUM_TSN ? "FORWARD_TSN" : "I_FORWARD_TSN"); - if (stcb == NULL) { - break; - } - if (stcb->asoc.prsctp_supported == 0) { - goto unknown_chunk; - } - if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) { - break; - } - if (((stcb->asoc.idata_supported == 1) && (ch->chunk_type == SCTP_FORWARD_CUM_TSN)) || - ((stcb->asoc.idata_supported == 0) && (ch->chunk_type == SCTP_IFORWARD_CUM_TSN))) { - if (ch->chunk_type == SCTP_FORWARD_CUM_TSN) { - SCTP_SNPRINTF(msg, sizeof(msg), "%s", "FORWARD-TSN chunk received when I-FORWARD-TSN was negotiated"); - } else { - SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-FORWARD-TSN chunk received when FORWARD-TSN was negotiated"); - } - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - *offset = length; - return (NULL); - } - *fwd_tsn_seen = 1; - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* We are not interested anymore */ -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_31); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - *offset = length; - return (NULL); - } - /* - * For sending a SACK this looks like DATA - * chunks. - */ - stcb->asoc.last_data_chunk_from = stcb->asoc.last_control_chunk_from; - abort_flag = 0; - sctp_handle_forward_tsn(stcb, - (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset); - if (abort_flag) { - *offset = length; - return (NULL); - } - break; - case SCTP_STREAM_RESET: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_STREAM_RESET\n"); - if (stcb == NULL) { - break; - } - if (stcb->asoc.reconfig_supported == 0) { - goto unknown_chunk; - } - if (chk_length < sizeof(struct sctp_stream_reset_tsn_req)) { - break; - } - if (sctp_handle_stream_reset(stcb, m, *offset, ch)) { - /* stop processing */ - *offset = length; - return (NULL); - } - break; - case SCTP_PACKET_DROPPED: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_PACKET_DROPPED\n"); - if (stcb == NULL) { - break; - } - if (stcb->asoc.pktdrop_supported == 0) { - goto unknown_chunk; - } - if (chk_length < sizeof(struct sctp_pktdrop_chunk)) { - break; - } - if ((netp != NULL) && (*netp != NULL)) { - sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch, - stcb, *netp, - min(chk_length, contiguous)); - } - break; - case SCTP_AUTHENTICATION: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_AUTHENTICATION\n"); - if (stcb == NULL) { - /* save the first AUTH for later processing */ - if (auth_skipped == 0) { - auth_offset = *offset; - auth_len = chk_length; - auth_skipped = 1; - } - /* skip this chunk (temporarily) */ - break; - } - if (stcb->asoc.auth_supported == 0) { - goto unknown_chunk; - } - if ((chk_length < (sizeof(struct sctp_auth_chunk))) || - (chk_length > (sizeof(struct sctp_auth_chunk) + - SCTP_AUTH_DIGEST_LEN_MAX))) { - /* Its not ours */ - *offset = length; - return (stcb); - } - if (got_auth == 1) { - /* skip this chunk... it's already auth'd */ - break; - } - got_auth = 1; - if (sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch, m, *offset)) { - /* auth HMAC failed so dump the packet */ - *offset = length; - return (stcb); - } else { - /* remaining chunks are HMAC checked */ - stcb->asoc.authenticated = 1; - } - break; - - default: - unknown_chunk: - /* it's an unknown chunk! */ - if ((ch->chunk_type & 0x40) && - (stcb != NULL) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_EMPTY) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_INUSE) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT)) { - struct sctp_gen_error_cause *cause; - int len; - - op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause), - 0, M_NOWAIT, 1, MT_DATA); - if (op_err != NULL) { - len = min(SCTP_SIZE32(chk_length), (uint32_t)(length - *offset)); - cause = mtod(op_err, struct sctp_gen_error_cause *); - cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK); - cause->length = htons((uint16_t)(len + sizeof(struct sctp_gen_error_cause))); - SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); - SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT); - if (SCTP_BUF_NEXT(op_err) != NULL) { -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(SCTP_BUF_NEXT(op_err), SCTP_MBUF_ICOPY); - } -#endif - sctp_queue_op_err(stcb, op_err); - } else { - sctp_m_freem(op_err); - } - } - } - if ((ch->chunk_type & 0x80) == 0) { - /* discard this packet */ - *offset = length; - return (stcb); - } /* else skip this bad chunk and continue... */ - break; - } /* switch (ch->chunk_type) */ - - next_chunk: - /* get the next chunk */ - *offset += SCTP_SIZE32(chk_length); - if (*offset >= length) { - /* no more data left in the mbuf chain */ - break; - } - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_chunkhdr), chunk_buf); - if (ch == NULL) { - *offset = length; - return (stcb); - } - } /* while */ - - if ((asconf_cnt > 0) && (stcb != NULL)) { - sctp_send_asconf_ack(stcb); - } - return (stcb); -} - -/* - * common input chunk processing (v4 and v6) - */ -void -sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int length, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_chunkhdr *ch, - uint8_t compute_crc, - uint8_t ecn_bits, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, -#endif - uint32_t vrf_id, uint16_t port) -{ - char msg[SCTP_DIAG_INFO_LEN]; - struct mbuf *m = *mm, *op_err; - struct sctp_inpcb *inp = NULL, *inp_decr = NULL; - struct sctp_tcb *stcb = NULL; - struct sctp_nets *net = NULL; -#if defined(__Userspace__) - struct socket *upcall_socket = NULL; -#endif - uint32_t high_tsn; - uint32_t cksum_in_hdr; - int un_sent; - int cnt_ctrl_ready = 0; - int fwd_tsn_seen = 0, data_processed = 0; - bool cksum_validated, stcb_looked_up; - - SCTP_STAT_INCR(sctps_recvdatagrams); -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xE0, 1); - sctp_auditing(0, inp, stcb, net); -#endif - - stcb_looked_up = false; - if (compute_crc != 0) { - cksum_validated = false; - cksum_in_hdr = sh->checksum; - if (cksum_in_hdr != htonl(0)) { - uint32_t cksum_calculated; - -validate_cksum: - sh->checksum = 0; - cksum_calculated = sctp_calculate_cksum(m, iphlen); - sh->checksum = cksum_in_hdr; - if (cksum_calculated != cksum_in_hdr) { - if (stcb_looked_up) { - /* - * The packet has a zero checksum, which - * is not the correct CRC, no stcb has - * been found or an stcb has been found - * but an incorrect zero checksum is not - * acceptable. - */ - KASSERT(cksum_in_hdr == htonl(0), - ("cksum in header not zero: %x", - ntohl(cksum_in_hdr))); - if ((inp == NULL) && - (SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum) == 1)) { - /* - * This is an OOTB packet, - * depending on the sysctl - * variable, pretend that the - * checksum is acceptable, - * to allow an appropriate - * response (ABORT, for examlpe) - * to be sent. - */ - KASSERT(stcb == NULL, - ("stcb is %p", stcb)); - SCTP_STAT_INCR(sctps_recvzerocrc); - goto cksum_validated; - } - } else { - stcb = sctp_findassociation_addr(m, offset, src, dst, - sh, ch, &inp, &net, vrf_id); - } - SCTPDBG(SCTP_DEBUG_INPUT1, "Bad cksum in SCTP packet:%x calculated:%x m:%p mlen:%d iphlen:%d\n", - ntohl(cksum_in_hdr), ntohl(cksum_calculated), (void *)m, length, iphlen); -#if defined(INET) || defined(INET6) - if ((ch->chunk_type != SCTP_INITIATION) && - (net != NULL) && (net->port != port)) { - if (net->port == 0) { - /* UDP encapsulation turned on. */ - net->mtu -= sizeof(struct udphdr); - if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu, true); - } - } else if (port == 0) { - /* UDP encapsulation turned off. */ - net->mtu += sizeof(struct udphdr); - /* XXX Update smallest_mtu */ - } - net->port = port; - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net != NULL) { - net->flowtype = mflowtype; - net->flowid = mflowid; - } - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); -#endif - if ((inp != NULL) && (stcb != NULL)) { - if (stcb->asoc.pktdrop_supported) { - sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); - } - } else if ((inp != NULL) && (stcb == NULL)) { - inp_decr = inp; - } - SCTP_STAT_INCR(sctps_badsum); - SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); - goto out; - } else { - cksum_validated = true; - } - } - KASSERT(cksum_validated || cksum_in_hdr == htonl(0), - ("cksum 0x%08x not zero and not validated", ntohl(cksum_in_hdr))); - if (!cksum_validated) { - stcb = sctp_findassociation_addr(m, offset, src, dst, - sh, ch, &inp, &net, vrf_id); - stcb_looked_up = true; - if (stcb == NULL) { - goto validate_cksum; - } - if (stcb->asoc.rcv_edmid == SCTP_EDMID_NONE) { - goto validate_cksum; - } - KASSERT(stcb->asoc.rcv_edmid == SCTP_EDMID_LOWER_LAYER_DTLS, - ("Unexpected EDMID %u", stcb->asoc.rcv_edmid)); - SCTP_STAT_INCR(sctps_recvzerocrc); - } - } -cksum_validated: - /* Destination port of 0 is illegal, based on RFC4960. */ - if (sh->dest_port == htons(0)) { - SCTP_STAT_INCR(sctps_hdrops); - if ((stcb == NULL) && (inp != NULL)) { - inp_decr = inp; - } - goto out; - } - if (!stcb_looked_up) { - stcb = sctp_findassociation_addr(m, offset, src, dst, - sh, ch, &inp, &net, vrf_id); - } -#if defined(INET) || defined(INET6) - if ((ch->chunk_type != SCTP_INITIATION) && - (net != NULL) && (net->port != port)) { - if (net->port == 0) { - /* UDP encapsulation turned on. */ - net->mtu -= sizeof(struct udphdr); - if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu, true); - } - } else if (port == 0) { - /* UDP encapsulation turned off. */ - net->mtu += sizeof(struct udphdr); - /* XXX Update smallest_mtu */ - } - net->port = port; - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net != NULL) { - net->flowtype = mflowtype; - net->flowid = mflowid; - } -#endif - if (inp == NULL) { - SCTP_STAT_INCR(sctps_noport); -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); - if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) { - goto out; - } -#endif - if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { - SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks); - sctp_send_shutdown_complete2(src, dst, sh, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - goto out; - } - if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { - SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks); - goto out; - } - if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) { - if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || - ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && - (ch->chunk_type != SCTP_INIT))) { - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Out of the blue"); - sctp_send_abort(m, iphlen, src, dst, - sh, 0, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - } - } - goto out; - } else if (stcb == NULL) { - inp_decr = inp; - } - SCTPDBG(SCTP_DEBUG_INPUT1, "Ok, Common input processing called, m:%p iphlen:%d offset:%d length:%d stcb:%p\n", - (void *)m, iphlen, offset, length, (void *)stcb); - if (stcb) { - /* always clear this before beginning a packet */ - stcb->asoc.authenticated = 0; - stcb->asoc.seen_a_sack_this_pkt = 0; - SCTPDBG(SCTP_DEBUG_INPUT1, "stcb:%p state:%x\n", - (void *)stcb, stcb->asoc.state); - - if ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) || - (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { - /*- - * If we hit here, we had a ref count - * up when the assoc was aborted and the - * timer is clearing out the assoc, we should - * NOT respond to any packet.. its OOTB. - */ - SCTP_TCB_UNLOCK(stcb); - stcb = NULL; -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); -#endif - SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - goto out; - } - } -#if defined(__Userspace__) - if ((stcb != NULL) && - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - if (stcb->sctp_socket->so_head != NULL) { - upcall_socket = stcb->sctp_socket->so_head; - } else { - upcall_socket = stcb->sctp_socket; - } - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - } -#endif - if (IS_SCTP_CONTROL(ch)) { - /* process the control portion of the SCTP packet */ - /* sa_ignore NO_NULL_CHK */ - stcb = sctp_process_control(m, iphlen, &offset, length, - src, dst, sh, ch, - inp, stcb, &net, &fwd_tsn_seen, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - if (stcb) { - /* This covers us if the cookie-echo was there - * and it changes our INP. - */ - inp = stcb->sctp_ep; -#if defined(INET) || defined(INET6) - if ((ch->chunk_type != SCTP_INITIATION) && - (net != NULL) && (net->port != port)) { - if (net->port == 0) { - /* UDP encapsulation turned on. */ - net->mtu -= sizeof(struct udphdr); - if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu, true); - } - } else if (port == 0) { - /* UDP encapsulation turned off. */ - net->mtu += sizeof(struct udphdr); - /* XXX Update smallest_mtu */ - } - net->port = port; - } -#endif - } - } else { - /* - * no control chunks, so pre-process DATA chunks (these - * checks are taken care of by control processing) - */ - - /* - * if DATA only packet, and auth is required, then punt... - * can't have authenticated without any AUTH (control) - * chunks - */ - if ((stcb != NULL) && - sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks)) { - /* "silently" ignore */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); -#endif - SCTP_STAT_INCR(sctps_recvauthmissing); - goto out; - } - if (stcb == NULL) { - /* out of the blue DATA chunk */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(receive, NULL, NULL, m, NULL, sh); -#endif - SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - goto out; - } - if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) { - /* v_tag mismatch! */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); -#endif - SCTP_STAT_INCR(sctps_badvtag); - goto out; - } - } - -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh); -#endif - if (stcb == NULL) { - /* - * no valid TCB for this packet, or we found it's a bad - * packet while processing control, or we're done with this - * packet (done or skip rest of data), so we drop it... - */ - goto out; - } -#if defined(__Userspace__) - if ((upcall_socket == NULL) && - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - if (stcb->sctp_socket->so_head != NULL) { - upcall_socket = stcb->sctp_socket->so_head; - } else { - upcall_socket = stcb->sctp_socket; - } - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - } -#endif - - /* - * DATA chunk processing - */ - /* plow through the data chunks while length > offset */ - - /* - * Rest should be DATA only. Check authentication state if AUTH for - * DATA is required. - */ - if ((length > offset) && - (stcb != NULL) && - sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks) && - !stcb->asoc.authenticated) { - /* "silently" ignore */ - SCTP_STAT_INCR(sctps_recvauthmissing); - SCTPDBG(SCTP_DEBUG_AUTH1, - "Data chunk requires AUTH, skipped\n"); - goto trigger_send; - } - if (length > offset) { - int retval; - - /* - * First check to make sure our state is correct. We would - * not get here unless we really did have a tag, so we don't - * abort if this happens, just dump the chunk silently. - */ - switch (SCTP_GET_STATE(stcb)) { - case SCTP_STATE_COOKIE_ECHOED: - /* - * we consider data with valid tags in this state - * shows us the cookie-ack was lost. Imply it was - * there. - */ - sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, net); - break; - case SCTP_STATE_COOKIE_WAIT: - /* - * We consider OOTB any data sent during asoc setup. - */ - SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - goto out; - /*sa_ignore NOTREACHED*/ - break; - case SCTP_STATE_EMPTY: /* should not happen */ - case SCTP_STATE_INUSE: /* should not happen */ - case SCTP_STATE_SHUTDOWN_RECEIVED: /* This is a peer error */ - case SCTP_STATE_SHUTDOWN_ACK_SENT: - default: - goto out; - /*sa_ignore NOTREACHED*/ - break; - case SCTP_STATE_OPEN: - case SCTP_STATE_SHUTDOWN_SENT: - break; - } - /* plow through the data chunks while length > offset */ - retval = sctp_process_data(mm, iphlen, &offset, length, - inp, stcb, net, &high_tsn); - if (retval == 2) { - /* - * The association aborted, NO UNLOCK needed since - * the association is destroyed. - */ - stcb = NULL; - goto out; - } - if (retval == 0) { - data_processed = 1; - } - /* - * Anything important needs to have been m_copy'ed in - * process_data - */ - } - - /* take care of ecn */ - if ((data_processed == 1) && - (stcb->asoc.ecn_supported == 1) && - ((ecn_bits & SCTP_CE_BITS) == SCTP_CE_BITS)) { - /* Yep, we need to add a ECNE */ - sctp_send_ecn_echo(stcb, net, high_tsn); - } - - if ((data_processed == 0) && (fwd_tsn_seen)) { - int was_a_gap; - uint32_t highest_tsn; - - if (SCTP_TSN_GT(stcb->asoc.highest_tsn_inside_nr_map, stcb->asoc.highest_tsn_inside_map)) { - highest_tsn = stcb->asoc.highest_tsn_inside_nr_map; - } else { - highest_tsn = stcb->asoc.highest_tsn_inside_map; - } - was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn); - stcb->asoc.send_sack = 1; - sctp_sack_check(stcb, was_a_gap); - } else if (fwd_tsn_seen) { - stcb->asoc.send_sack = 1; - } - /* trigger send of any chunks in queue... */ -trigger_send: -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xE0, 2); - sctp_auditing(1, inp, stcb, net); -#endif - SCTPDBG(SCTP_DEBUG_INPUT1, - "Check for chunk output prw:%d tqe:%d tf=%d\n", - stcb->asoc.peers_rwnd, - TAILQ_EMPTY(&stcb->asoc.control_send_queue), - stcb->asoc.total_flight); - un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight); - if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { - cnt_ctrl_ready = stcb->asoc.ctrl_queue_cnt - stcb->asoc.ecn_echo_cnt_onq; - } - if (!TAILQ_EMPTY(&stcb->asoc.asconf_send_queue) || - cnt_ctrl_ready || - stcb->asoc.trigger_reset || - ((un_sent > 0) && - (stcb->asoc.peers_rwnd > 0 || stcb->asoc.total_flight == 0))) { - SCTPDBG(SCTP_DEBUG_INPUT3, "Calling chunk OUTPUT\n"); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); - SCTPDBG(SCTP_DEBUG_INPUT3, "chunk OUTPUT returns\n"); - } -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xE0, 3); - sctp_auditing(2, inp, stcb, net); -#endif - out: - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } -#if defined(__Userspace__) - if (upcall_socket != NULL) { - if (upcall_socket->so_upcall != NULL) { - if (soreadable(upcall_socket) || - sowriteable(upcall_socket) || - upcall_socket->so_error) { - (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); - } - } - ACCEPT_LOCK(); - SOCK_LOCK(upcall_socket); - sorele(upcall_socket); - } -#endif - if (inp_decr != NULL) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp_decr); - SCTP_INP_DECR_REF(inp_decr); - SCTP_INP_WUNLOCK(inp_decr); - } - return; -} - -#ifdef INET -#if !defined(__Userspace__) -void -sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) -{ - struct mbuf *m; - int iphlen; - uint32_t vrf_id = 0; - uint8_t ecn_bits; - struct sockaddr_in src, dst; - struct ip *ip; - struct sctphdr *sh; - struct sctp_chunkhdr *ch; - int length, offset; - uint8_t compute_crc; -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint32_t mflowid; - uint8_t mflowtype; - uint16_t fibnum; -#endif -#if defined(__Userspace__) - uint16_t port = 0; -#endif - - iphlen = off; - if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) { - SCTP_RELEASE_PKT(i_pak); - return; - } - m = SCTP_HEADER_TO_CHAIN(i_pak); -#ifdef SCTP_MBUF_LOGGING - /* Log in any input mbufs */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(m, SCTP_MBUF_INPUT); - } -#endif -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { - sctp_packet_log(m); - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp_input(): Packet of length %d received on %s with csum_flags 0x%b.\n", - m->m_pkthdr.len, - if_name(m->m_pkthdr.rcvif), - (int)m->m_pkthdr.csum_flags, CSUM_BITS); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp_input(): Packet of length %d received on %s%d with csum_flags 0x%x.\n", - m->m_pkthdr.len, - m->m_pkthdr.rcvif->if_name, - m->m_pkthdr.rcvif->if_unit, - m->m_pkthdr.csum_flags); -#endif -#if defined(_WIN32) && !defined(__Userspace__) - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", - m->m_pkthdr.len, - m->m_pkthdr.rcvif->if_xname, - m->m_pkthdr.csum_flags); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowid = m->m_pkthdr.flowid; - mflowtype = M_HASHTYPE_GET(m); - fibnum = M_GETFIB(m); -#endif - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - /* Get IP, SCTP, and first chunk header together in the first mbuf. */ - offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (SCTP_BUF_LEN(m) < offset) { - if ((m = m_pullup(m, offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - return; - } - } - ip = mtod(m, struct ip *); - sh = (struct sctphdr *)((caddr_t)ip + iphlen); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - memset(&src, 0, sizeof(struct sockaddr_in)); - src.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - src.sin_len = sizeof(struct sockaddr_in); -#endif - src.sin_port = sh->src_port; - src.sin_addr = ip->ip_src; - memset(&dst, 0, sizeof(struct sockaddr_in)); - dst.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - dst.sin_port = sh->dest_port; - dst.sin_addr = ip->ip_dst; -#if defined(_WIN32) && !defined(__Userspace__) - NTOHS(ip->ip_len); -#endif -#if defined(__linux__) || (defined(_WIN32) && defined(__Userspace__)) - ip->ip_len = ntohs(ip->ip_len); -#endif -#if defined(__Userspace__) -#if defined(__linux__) || defined(_WIN32) - length = ip->ip_len; -#else - length = ip->ip_len + iphlen; -#endif -#elif defined(__FreeBSD__) - length = ntohs(ip->ip_len); -#elif defined(__APPLE__) - length = ip->ip_len + iphlen; -#else - length = ip->ip_len; -#endif - /* Validate mbuf chain length with IP payload length. */ - if (SCTP_HEADER_LEN(m) != length) { - SCTPDBG(SCTP_DEBUG_INPUT1, - "sctp_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m)); - SCTP_STAT_INCR(sctps_hdrops); - goto out; - } - /* SCTP does not allow broadcasts or multicasts */ - if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { - goto out; - } - if (SCTP_IS_IT_BROADCAST(dst.sin_addr, m)) { - goto out; - } - ecn_bits = ip->ip_tos; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { - SCTP_STAT_INCR(sctps_recvhwcrc); - compute_crc = 0; - } else { -#else - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - ((src.sin_addr.s_addr == dst.sin_addr.s_addr) || - (SCTP_IS_IT_LOOPBACK(m)))) { - SCTP_STAT_INCR(sctps_recvhwcrc); - compute_crc = 0; - } else { -#endif - SCTP_STAT_INCR(sctps_recvswcrc); - compute_crc = 1; - } - sctp_common_input_processing(&m, iphlen, offset, length, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - compute_crc, - ecn_bits, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - out: - if (m) { - sctp_m_freem(m); - } - return; -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_MCORE_INPUT) && defined(SMP) -extern int *sctp_cpuarry; -#endif -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -int -sctp_input(struct mbuf **mp, int *offp, int proto SCTP_UNUSED) -{ - struct mbuf *m; - int off; - - m = *mp; - off = *offp; -#else -void -sctp_input(struct mbuf *m, int off) -{ -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_MCORE_INPUT) && defined(SMP) - if (mp_ncpus > 1) { - struct ip *ip; - struct sctphdr *sh; - int offset; - int cpu_to_use; - uint32_t flowid, tag; - - if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { - flowid = m->m_pkthdr.flowid; - } else { - /* No flow id built by lower layers - * fix it so we create one. - */ - offset = off + sizeof(struct sctphdr); - if (SCTP_BUF_LEN(m) < offset) { - if ((m = m_pullup(m, offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - return (IPPROTO_DONE); - } - } - ip = mtod(m, struct ip *); - sh = (struct sctphdr *)((caddr_t)ip + off); - tag = htonl(sh->v_tag); - flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); - m->m_pkthdr.flowid = flowid; - M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE_HASH); - } - cpu_to_use = sctp_cpuarry[flowid % mp_ncpus]; - sctp_queue_to_mcore(m, off, cpu_to_use); - return (IPPROTO_DONE); - } -#endif -#endif - sctp_input_with_port(m, off, 0); -#if defined(__FreeBSD__) && !defined(__Userspace__) - return (IPPROTO_DONE); -#endif -} -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.h deleted file mode 100644 index d2cd2157..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_input.h +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_INPUT_H_ -#define _NETINET_SCTP_INPUT_H_ - -#if defined(_KERNEL) || defined(__Userspace__) -void -sctp_common_input_processing(struct mbuf **, int, int, int, - struct sockaddr *, struct sockaddr *, - struct sctphdr *, struct sctp_chunkhdr *, - uint8_t, - uint8_t, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, uint16_t, -#endif - uint32_t, uint16_t); - -struct sctp_stream_reset_request * -sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, - struct sctp_tmit_chunk **bchk); - -void -sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, - uint16_t *list); - -int sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked); - -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_lock_userspace.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_lock_userspace.h deleted file mode 100644 index 05259f40..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_lock_userspace.h +++ /dev/null @@ -1,244 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * Copyright (c) 2008-2012, by Brad Penoff. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_LOCK_EMPTY_H_ -#define _NETINET_SCTP_LOCK_EMPTY_H_ - -/* - * Empty Lock declarations for all other platforms. Pre-process away to - * nothing. - */ - -/* __Userspace__ putting lock macros in same order as sctp_lock_bsd.h ...*/ - -#define SCTP_IPI_COUNT_INIT() - -#define SCTP_STATLOG_INIT_LOCK() -#define SCTP_STATLOG_LOCK() -#define SCTP_STATLOG_UNLOCK() -#define SCTP_STATLOG_DESTROY() - -#define SCTP_INP_INFO_LOCK_DESTROY() - -#define SCTP_INP_INFO_LOCK_INIT() -#define SCTP_INP_INFO_RLOCK() -#define SCTP_INP_INFO_WLOCK() -#define SCTP_INP_INFO_TRYLOCK() 1 -#define SCTP_INP_INFO_RUNLOCK() -#define SCTP_INP_INFO_WUNLOCK() -#define SCTP_INP_INFO_LOCK_ASSERT() -#define SCTP_INP_INFO_RLOCK_ASSERT() -#define SCTP_INP_INFO_WLOCK_ASSERT() - -#define SCTP_WQ_ADDR_INIT() -#define SCTP_WQ_ADDR_DESTROY() -#define SCTP_WQ_ADDR_LOCK() -#define SCTP_WQ_ADDR_UNLOCK() -#define SCTP_WQ_ADDR_LOCK_ASSERT() - -#define SCTP_IPI_ADDR_INIT() -#define SCTP_IPI_ADDR_DESTROY() -#define SCTP_IPI_ADDR_RLOCK() -#define SCTP_IPI_ADDR_WLOCK() -#define SCTP_IPI_ADDR_RUNLOCK() -#define SCTP_IPI_ADDR_WUNLOCK() -#define SCTP_IPI_ADDR_LOCK_ASSERT() -#define SCTP_IPI_ADDR_WLOCK_ASSERT() - -#define SCTP_IPI_ITERATOR_WQ_INIT() -#define SCTP_IPI_ITERATOR_WQ_DESTROY() -#define SCTP_IPI_ITERATOR_WQ_LOCK() -#define SCTP_IPI_ITERATOR_WQ_UNLOCK() - -#define SCTP_IP_PKTLOG_INIT() -#define SCTP_IP_PKTLOG_LOCK() -#define SCTP_IP_PKTLOG_UNLOCK() -#define SCTP_IP_PKTLOG_DESTROY() - -#define SCTP_INP_READ_LOCK_INIT(_inp) -#define SCTP_INP_READ_LOCK_DESTROY(_inp) -#define SCTP_INP_READ_LOCK(_inp) -#define SCTP_INP_READ_UNLOCK(_inp) -#define SCTP_INP_READ_LOCK_ASSERT(_inp) - -#define SCTP_INP_LOCK_INIT(_inp) -#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) -#define SCTP_INP_LOCK_DESTROY(_inp) -#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) - -#define SCTP_INP_RLOCK(_inp) -#define SCTP_INP_WLOCK(_inp) -#define SCTP_INP_RLOCK_ASSERT(_inp) -#define SCTP_INP_WLOCK_ASSERT(_inp) - -#define SCTP_INP_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */ - -#define SCTP_INP_READ_CONTENDED(_inp) (0) /* Don't know if this is possible */ - -#define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */ - - -#define SCTP_INP_INCR_REF(_inp) -#define SCTP_INP_DECR_REF(_inp) - -#define SCTP_ASOC_CREATE_LOCK(_inp) - -#define SCTP_INP_RUNLOCK(_inp) -#define SCTP_INP_WUNLOCK(_inp) -#define SCTP_ASOC_CREATE_UNLOCK(_inp) - - -#define SCTP_TCB_LOCK_INIT(_tcb) -#define SCTP_TCB_LOCK_DESTROY(_tcb) -#define SCTP_TCB_LOCK(_tcb) -#define SCTP_TCB_TRYLOCK(_tcb) 1 -#define SCTP_TCB_UNLOCK(_tcb) -#define SCTP_TCB_UNLOCK_IFOWNED(_tcb) -#define SCTP_TCB_LOCK_ASSERT(_tcb) - - - -#define SCTP_ITERATOR_LOCK_INIT() -#define SCTP_ITERATOR_LOCK() -#define SCTP_ITERATOR_UNLOCK() -#define SCTP_ITERATOR_LOCK_DESTROY() - - - -#define SCTP_INCR_EP_COUNT() \ - do { \ - sctppcbinfo.ipi_count_ep++; \ - } while (0) - -#define SCTP_DECR_EP_COUNT() \ - do { \ - sctppcbinfo.ipi_count_ep--; \ - } while (0) - -#define SCTP_INCR_ASOC_COUNT() \ - do { \ - sctppcbinfo.ipi_count_asoc++; \ - } while (0) - -#define SCTP_DECR_ASOC_COUNT() \ - do { \ - sctppcbinfo.ipi_count_asoc--; \ - } while (0) - -#define SCTP_INCR_LADDR_COUNT() \ - do { \ - sctppcbinfo.ipi_count_laddr++; \ - } while (0) - -#define SCTP_DECR_LADDR_COUNT() \ - do { \ - sctppcbinfo.ipi_count_laddr--; \ - } while (0) - -#define SCTP_INCR_RADDR_COUNT() \ - do { \ - sctppcbinfo.ipi_count_raddr++; \ - } while (0) - -#define SCTP_DECR_RADDR_COUNT() \ - do { \ - sctppcbinfo.ipi_count_raddr--; \ - } while (0) - -#define SCTP_INCR_CHK_COUNT() \ - do { \ - sctppcbinfo.ipi_count_chunk++; \ - } while (0) - -#define SCTP_DECR_CHK_COUNT() \ - do { \ - sctppcbinfo.ipi_count_chunk--; \ - } while (0) - -#define SCTP_INCR_READQ_COUNT() \ - do { \ - sctppcbinfo.ipi_count_readq++; \ - } while (0) - -#define SCTP_DECR_READQ_COUNT() \ - do { \ - sctppcbinfo.ipi_count_readq--; \ - } while (0) - -#define SCTP_INCR_STRMOQ_COUNT() \ - do { \ - sctppcbinfo.ipi_count_strmoq++; \ - } while (0) - -#define SCTP_DECR_STRMOQ_COUNT() \ - do { \ - sctppcbinfo.ipi_count_strmoq--; \ - } while (0) - - -/* these were in sctp_lock_empty.h but aren't in sctp_lock_bsd.h ... */ -#if 0 -#define SCTP_IPI_ADDR_LOCK() -#define SCTP_IPI_ADDR_UNLOCK() -#endif - - -/* These were in sctp_lock_empty.h because they were commented out within - * within user_include/user_socketvar.h . If they are NOT commented out - * in user_socketvar.h (because that seems the more natural place for them - * to live), then change this "if" to 0. Keep the "if" as 1 if these ARE - * indeed commented out in user_socketvar.h . - * - * This modularity is kept so this file can easily be chosen as an alternative - * to SCTP_PROCESS_LEVEL_LOCKS. If one defines SCTP_PROCESS_LEVEL_LOCKS in - * user_include/opt_sctp.h, then the file sctp_process_lock.h (which we didn't - * implement) is used, and that declares these locks already (so using - * SCTP_PROCESS_LEVEL_LOCKS *requires* that these defintions be commented out - * in user_socketvar.h). - */ -#if 1 -#define SOCK_LOCK(_so) -#define SOCK_UNLOCK(_so) -#define SOCKBUF_LOCK(_so_buf) -#define SOCKBUF_UNLOCK(_so_buf) -#define SOCKBUF_LOCK_ASSERT(_so_buf) -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os.h deleted file mode 100644 index dae612bc..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os.h +++ /dev/null @@ -1,89 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2006-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_OS_H_ -#define _NETINET_SCTP_OS_H_ - -/* - * General kernel memory allocation: - * SCTP_MALLOC(element, type, size, name) - * SCTP_FREE(element) - * Kernel memory allocation for "soname"- memory must be zeroed. - * SCTP_MALLOC_SONAME(name, type, size) - * SCTP_FREE_SONAME(name) - */ - -/* - * Zone(pool) allocation routines: MUST be defined for each OS. - * zone = zone/pool pointer. - * name = string name of the zone/pool. - * size = size of each zone/pool element. - * number = number of elements in zone/pool. - * type = structure type to allocate - * - * sctp_zone_t - * SCTP_ZONE_INIT(zone, name, size, number) - * SCTP_ZONE_GET(zone, type) - * SCTP_ZONE_FREE(zone, element) - * SCTP_ZONE_DESTROY(zone) - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#else -#define MODULE_GLOBAL(_B) (_B) -#endif -#if defined(__Userspace__) -#include -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#include -#endif -#if defined(_WIN32) && !defined(__Userspace__) -#include -#endif - -/* All os's must implement this address gatherer. If - * no VRF's exist, then vrf 0 is the only one and all - * addresses and ifn's live here. - */ -#define SCTP_DEFAULT_VRF 0 -void sctp_init_vrf_list(int vrfid); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os_userspace.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os_userspace.h deleted file mode 100644 index 493ae026..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_os_userspace.h +++ /dev/null @@ -1,1153 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2006-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved. - * Copyright (c) 2008-2011, by Brad Penoff. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __sctp_os_userspace_h__ -#define __sctp_os_userspace_h__ -/* - * Userspace includes - * All the opt_xxx.h files are placed in the kernel build directory. - * We will place them in userspace stack build directory. - */ - -#include - -#if defined(_WIN32) -#include -#include -#include -#include -#include -#include "user_environment.h" -typedef CRITICAL_SECTION userland_mutex_t; -#if WINVER < 0x0600 -typedef CRITICAL_SECTION userland_rwlock_t; -enum { - C_SIGNAL = 0, - C_BROADCAST = 1, - C_MAX_EVENTS = 2 -}; -typedef struct -{ - u_int waiters_count; - CRITICAL_SECTION waiters_count_lock; - HANDLE events_[C_MAX_EVENTS]; -} userland_cond_t; -void InitializeXPConditionVariable(userland_cond_t *); -void DeleteXPConditionVariable(userland_cond_t *); -int SleepXPConditionVariable(userland_cond_t *, userland_mutex_t *); -void WakeAllXPConditionVariable(userland_cond_t *); -#define InitializeConditionVariable(cond) InitializeXPConditionVariable(cond) -#define DeleteConditionVariable(cond) DeleteXPConditionVariable(cond) -#define SleepConditionVariableCS(cond, mtx, time) SleepXPConditionVariable(cond, mtx) -#define WakeAllConditionVariable(cond) WakeAllXPConditionVariable(cond) -#else -typedef SRWLOCK userland_rwlock_t; -#define DeleteConditionVariable(cond) -typedef CONDITION_VARIABLE userland_cond_t; -#endif -typedef HANDLE userland_thread_t; -#define ADDRESS_FAMILY unsigned __int8 -#define IPVERSION 4 -#define MAXTTL 255 -/* VS2010 comes with stdint.h */ -#if !defined(_MSC_VER) || (_MSC_VER >= 1600) -#include -#else -typedef unsigned __int64 uint64_t; -typedef unsigned __int32 uint32_t; -typedef __int32 int32_t; -typedef unsigned __int16 uint16_t; -typedef __int16 int16_t; -typedef unsigned __int8 uint8_t; -typedef __int8 int8_t; -#endif -#ifndef _SIZE_T_DEFINED -#typedef __int32 size_t; -#endif -typedef unsigned __int32 u_int; -typedef unsigned char u_char; -typedef unsigned __int16 u_short; -typedef unsigned __int8 sa_family_t; -#ifndef _SSIZE_T_DEFINED -typedef __int64 ssize_t; -#endif -#if !defined(__MINGW32__) -#define __func__ __FUNCTION__ -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef EALREADY -#define EALREADY WSAEALREADY -#endif -#ifndef ENOTSOCK -#define ENOTSOCK WSAENOTSOCK -#endif -#ifndef EDESTADDRREQ -#define EDESTADDRREQ WSAEDESTADDRREQ -#endif -#ifndef EMSGSIZE -#define EMSGSIZE WSAEMSGSIZE -#endif -#ifndef EPROTOTYPE -#define EPROTOTYPE WSAEPROTOTYPE -#endif -#ifndef ENOPROTOOPT -#define ENOPROTOOPT WSAENOPROTOOPT -#endif -#ifndef EPROTONOSUPPORT -#define EPROTONOSUPPORT WSAEPROTONOSUPPORT -#endif -#ifndef ESOCKTNOSUPPORT -#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT -#endif -#ifndef EOPNOTSUPP -#define EOPNOTSUPP WSAEOPNOTSUPP -#endif -#ifndef ENOTSUP -#define ENOTSUP WSAEOPNOTSUPP -#endif -#ifndef EPFNOSUPPORT -#define EPFNOSUPPORT WSAEPFNOSUPPORT -#endif -#ifndef EAFNOSUPPORT -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#endif -#ifndef EADDRINUSE -#define EADDRINUSE WSAEADDRINUSE -#endif -#ifndef EADDRNOTAVAIL -#define EADDRNOTAVAIL WSAEADDRNOTAVAIL -#endif -#ifndef ENETDOWN -#define ENETDOWN WSAENETDOWN -#endif -#ifndef ENETUNREACH -#define ENETUNREACH WSAENETUNREACH -#endif -#ifndef ENETRESET -#define ENETRESET WSAENETRESET -#endif -#ifndef ECONNABORTED -#define ECONNABORTED WSAECONNABORTED -#endif -#ifndef ECONNRESET -#define ECONNRESET WSAECONNRESET -#endif -#ifndef ENOBUFS -#define ENOBUFS WSAENOBUFS -#endif -#ifndef EISCONN -#define EISCONN WSAEISCONN -#endif -#ifndef ENOTCONN -#define ENOTCONN WSAENOTCONN -#endif -#ifndef ESHUTDOWN -#define ESHUTDOWN WSAESHUTDOWN -#endif -#ifndef ETOOMANYREFS -#define ETOOMANYREFS WSAETOOMANYREFS -#endif -#ifndef ETIMEDOUT -#define ETIMEDOUT WSAETIMEDOUT -#endif -#ifndef ECONNREFUSED -#define ECONNREFUSED WSAECONNREFUSED -#endif -#ifndef ELOOP -#define ELOOP WSAELOOP -#endif -#ifndef EHOSTDOWN -#define EHOSTDOWN WSAEHOSTDOWN -#endif -#ifndef EHOSTUNREACH -#define EHOSTUNREACH WSAEHOSTUNREACH -#endif -#ifndef EPROCLIM -#define EPROCLIM WSAEPROCLIM -#endif -#ifndef EUSERS -#define EUSERS WSAEUSERS -#endif -#ifndef EDQUOT -#define EDQUOT WSAEDQUOT -#endif -#ifndef ESTALE -#define ESTALE WSAESTALE -#endif -#ifndef EREMOTE -#define EREMOTE WSAEREMOTE -#endif - -typedef char* caddr_t; - -#define bzero(buf, len) memset(buf, 0, len) -#define bcopy(srcKey, dstKey, len) memcpy(dstKey, srcKey, len) - -#if defined(_MSC_VER) && (_MSC_VER < 1900) && !defined(__MINGW32__) -#define SCTP_SNPRINTF(data, size, format, ...) \ - if (_snprintf_s(data, size, _TRUNCATE, format, __VA_ARGS__) < 0) { \ - data[0] = '\0'; \ - } -#else -#define SCTP_SNPRINTF(data, ...) \ - if (snprintf(data, __VA_ARGS__) < 0 ) { \ - data[0] = '\0'; \ - } -#endif - -#define inline __inline -#define __inline__ __inline -#define MSG_EOR 0x8 /* data completes record */ -#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ - -#ifdef CMSG_DATA -#undef CMSG_DATA -#endif -/* - * The following definitions should apply iff WINVER < 0x0600 - * but that check doesn't work in all cases. So be more pedantic... - */ -#define CMSG_DATA(x) WSA_CMSG_DATA(x) -#define CMSG_ALIGN(x) WSA_CMSGDATA_ALIGN(x) -#ifndef CMSG_FIRSTHDR -#define CMSG_FIRSTHDR(x) WSA_CMSG_FIRSTHDR(x) -#endif -#ifndef CMSG_NXTHDR -#define CMSG_NXTHDR(x, y) WSA_CMSG_NXTHDR(x, y) -#endif -#ifndef CMSG_SPACE -#define CMSG_SPACE(x) WSA_CMSG_SPACE(x) -#endif -#ifndef CMSG_LEN -#define CMSG_LEN(x) WSA_CMSG_LEN(x) -#endif - -/**** from sctp_os_windows.h ***************/ -#define SCTP_IFN_IS_IFT_LOOP(ifn) ((ifn)->ifn_type == IFT_LOOP) -#define SCTP_ROUTE_IS_REAL_LOOP(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifa && (ro)->ro_rt->rt_ifa->ifa_ifp && (ro)->ro_rt->rt_ifa->ifa_ifp->if_type == IFT_LOOP) - -/* - * Access to IFN's to help with src-addr-selection - */ -/* This could return VOID if the index works but for BSD we provide both. */ -#define SCTP_GET_IFN_VOID_FROM_ROUTE(ro) \ - ((ro)->ro_rt != NULL ? (ro)->ro_rt->rt_ifp : NULL) -#define SCTP_ROUTE_HAS_VALID_IFN(ro) \ - ((ro)->ro_rt && (ro)->ro_rt->rt_ifp) -/******************************************/ - -#define SCTP_GET_IF_INDEX_FROM_ROUTE(ro) 1 /* compiles... TODO use routing socket to determine */ - -#define BIG_ENDIAN 1 -#define LITTLE_ENDIAN 0 -#ifdef WORDS_BIGENDIAN -#define BYTE_ORDER BIG_ENDIAN -#else -#define BYTE_ORDER LITTLE_ENDIAN -#endif - -#else /* !defined(Userspace_os_Windows) */ -#include - -#if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__) -#error "Unsupported build configuration." -#endif - -#include - -typedef pthread_mutex_t userland_mutex_t; -typedef pthread_rwlock_t userland_rwlock_t; -typedef pthread_cond_t userland_cond_t; -typedef pthread_t userland_thread_t; -#endif - -#if defined(_WIN32) || defined(__native_client__) - -#define IFNAMSIZ 64 - -#define random() rand() -#define srandom(s) srand(s) - -#define timeradd(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ - if ((vvp)->tv_usec >= 1000000) { \ - (vvp)->tv_sec++; \ - (vvp)->tv_usec -= 1000000; \ - } \ - } while (0) - -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) - -/*#include -#pragma pack(push, 1)*/ -struct ip { - u_char ip_hl:4, ip_v:4; - u_char ip_tos; - u_short ip_len; - u_short ip_id; - u_short ip_off; -#define IP_RP 0x8000 -#define IP_DF 0x4000 -#define IP_MF 0x2000 -#define IP_OFFMASK 0x1fff - u_char ip_ttl; - u_char ip_p; - u_short ip_sum; - struct in_addr ip_src, ip_dst; -}; - -struct ifaddrs { - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - struct sockaddr *ifa_dstaddr; - void *ifa_data; -}; - -struct udphdr { - uint16_t uh_sport; - uint16_t uh_dport; - uint16_t uh_ulen; - uint16_t uh_sum; -}; - -struct iovec { - size_t len; - char *buf; -}; - -#define iov_base buf -#define iov_len len - -struct ifa_msghdr { - uint16_t ifam_msglen; - unsigned char ifam_version; - unsigned char ifam_type; - uint32_t ifam_addrs; - uint32_t ifam_flags; - uint16_t ifam_index; - uint32_t ifam_metric; -}; - -struct ifdevmtu { - int ifdm_current; - int ifdm_min; - int ifdm_max; -}; - -struct ifkpi { - unsigned int ifk_module_id; - unsigned int ifk_type; - union { - void *ifk_ptr; - int ifk_value; - } ifk_data; -}; -#endif - -#if defined(_WIN32) -int Win_getifaddrs(struct ifaddrs**); -#define getifaddrs(interfaces) (int)Win_getifaddrs(interfaces) -int win_if_nametoindex(const char *); -#define if_nametoindex(x) win_if_nametoindex(x) -#endif - -#define mtx_lock(arg1) -#define mtx_unlock(arg1) -#define mtx_assert(arg1,arg2) -#define MA_OWNED 7 /* sys/mutex.h typically on FreeBSD */ -#if !defined(__FreeBSD__) -struct mtx {int dummy;}; -#if !defined(__NetBSD__) -struct selinfo {int dummy;}; -#endif -struct sx {int dummy;}; -#endif - -#include -#include -#include -/* #include in FreeBSD defines MSIZE */ -/* #include */ -/* #include */ -#if defined(HAVE_SYS_QUEUE_H) -#include -#else -#include -#endif -#include -/* #include */ -/* #include */ -/* #include */ -/* on FreeBSD, this results in a redefintion of SOCK(BUF)_(UN)LOCK and - * uknown type of struct mtx for sb_mtx in struct sockbuf */ -#include "user_socketvar.h" /* MALLOC_DECLARE's M_PCB. Replacement for sys/socketvar.h */ -/* #include */ -/* #include */ -#include -#include -#include -/* #include */ -/* #include */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -/* #include */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -/* #include */ -#include -/* #include */ - -#if defined(__APPLE__) -/* was a 0 byte file. needed for structs if_data(64) and net_event_data */ -#include -#endif -#if defined(__FreeBSD__) -#include -/* #include was a 0 byte file. causes struct mtx redefinition */ -#endif -/* OOTB only - dummy route used at the moment. should we port route to - * userspace as well? */ -/* on FreeBSD, this results in a redefintion of struct route */ -/* #include */ -#if !defined(_WIN32) && !defined(__native_client__) -#include -#include -#include -#include -#endif -#if defined(HAVE_NETINET_IP_ICMP_H) -#include -#else -#include -#endif -/* #include ported to userspace */ -#include - -/* for getifaddrs */ -#include -#if !defined(_WIN32) -#if defined(INET) || defined(INET6) -#include -#endif - -/* for ioctl */ -#include - -/* for close, etc. */ -#include -/* for gettimeofday */ -#include -#endif - -/* lots of errno's used and needed in userspace */ - -/* for offsetof */ -#include - -#if defined(SCTP_PROCESS_LEVEL_LOCKS) && !defined(_WIN32) -/* for pthread_mutex_lock, pthread_mutex_unlock, etc. */ -#include -#endif - -#ifdef IPSEC -#include -#include -#endif /* IPSEC */ - -#ifdef INET6 -#if defined(__FreeBSD__) -#include -#endif -#ifdef IPSEC -#include -#endif -#if !defined(_WIN32) -#include -#endif -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(_WIN32) || defined(__EMSCRIPTEN__) -#include "user_ip6_var.h" -#else -#include -#endif -#if defined(__FreeBSD__) -#include -#include -#endif -#endif /* INET6 */ - -#if defined(HAVE_SCTP_PEELOFF_SOCKOPT) -#include -#include -#endif - -#include "netinet/sctp_sha1.h" - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif - -#define SCTP_PRINTF(...) \ - if (SCTP_BASE_VAR(debug_printf)) { \ - SCTP_BASE_VAR(debug_printf)(__VA_ARGS__); \ - } - -/* Declare all the malloc names for all the various mallocs */ -MALLOC_DECLARE(SCTP_M_MAP); -MALLOC_DECLARE(SCTP_M_STRMI); -MALLOC_DECLARE(SCTP_M_STRMO); -MALLOC_DECLARE(SCTP_M_ASC_ADDR); -MALLOC_DECLARE(SCTP_M_ASC_IT); -MALLOC_DECLARE(SCTP_M_AUTH_CL); -MALLOC_DECLARE(SCTP_M_AUTH_KY); -MALLOC_DECLARE(SCTP_M_AUTH_HL); -MALLOC_DECLARE(SCTP_M_AUTH_IF); -MALLOC_DECLARE(SCTP_M_STRESET); -MALLOC_DECLARE(SCTP_M_CMSG); -MALLOC_DECLARE(SCTP_M_COPYAL); -MALLOC_DECLARE(SCTP_M_VRF); -MALLOC_DECLARE(SCTP_M_IFA); -MALLOC_DECLARE(SCTP_M_IFN); -MALLOC_DECLARE(SCTP_M_TIMW); -MALLOC_DECLARE(SCTP_M_MVRF); -MALLOC_DECLARE(SCTP_M_ITER); -MALLOC_DECLARE(SCTP_M_SOCKOPT); - -#if defined(SCTP_LOCAL_TRACE_BUF) - -#define SCTP_GET_CYCLECOUNT get_cyclecount() -#define SCTP_CTR6 sctp_log_trace - -#else -#define SCTP_CTR6 CTR6 -#endif - -/* Empty ktr statement for _Userspace__ (similar to what is done for mac) */ -#define CTR6(m, d, p1, p2, p3, p4, p5, p6) - - - -#define SCTP_BASE_INFO(__m) system_base_info.sctppcbinfo.__m -#define SCTP_BASE_STATS system_base_info.sctpstat -#define SCTP_BASE_STAT(__m) system_base_info.sctpstat.__m -#define SCTP_BASE_SYSCTL(__m) system_base_info.sctpsysctl.__m -#define SCTP_BASE_VAR(__m) system_base_info.__m - -/* - * - */ -#if !defined(__APPLE__) -#define USER_ADDR_NULL (NULL) /* FIX ME: temp */ -#endif - -#include -#if defined(SCTP_DEBUG) -#define SCTPDBG(level, ...) \ -{ \ - do { \ - if (SCTP_BASE_SYSCTL(sctp_debug_on) & level) { \ - SCTP_PRINTF(__VA_ARGS__); \ - } \ - } while (0); \ -} -#define SCTPDBG_ADDR(level, addr) \ -{ \ - do { \ - if (SCTP_BASE_SYSCTL(sctp_debug_on) & level ) { \ - sctp_print_address(addr); \ - } \ - } while (0); \ -} -#else -#define SCTPDBG(level, ...) -#define SCTPDBG_ADDR(level, addr) -#endif - -#ifdef SCTP_LTRACE_CHUNKS -#define SCTP_LTRACE_CHK(a, b, c, d) if(sctp_logging_level & SCTP_LTRACE_CHUNK_ENABLE) CTR6(KTR_SUBSYS, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_CHUNK_PROC, 0, a, b, c, d) -#else -#define SCTP_LTRACE_CHK(a, b, c, d) -#endif - -#ifdef SCTP_LTRACE_ERRORS -#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err) \ - if (sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) \ - SCTP_PRINTF("mbuf:%p inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \ - (void *)m, (void *)inp, (void *)stcb, (void *)net, file, __LINE__, err); -#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err) \ - if (sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) \ - SCTP_PRINTF("inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \ - (void *)inp, (void *)stcb, (void *)net, file, __LINE__, err); -#else -#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err) -#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err) -#endif - - -/* - * Local address and interface list handling - */ -#define SCTP_MAX_VRF_ID 0 -#define SCTP_SIZE_OF_VRF_HASH 3 -#define SCTP_IFNAMSIZ IFNAMSIZ -#define SCTP_DEFAULT_VRFID 0 -#define SCTP_VRF_ADDR_HASH_SIZE 16 -#define SCTP_VRF_IFN_HASH_SIZE 3 -#define SCTP_INIT_VRF_TABLEID(vrf) - -#if !defined(_WIN32) -#define SCTP_IFN_IS_IFT_LOOP(ifn) (strncmp((ifn)->ifn_name, "lo", 2) == 0) -/* BSD definition */ -/* #define SCTP_ROUTE_IS_REAL_LOOP(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifa && (ro)->ro_rt->rt_ifa->ifa_ifp && (ro)->ro_rt->rt_ifa->ifa_ifp->if_type == IFT_LOOP) */ -/* only used in IPv6 scenario, which isn't supported yet */ -#define SCTP_ROUTE_IS_REAL_LOOP(ro) 0 - -/* - * Access to IFN's to help with src-addr-selection - */ -/* This could return VOID if the index works but for BSD we provide both. */ -#define SCTP_GET_IFN_VOID_FROM_ROUTE(ro) (void *)ro->ro_rt->rt_ifp -#define SCTP_GET_IF_INDEX_FROM_ROUTE(ro) 1 /* compiles... TODO use routing socket to determine */ -#define SCTP_ROUTE_HAS_VALID_IFN(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifp) -#endif - -/* - * general memory allocation - */ -#define SCTP_MALLOC(var, type, size, name) \ - do { \ - MALLOC(var, type, size, name, M_NOWAIT); \ - } while (0) - -#define SCTP_FREE(var, type) FREE(var, type) - -#define SCTP_MALLOC_SONAME(var, type, size) \ - do { \ - MALLOC(var, type, size, M_SONAME, (M_WAITOK | M_ZERO)); \ - } while (0) - -#define SCTP_FREE_SONAME(var) FREE(var, M_SONAME) - -#define SCTP_PROCESS_STRUCT struct proc * - -/* - * zone allocation functions - */ - - -#if defined(SCTP_SIMPLE_ALLOCATOR) -/*typedef size_t sctp_zone_t;*/ -#define SCTP_ZONE_INIT(zone, name, size, number) { \ - zone = size; \ -} - -/* __Userspace__ SCTP_ZONE_GET: allocate element from the zone */ -#define SCTP_ZONE_GET(zone, type) \ - (type *)malloc(zone); - - -/* __Userspace__ SCTP_ZONE_FREE: free element from the zone */ -#define SCTP_ZONE_FREE(zone, element) { \ - free(element); \ -} - -#define SCTP_ZONE_DESTROY(zone) -#else -/*__Userspace__ - Compiling & linking notes: Needs libumem, which has been placed in ./user_lib - All userspace header files are in ./user_include. Makefile will need the - following. - CFLAGS = -I./ -Wall - LDFLAGS = -L./user_lib -R./user_lib -lumem -*/ -#include "user_include/umem.h" - -/* __Userspace__ SCTP_ZONE_INIT: initialize the zone */ -/* - __Userspace__ - No equivalent function to uma_zone_set_max added yet. (See SCTP_ZONE_INIT in sctp_os_bsd.h - for reference). It may not be required as mentioned in - http://nixdoc.net/man-pages/FreeBSD/uma_zalloc.9.html that - max limits may not enforced on systems with more than one CPU. -*/ -#define SCTP_ZONE_INIT(zone, name, size, number) { \ - zone = umem_cache_create(name, size, 0, NULL, NULL, NULL, NULL, NULL, 0); \ - } - -/* __Userspace__ SCTP_ZONE_GET: allocate element from the zone */ -#define SCTP_ZONE_GET(zone, type) \ - (type *)umem_cache_alloc(zone, UMEM_DEFAULT); - - -/* __Userspace__ SCTP_ZONE_FREE: free element from the zone */ -#define SCTP_ZONE_FREE(zone, element) \ - umem_cache_free(zone, element); - - -/* __Userspace__ SCTP_ZONE_DESTROY: destroy the zone */ -#define SCTP_ZONE_DESTROY(zone) \ - umem_cache_destroy(zone); -#endif - -/* - * __Userspace__ Defining sctp_hashinit_flags() and sctp_hashdestroy() for userland. - */ -void *sctp_hashinit_flags(int elements, struct malloc_type *type, - u_long *hashmask, int flags); -void -sctp_hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask); - -void -sctp_hashfreedestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask); - - -#define HASH_NOWAIT 0x00000001 -#define HASH_WAITOK 0x00000002 - -/* M_PCB is MALLOC_DECLARE'd in sys/socketvar.h */ -#define SCTP_HASH_INIT(size, hashmark) sctp_hashinit_flags(size, M_PCB, hashmark, HASH_NOWAIT) - -#define SCTP_HASH_FREE(table, hashmark) sctp_hashdestroy(table, M_PCB, hashmark) - -#define SCTP_HASH_FREE_DESTROY(table, hashmark) sctp_hashfreedestroy(table, M_PCB, hashmark) -#define SCTP_M_COPYM m_copym - -/* - * timers - */ -/* __Userspace__ - * user_sctp_callout.h has typedef struct sctp_callout sctp_os_timer_t; - * which is used in the timer related functions such as - * SCTP_OS_TIMER_INIT etc. -*/ -#include - -/* __Userspace__ Creating a receive thread */ -#include - -/*__Userspace__ defining KTR_SUBSYS 1 as done in sctp_os_macosx.h */ -#define KTR_SUBSYS 1 - -/* The packed define for 64 bit platforms */ -#if !defined(_WIN32) -#define SCTP_PACKED __attribute__((packed)) -#define SCTP_UNUSED __attribute__((unused)) -#else -#define SCTP_PACKED -#define SCTP_UNUSED -#endif - -/* - * Functions - */ -/* Mbuf manipulation and access macros */ -#define SCTP_BUF_LEN(m) (m->m_len) -#define SCTP_BUF_NEXT(m) (m->m_next) -#define SCTP_BUF_NEXT_PKT(m) (m->m_nextpkt) -#define SCTP_BUF_RESV_UF(m, size) m->m_data += size -#define SCTP_BUF_AT(m, size) m->m_data + size -#define SCTP_BUF_IS_EXTENDED(m) (m->m_flags & M_EXT) -#define SCTP_BUF_EXTEND_SIZE(m) (m->m_ext.ext_size) -#define SCTP_BUF_TYPE(m) (m->m_type) -#define SCTP_BUF_RECVIF(m) (m->m_pkthdr.rcvif) -#define SCTP_BUF_PREPEND M_PREPEND - -#define SCTP_ALIGN_TO_END(m, len) if(m->m_flags & M_PKTHDR) { \ - MH_ALIGN(m, len); \ - } else if ((m->m_flags & M_EXT) == 0) { \ - M_ALIGN(m, len); \ - } - -#if !defined(_WIN32) -#define SCTP_SNPRINTF(data, ...) \ - if (snprintf(data, __VA_ARGS__) < 0) { \ - data[0] = '\0'; \ - } -#endif - -/* We make it so if you have up to 4 threads - * writting based on the default size of - * the packet log 65 k, that would be - * 4 16k packets before we would hit - * a problem. - */ -#define SCTP_PKTLOG_WRITERS_NEED_LOCK 3 - - -/* - * routes, output, etc. - */ - -typedef struct sctp_route sctp_route_t; -typedef struct sctp_rtentry sctp_rtentry_t; - -static inline void sctp_userspace_rtalloc(sctp_route_t *ro) -{ - if (ro->ro_rt != NULL) { - ro->ro_rt->rt_refcnt++; - return; - } - - ro->ro_rt = (sctp_rtentry_t *) malloc(sizeof(sctp_rtentry_t)); - if (ro->ro_rt == NULL) - return; - - /* initialize */ - memset(ro->ro_rt, 0, sizeof(sctp_rtentry_t)); - ro->ro_rt->rt_refcnt = 1; - - /* set MTU */ - /* TODO set this based on the ro->ro_dst, looking up MTU with routing socket */ -#if 0 - if (userspace_rawroute == -1) { - userspace_rawroute = socket(AF_ROUTE, SOCK_RAW, 0); - if (userspace_rawroute == -1) - return; - } -#endif - ro->ro_rt->rt_rmx.rmx_mtu = 1500; /* FIXME temporary solution */ - - /* TODO enable the ability to obtain interface index of route for - * SCTP_GET_IF_INDEX_FROM_ROUTE macro. - */ -} -#define SCTP_RTALLOC(ro, vrf_id, fibnum) sctp_userspace_rtalloc((sctp_route_t *)ro) - -/* dummy rtfree needed once user_route.h is included */ -static inline void sctp_userspace_rtfree(sctp_rtentry_t *rt) -{ - if(rt == NULL) { - return; - } - if(--rt->rt_refcnt > 0) { - return; - } - free(rt); -} -#define rtfree(arg1) sctp_userspace_rtfree(arg1) - - -/*************************/ -/* MTU */ -/*************************/ -int sctp_userspace_get_mtu_from_ifn(uint32_t if_index); - -#define SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index) sctp_userspace_get_mtu_from_ifn(ifn_index) - -#define SCTP_GATHER_MTU_FROM_ROUTE(sctp_ifa, sa, rt) ((rt != NULL) ? rt->rt_rmx.rmx_mtu : 0) - -#define SCTP_SET_MTU_OF_ROUTE(sa, rt, mtu) do { \ - if (rt != NULL) \ - rt->rt_rmx.rmx_mtu = mtu; \ - } while(0) - - -/*************************/ -/* These are for logging */ -/*************************/ -/* return the base ext data pointer */ -#define SCTP_BUF_EXTEND_BASE(m) (m->m_ext.ext_buf) - /* return the refcnt of the data pointer */ -#define SCTP_BUF_EXTEND_REFCNT(m) (*m->m_ext.ref_cnt) -/* return any buffer related flags, this is - * used beyond logging for apple only. - */ -#define SCTP_BUF_GET_FLAGS(m) (m->m_flags) - -/* For BSD this just accesses the M_PKTHDR length - * so it operates on an mbuf with hdr flag. Other - * O/S's may have seperate packet header and mbuf - * chain pointers.. thus the macro. - */ -#define SCTP_HEADER_TO_CHAIN(m) (m) -#define SCTP_DETACH_HEADER_FROM_CHAIN(m) -#define SCTP_HEADER_LEN(m) ((m)->m_pkthdr.len) -#define SCTP_GET_HEADER_FOR_OUTPUT(o_pak) 0 -#define SCTP_RELEASE_HEADER(m) -#define SCTP_RELEASE_PKT(m) sctp_m_freem(m) - -#define SCTP_GET_PKT_VRFID(m, vrf_id) ((vrf_id = SCTP_DEFAULT_VRFID) != SCTP_DEFAULT_VRFID) - - - -/* Attach the chain of data into the sendable packet. */ -#define SCTP_ATTACH_CHAIN(pak, m, packet_length) do { \ - pak = m; \ - pak->m_pkthdr.len = packet_length; \ - } while(0) - -/* Other m_pkthdr type things */ -/* FIXME need real definitions */ -#define SCTP_IS_IT_BROADCAST(dst, m) 0 -/* OOTB only #define SCTP_IS_IT_BROADCAST(dst, m) ((m->m_flags & M_PKTHDR) ? in_broadcast(dst, m->m_pkthdr.rcvif) : 0) BSD def */ -#define SCTP_IS_IT_LOOPBACK(m) 0 -/* OOTB ONLY #define SCTP_IS_IT_LOOPBACK(m) ((m->m_flags & M_PKTHDR) && ((m->m_pkthdr.rcvif == NULL) || (m->m_pkthdr.rcvif->if_type == IFT_LOOP))) BSD def */ - - -/* This converts any input packet header - * into the chain of data holders, for BSD - * its a NOP. - */ - -/* get the v6 hop limit */ -#define SCTP_GET_HLIM(inp, ro) 128 -#define IPv6_HOP_LIMIT 128 - -/* is the endpoint v6only? */ -#define SCTP_IPV6_V6ONLY(sctp_inpcb) ((sctp_inpcb)->ip_inp.inp.inp_flags & IN6P_IPV6_V6ONLY) -/* is the socket non-blocking? */ -#define SCTP_SO_IS_NBIO(so) ((so)->so_state & SS_NBIO) -#define SCTP_SET_SO_NBIO(so) ((so)->so_state |= SS_NBIO) -#define SCTP_CLEAR_SO_NBIO(so) ((so)->so_state &= ~SS_NBIO) -/* get the socket type */ -#define SCTP_SO_TYPE(so) ((so)->so_type) - -/* reserve sb space for a socket */ -#define SCTP_SORESERVE(so, send, recv) soreserve(so, send, recv) - -/* wakeup a socket */ -#define SCTP_SOWAKEUP(so) wakeup(&(so)->so_timeo, so) -/* number of bytes ready to read */ -#define SCTP_SBAVAIL(sb) (sb)->sb_cc -#define SCTP_SB_INCR(sb, incr) \ -{ \ - atomic_add_int(&(sb)->sb_cc, incr); \ -} -#define SCTP_SB_DECR(sb, decr) \ -{ \ - SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, (int)(decr)); \ -} -/* clear the socket buffer state */ -#define SCTP_SB_CLEAR(sb) \ - (sb).sb_cc = 0; \ - (sb).sb_mb = NULL; \ - (sb).sb_mbcnt = 0; - -#define SCTP_SB_LIMIT_RCV(so) so->so_rcv.sb_hiwat -#define SCTP_SB_LIMIT_SND(so) so->so_snd.sb_hiwat - -#define SCTP_READ_RANDOM(buf, len) read_random(buf, len) - -#define SCTP_SHA1_CTX struct sctp_sha1_context -#define SCTP_SHA1_INIT sctp_sha1_init -#define SCTP_SHA1_UPDATE sctp_sha1_update -#define SCTP_SHA1_FINAL(x,y) sctp_sha1_final((unsigned char *)x, y) - -/* start OOTB only stuff */ -/* TODO IFT_LOOP is in net/if_types.h on Linux */ -#define IFT_LOOP 0x18 - -/* sctp_pcb.h */ - -#if defined(_WIN32) -#define SHUT_RD 1 -#define SHUT_WR 2 -#define SHUT_RDWR 3 -#endif -#define PRU_FLUSH_RD SHUT_RD -#define PRU_FLUSH_WR SHUT_WR -#define PRU_FLUSH_RDWR SHUT_RDWR - -/* netinet/ip_var.h defintions are behind an if defined for _KERNEL on FreeBSD */ -#define IP_RAWOUTPUT 0x2 - - -/* end OOTB only stuff */ - -#define AF_CONN 123 -struct sockaddr_conn { -#ifdef HAVE_SCONN_LEN - uint8_t sconn_len; - uint8_t sconn_family; -#else - uint16_t sconn_family; -#endif - uint16_t sconn_port; - void *sconn_addr; -}; - -typedef void *(*start_routine_t)(void *); - -extern int -sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine); - -void -sctp_userspace_set_threadname(const char *name); - -/* - * SCTP protocol specific mbuf flags. - */ -#define M_NOTIFICATION M_PROTO5 /* SCTP notification */ - -/* - * IP output routines - */ - -/* Defining SCTP_IP_ID macro. - In netinet/ip_output.c, we have u_short ip_id; - In netinet/ip_var.h, we have extern u_short ip_id; (enclosed within _KERNEL_) - See static __inline uint16_t ip_newid(void) in netinet/ip_var.h - */ -#define SCTP_IP_ID(inp) (ip_id) - -/* need sctphdr to get port in SCTP_IP_OUTPUT. sctphdr defined in sctp.h */ -#include -extern void sctp_userspace_ip_output(int *result, struct mbuf *o_pak, - sctp_route_t *ro, void *stcb, - uint32_t vrf_id); - -#define SCTP_IP_OUTPUT(result, o_pak, ro, inp, vrf_id) sctp_userspace_ip_output(&result, o_pak, ro, inp, vrf_id); - -#if defined(INET6) -extern void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, - struct route_in6 *ro, void *stcb, - uint32_t vrf_id); -#define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, inp, vrf_id) sctp_userspace_ip6_output(&result, o_pak, ro, inp, vrf_id); -#endif - - - -#if 0 -#define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, stcb, vrf_id) \ -{ \ - if (stcb && stcb->sctp_ep) \ - result = ip6_output(o_pak, \ - ((struct inpcb *)(stcb->sctp_ep))->in6p_outputopts, \ - (ro), 0, 0, ifp, NULL); \ - else \ - result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \ -} -#endif - -struct mbuf * -sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int allonebuf, int type); - - -/* with the current included files, this is defined in Linux but - * in FreeBSD, it is behind a _KERNEL in sys/socket.h ... - */ -#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__native_client__) -/* stolen from /usr/include/sys/socket.h */ -#define CMSG_ALIGN(n) _ALIGN(n) -#elif defined(__NetBSD__) -#define CMSG_ALIGN(n) (((n) + __ALIGNBYTES) & ~__ALIGNBYTES) -#elif defined(__APPLE__) -#if !defined(__DARWIN_ALIGNBYTES) -#define __DARWIN_ALIGNBYTES (sizeof(__darwin_size_t) - 1) -#endif - -#if !defined(__DARWIN_ALIGN) -#define __DARWIN_ALIGN(p) ((__darwin_size_t)((char *)(uintptr_t)(p) + __DARWIN_ALIGNBYTES) &~ __DARWIN_ALIGNBYTES) -#endif - -#if !defined(__DARWIN_ALIGNBYTES32) -#define __DARWIN_ALIGNBYTES32 (sizeof(__uint32_t) - 1) -#endif - -#if !defined(__DARWIN_ALIGN32) -#define __DARWIN_ALIGN32(p) ((__darwin_size_t)((char *)(uintptr_t)(p) + __DARWIN_ALIGNBYTES32) &~ __DARWIN_ALIGNBYTES32) -#endif -#define CMSG_ALIGN(n) __DARWIN_ALIGN32(n) -#endif -#define I_AM_HERE \ - do { \ - SCTP_PRINTF("%s:%d at %s\n", __FILE__, __LINE__ , __func__); \ - } while (0) - -#ifndef timevalsub -#define timevalsub(tp1, tp2) \ - do { \ - (tp1)->tv_sec -= (tp2)->tv_sec; \ - (tp1)->tv_usec -= (tp2)->tv_usec; \ - if ((tp1)->tv_usec < 0) { \ - (tp1)->tv_sec--; \ - (tp1)->tv_usec += 1000000; \ - } \ - } while (0) -#endif - -#if defined(__linux__) -#if !defined(TAILQ_FOREACH_SAFE) -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = ((head)->tqh_first); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) -#endif -#if !defined(LIST_FOREACH_SAFE) -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = ((head)->lh_first); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) -#endif -#endif -#if defined(__DragonFly__) -#define TAILQ_FOREACH_SAFE TAILQ_FOREACH_MUTABLE -#define LIST_FOREACH_SAFE LIST_FOREACH_MUTABLE -#endif - -#if defined(__native_client__) -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec == (uvp)->tv_sec) ? \ - ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ - ((tvp)->tv_sec cmp (uvp)->tv_sec)) -#endif - -#define SCTP_IS_LISTENING(inp) ((inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) != 0) - -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__linux__) || defined(__native_client__) || defined(__NetBSD__) || defined(_WIN32) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) -int -timingsafe_bcmp(const void *, const void *, size_t); -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.c deleted file mode 100644 index 5620a40a..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.c +++ /dev/null @@ -1,15088 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#if defined(__linux__) -#define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */ -#endif -#if defined(INET) || defined(INET6) -#if !defined(_WIN32) -#include -#endif -#endif -#if !defined(__Userspace__) -#if defined(__APPLE__) -#include -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#include -#endif -#endif -#if defined(__Userspace__) && defined(INET6) -#include -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#if !(defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)) -#define SCTP_MAX_LINKHDR 16 -#endif -#endif - -#define SCTP_MAX_GAPS_INARRAY 4 -struct sack_track { - uint8_t right_edge; /* mergable on the right edge */ - uint8_t left_edge; /* mergable on the left edge */ - uint8_t num_entries; - uint8_t spare; - struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY]; -}; - -const struct sack_track sack_array[256] = { - {0, 0, 0, 0, /* 0x00 */ - {{0, 0}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x01 */ - {{0, 0}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x02 */ - {{1, 1}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x03 */ - {{0, 1}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x04 */ - {{2, 2}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x05 */ - {{0, 0}, - {2, 2}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x06 */ - {{1, 2}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x07 */ - {{0, 2}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x08 */ - {{3, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x09 */ - {{0, 0}, - {3, 3}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x0a */ - {{1, 1}, - {3, 3}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x0b */ - {{0, 1}, - {3, 3}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x0c */ - {{2, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x0d */ - {{0, 0}, - {2, 3}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x0e */ - {{1, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x0f */ - {{0, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x10 */ - {{4, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x11 */ - {{0, 0}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x12 */ - {{1, 1}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x13 */ - {{0, 1}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x14 */ - {{2, 2}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x15 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x16 */ - {{1, 2}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x17 */ - {{0, 2}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x18 */ - {{3, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x19 */ - {{0, 0}, - {3, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x1a */ - {{1, 1}, - {3, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x1b */ - {{0, 1}, - {3, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x1c */ - {{2, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x1d */ - {{0, 0}, - {2, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x1e */ - {{1, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x1f */ - {{0, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x20 */ - {{5, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x21 */ - {{0, 0}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x22 */ - {{1, 1}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x23 */ - {{0, 1}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x24 */ - {{2, 2}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x25 */ - {{0, 0}, - {2, 2}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x26 */ - {{1, 2}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x27 */ - {{0, 2}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x28 */ - {{3, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x29 */ - {{0, 0}, - {3, 3}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x2a */ - {{1, 1}, - {3, 3}, - {5, 5}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x2b */ - {{0, 1}, - {3, 3}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x2c */ - {{2, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x2d */ - {{0, 0}, - {2, 3}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x2e */ - {{1, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x2f */ - {{0, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x30 */ - {{4, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x31 */ - {{0, 0}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x32 */ - {{1, 1}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x33 */ - {{0, 1}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x34 */ - {{2, 2}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x35 */ - {{0, 0}, - {2, 2}, - {4, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x36 */ - {{1, 2}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x37 */ - {{0, 2}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x38 */ - {{3, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x39 */ - {{0, 0}, - {3, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x3a */ - {{1, 1}, - {3, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x3b */ - {{0, 1}, - {3, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x3c */ - {{2, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x3d */ - {{0, 0}, - {2, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x3e */ - {{1, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x3f */ - {{0, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x40 */ - {{6, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x41 */ - {{0, 0}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x42 */ - {{1, 1}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x43 */ - {{0, 1}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x44 */ - {{2, 2}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x45 */ - {{0, 0}, - {2, 2}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x46 */ - {{1, 2}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x47 */ - {{0, 2}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x48 */ - {{3, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x49 */ - {{0, 0}, - {3, 3}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x4a */ - {{1, 1}, - {3, 3}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x4b */ - {{0, 1}, - {3, 3}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x4c */ - {{2, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x4d */ - {{0, 0}, - {2, 3}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x4e */ - {{1, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x4f */ - {{0, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x50 */ - {{4, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x51 */ - {{0, 0}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x52 */ - {{1, 1}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x53 */ - {{0, 1}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x54 */ - {{2, 2}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 4, 0, /* 0x55 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {6, 6} - } - }, - {0, 0, 3, 0, /* 0x56 */ - {{1, 2}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x57 */ - {{0, 2}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x58 */ - {{3, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x59 */ - {{0, 0}, - {3, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x5a */ - {{1, 1}, - {3, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x5b */ - {{0, 1}, - {3, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x5c */ - {{2, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x5d */ - {{0, 0}, - {2, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x5e */ - {{1, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x5f */ - {{0, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x60 */ - {{5, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x61 */ - {{0, 0}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x62 */ - {{1, 1}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x63 */ - {{0, 1}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x64 */ - {{2, 2}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x65 */ - {{0, 0}, - {2, 2}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x66 */ - {{1, 2}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x67 */ - {{0, 2}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x68 */ - {{3, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x69 */ - {{0, 0}, - {3, 3}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x6a */ - {{1, 1}, - {3, 3}, - {5, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x6b */ - {{0, 1}, - {3, 3}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x6c */ - {{2, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x6d */ - {{0, 0}, - {2, 3}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x6e */ - {{1, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x6f */ - {{0, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x70 */ - {{4, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x71 */ - {{0, 0}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x72 */ - {{1, 1}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x73 */ - {{0, 1}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x74 */ - {{2, 2}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x75 */ - {{0, 0}, - {2, 2}, - {4, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x76 */ - {{1, 2}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x77 */ - {{0, 2}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x78 */ - {{3, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x79 */ - {{0, 0}, - {3, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x7a */ - {{1, 1}, - {3, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x7b */ - {{0, 1}, - {3, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x7c */ - {{2, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x7d */ - {{0, 0}, - {2, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x7e */ - {{1, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x7f */ - {{0, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0x80 */ - {{7, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x81 */ - {{0, 0}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x82 */ - {{1, 1}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x83 */ - {{0, 1}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x84 */ - {{2, 2}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x85 */ - {{0, 0}, - {2, 2}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x86 */ - {{1, 2}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x87 */ - {{0, 2}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x88 */ - {{3, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x89 */ - {{0, 0}, - {3, 3}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x8a */ - {{1, 1}, - {3, 3}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x8b */ - {{0, 1}, - {3, 3}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x8c */ - {{2, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x8d */ - {{0, 0}, - {2, 3}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x8e */ - {{1, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x8f */ - {{0, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x90 */ - {{4, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x91 */ - {{0, 0}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x92 */ - {{1, 1}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x93 */ - {{0, 1}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x94 */ - {{2, 2}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0x95 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0x96 */ - {{1, 2}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x97 */ - {{0, 2}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x98 */ - {{3, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x99 */ - {{0, 0}, - {3, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x9a */ - {{1, 1}, - {3, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x9b */ - {{0, 1}, - {3, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x9c */ - {{2, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x9d */ - {{0, 0}, - {2, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x9e */ - {{1, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x9f */ - {{0, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xa0 */ - {{5, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xa1 */ - {{0, 0}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xa2 */ - {{1, 1}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xa3 */ - {{0, 1}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xa4 */ - {{2, 2}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xa5 */ - {{0, 0}, - {2, 2}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xa6 */ - {{1, 2}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xa7 */ - {{0, 2}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xa8 */ - {{3, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xa9 */ - {{0, 0}, - {3, 3}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 4, 0, /* 0xaa */ - {{1, 1}, - {3, 3}, - {5, 5}, - {7, 7} - } - }, - {1, 1, 4, 0, /* 0xab */ - {{0, 1}, - {3, 3}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xac */ - {{2, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xad */ - {{0, 0}, - {2, 3}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xae */ - {{1, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xaf */ - {{0, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xb0 */ - {{4, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb1 */ - {{0, 0}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xb2 */ - {{1, 1}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb3 */ - {{0, 1}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xb4 */ - {{2, 2}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xb5 */ - {{0, 0}, - {2, 2}, - {4, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xb6 */ - {{1, 2}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb7 */ - {{0, 2}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xb8 */ - {{3, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb9 */ - {{0, 0}, - {3, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xba */ - {{1, 1}, - {3, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xbb */ - {{0, 1}, - {3, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xbc */ - {{2, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xbd */ - {{0, 0}, - {2, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xbe */ - {{1, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xbf */ - {{0, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xc0 */ - {{6, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xc1 */ - {{0, 0}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc2 */ - {{1, 1}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xc3 */ - {{0, 1}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc4 */ - {{2, 2}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xc5 */ - {{0, 0}, - {2, 2}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc6 */ - {{1, 2}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xc7 */ - {{0, 2}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc8 */ - {{3, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xc9 */ - {{0, 0}, - {3, 3}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xca */ - {{1, 1}, - {3, 3}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xcb */ - {{0, 1}, - {3, 3}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xcc */ - {{2, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xcd */ - {{0, 0}, - {2, 3}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xce */ - {{1, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xcf */ - {{0, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xd0 */ - {{4, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd1 */ - {{0, 0}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xd2 */ - {{1, 1}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd3 */ - {{0, 1}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xd4 */ - {{2, 2}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xd5 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {6, 7} - } - }, - {0, 1, 3, 0, /* 0xd6 */ - {{1, 2}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd7 */ - {{0, 2}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xd8 */ - {{3, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd9 */ - {{0, 0}, - {3, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xda */ - {{1, 1}, - {3, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xdb */ - {{0, 1}, - {3, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xdc */ - {{2, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xdd */ - {{0, 0}, - {2, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xde */ - {{1, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xdf */ - {{0, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xe0 */ - {{5, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xe1 */ - {{0, 0}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe2 */ - {{1, 1}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xe3 */ - {{0, 1}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe4 */ - {{2, 2}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xe5 */ - {{0, 0}, - {2, 2}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe6 */ - {{1, 2}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xe7 */ - {{0, 2}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe8 */ - {{3, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xe9 */ - {{0, 0}, - {3, 3}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xea */ - {{1, 1}, - {3, 3}, - {5, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xeb */ - {{0, 1}, - {3, 3}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xec */ - {{2, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xed */ - {{0, 0}, - {2, 3}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xee */ - {{1, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xef */ - {{0, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xf0 */ - {{4, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf1 */ - {{0, 0}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xf2 */ - {{1, 1}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf3 */ - {{0, 1}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xf4 */ - {{2, 2}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xf5 */ - {{0, 0}, - {2, 2}, - {4, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xf6 */ - {{1, 2}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf7 */ - {{0, 2}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xf8 */ - {{3, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf9 */ - {{0, 0}, - {3, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xfa */ - {{1, 1}, - {3, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xfb */ - {{0, 1}, - {3, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xfc */ - {{2, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xfd */ - {{0, 0}, - {2, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xfe */ - {{1, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 1, 0, /* 0xff */ - {{0, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - } -}; - -int -sctp_is_address_in_scope(struct sctp_ifa *ifa, - struct sctp_scoping *scope, - int do_update) -{ - if ((scope->loopback_scope == 0) && - (ifa->ifn_p) && SCTP_IFN_IS_IFT_LOOP(ifa->ifn_p)) { - /* - * skip loopback if not in scope * - */ - return (0); - } - switch (ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (scope->ipv4_addr_legal) { - struct sockaddr_in *sin; - - sin = &ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - /* not in scope , unspecified */ - return (0); - } - if ((scope->ipv4_local_scope == 0) && - (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { - /* private address not in scope */ - return (0); - } - } else { - return (0); - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (scope->ipv6_addr_legal) { - struct sockaddr_in6 *sin6; - - /* Must update the flags, bummer, which - * means any IFA locks must now be applied HERE <-> - */ - if (do_update) { - sctp_gather_internal_ifa_flags(ifa); - } - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - return (0); - } - /* ok to use deprecated addresses? */ - sin6 = &ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* skip unspecified addresses */ - return (0); - } - if ( /* (local_scope == 0) && */ - (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { - return (0); - } - if ((scope->site_scope == 0) && - (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - return (0); - } - } else { - return (0); - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (!scope->conn_addr_legal) { - return (0); - } - break; -#endif - default: - return (0); - } - return (1); -} - -static struct mbuf * -sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len) -{ -#if defined(INET) || defined(INET6) - struct sctp_paramhdr *paramh; - struct mbuf *mret; - uint16_t plen; -#endif - - switch (ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - plen = (uint16_t)sizeof(struct sctp_ipv4addr_param); - break; -#endif -#ifdef INET6 - case AF_INET6: - plen = (uint16_t)sizeof(struct sctp_ipv6addr_param); - break; -#endif - default: - return (m); - } -#if defined(INET) || defined(INET6) - if (M_TRAILINGSPACE(m) >= plen) { - /* easy side we just drop it on the end */ - paramh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m))); - mret = m; - } else { - /* Need more space */ - mret = m; - while (SCTP_BUF_NEXT(mret) != NULL) { - mret = SCTP_BUF_NEXT(mret); - } - SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(plen, 0, M_NOWAIT, 1, MT_DATA); - if (SCTP_BUF_NEXT(mret) == NULL) { - /* We are hosed, can't add more addresses */ - return (m); - } - mret = SCTP_BUF_NEXT(mret); - paramh = mtod(mret, struct sctp_paramhdr *); - } - /* now add the parameter */ - switch (ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - { - struct sctp_ipv4addr_param *ipv4p; - struct sockaddr_in *sin; - - sin = &ifa->address.sin; - ipv4p = (struct sctp_ipv4addr_param *)paramh; - paramh->param_type = htons(SCTP_IPV4_ADDRESS); - paramh->param_length = htons(plen); - ipv4p->addr = sin->sin_addr.s_addr; - SCTP_BUF_LEN(mret) += plen; - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sctp_ipv6addr_param *ipv6p; - struct sockaddr_in6 *sin6; - - sin6 = &ifa->address.sin6; - ipv6p = (struct sctp_ipv6addr_param *)paramh; - paramh->param_type = htons(SCTP_IPV6_ADDRESS); - paramh->param_length = htons(plen); - memcpy(ipv6p->addr, &sin6->sin6_addr, - sizeof(ipv6p->addr)); -#if defined(SCTP_EMBEDDED_V6_SCOPE) - /* clear embedded scope in the address */ - in6_clearscope((struct in6_addr *)ipv6p->addr); -#endif - SCTP_BUF_LEN(mret) += plen; - break; - } -#endif - default: - return (m); - } - if (len != NULL) { - *len += plen; - } - return (mret); -#endif -} - -struct mbuf * -sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_scoping *scope, - struct mbuf *m_at, int cnt_inits_to, - uint16_t *padding_len, uint16_t *chunk_len) -{ - struct sctp_vrf *vrf = NULL; - int cnt, limit_out = 0, total_count; - uint32_t vrf_id; - - vrf_id = inp->def_vrf_id; - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - SCTP_IPI_ADDR_RUNLOCK(); - return (m_at); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - struct sctp_ifa *sctp_ifap; - struct sctp_ifn *sctp_ifnp; - - cnt = cnt_inits_to; - if (vrf->total_ifa_count > SCTP_COUNT_LIMIT) { - limit_out = 1; - cnt = SCTP_ADDRESS_LIMIT; - goto skip_count; - } - LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { - if ((scope->loopback_scope == 0) && - SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) { - /* - * Skip loopback devices if loopback_scope - * not set - */ - continue; - } - LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifap->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifap->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifap->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifap->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if (sctp_is_addr_restricted(stcb, sctp_ifap)) { - continue; - } -#if defined(__Userspace__) - if (sctp_ifap->address.sa.sa_family == AF_CONN) { - continue; - } -#endif - if (sctp_is_address_in_scope(sctp_ifap, scope, 1) == 0) { - continue; - } - cnt++; - if (cnt > SCTP_ADDRESS_LIMIT) { - break; - } - } - if (cnt > SCTP_ADDRESS_LIMIT) { - break; - } - } - skip_count: - if (cnt > 1) { - total_count = 0; - LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { - cnt = 0; - if ((scope->loopback_scope == 0) && - SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) { - /* - * Skip loopback devices if - * loopback_scope not set - */ - continue; - } - LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifap->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifap->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifap->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifap->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if (sctp_is_addr_restricted(stcb, sctp_ifap)) { - continue; - } -#if defined(__Userspace__) - if (sctp_ifap->address.sa.sa_family == AF_CONN) { - continue; - } -#endif - if (sctp_is_address_in_scope(sctp_ifap, - scope, 0) == 0) { - continue; - } - if ((chunk_len != NULL) && - (padding_len != NULL) && - (*padding_len > 0)) { - memset(mtod(m_at, caddr_t) + *chunk_len, 0, *padding_len); - SCTP_BUF_LEN(m_at) += *padding_len; - *chunk_len += *padding_len; - *padding_len = 0; - } - m_at = sctp_add_addr_to_mbuf(m_at, sctp_ifap, chunk_len); - if (limit_out) { - cnt++; - total_count++; - if (cnt >= 2) { - /* two from each address */ - break; - } - if (total_count > SCTP_ADDRESS_LIMIT) { - /* No more addresses */ - break; - } - } - } - } - } - } else { - struct sctp_laddr *laddr; - - cnt = cnt_inits_to; - /* First, how many ? */ - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - continue; - } - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) - /* Address being deleted by the system, dont - * list. - */ - continue; - if (laddr->action == SCTP_DEL_IP_ADDRESS) { - /* Address being deleted on this ep - * don't list. - */ - continue; - } -#if defined(__Userspace__) - if (laddr->ifa->address.sa.sa_family == AF_CONN) { - continue; - } -#endif - if (sctp_is_address_in_scope(laddr->ifa, - scope, 1) == 0) { - continue; - } - cnt++; - } - /* - * To get through a NAT we only list addresses if we have - * more than one. That way if you just bind a single address - * we let the source of the init dictate our address. - */ - if (cnt > 1) { - cnt = cnt_inits_to; - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - continue; - } - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { - continue; - } -#if defined(__Userspace__) - if (laddr->ifa->address.sa.sa_family == AF_CONN) { - continue; - } -#endif - if (sctp_is_address_in_scope(laddr->ifa, - scope, 0) == 0) { - continue; - } - if ((chunk_len != NULL) && - (padding_len != NULL) && - (*padding_len > 0)) { - memset(mtod(m_at, caddr_t) + *chunk_len, 0, *padding_len); - SCTP_BUF_LEN(m_at) += *padding_len; - *chunk_len += *padding_len; - *padding_len = 0; - } - m_at = sctp_add_addr_to_mbuf(m_at, laddr->ifa, chunk_len); - cnt++; - if (cnt >= SCTP_ADDRESS_LIMIT) { - break; - } - } - } - } - SCTP_IPI_ADDR_RUNLOCK(); - return (m_at); -} - -static struct sctp_ifa * -sctp_is_ifa_addr_preferred(struct sctp_ifa *ifa, - uint8_t dest_is_loop, - uint8_t dest_is_priv, - sa_family_t fam) -{ - uint8_t dest_is_global = 0; - /* dest_is_priv is true if destination is a private address */ - /* dest_is_loop is true if destination is a loopback addresses */ - - /** - * Here we determine if its a preferred address. A preferred address - * means it is the same scope or higher scope then the destination. - * L = loopback, P = private, G = global - * ----------------------------------------- - * src | dest | result - * ---------------------------------------- - * L | L | yes - * ----------------------------------------- - * P | L | yes-v4 no-v6 - * ----------------------------------------- - * G | L | yes-v4 no-v6 - * ----------------------------------------- - * L | P | no - * ----------------------------------------- - * P | P | yes - * ----------------------------------------- - * G | P | no - * ----------------------------------------- - * L | G | no - * ----------------------------------------- - * P | G | no - * ----------------------------------------- - * G | G | yes - * ----------------------------------------- - */ - - if (ifa->address.sa.sa_family != fam) { - /* forget mis-matched family */ - return (NULL); - } - if ((dest_is_priv == 0) && (dest_is_loop == 0)) { - dest_is_global = 1; - } - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Is destination preferred:"); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ifa->address.sa); - /* Ok the address may be ok */ -#ifdef INET6 - if (fam == AF_INET6) { - /* ok to use deprecated addresses? no lets not! */ - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:1\n"); - return (NULL); - } - if (ifa->src_is_priv && !ifa->src_is_loop) { - if (dest_is_loop) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2\n"); - return (NULL); - } - } - if (ifa->src_is_glob) { - if (dest_is_loop) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:3\n"); - return (NULL); - } - } - } -#endif - /* Now that we know what is what, implement or table - * this could in theory be done slicker (it used to be), but this - * is straightforward and easier to validate :-) - */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "src_loop:%d src_priv:%d src_glob:%d\n", - ifa->src_is_loop, ifa->src_is_priv, ifa->src_is_glob); - SCTPDBG(SCTP_DEBUG_OUTPUT3, "dest_loop:%d dest_priv:%d dest_glob:%d\n", - dest_is_loop, dest_is_priv, dest_is_global); - - if ((ifa->src_is_loop) && (dest_is_priv)) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:4\n"); - return (NULL); - } - if ((ifa->src_is_glob) && (dest_is_priv)) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:5\n"); - return (NULL); - } - if ((ifa->src_is_loop) && (dest_is_global)) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:6\n"); - return (NULL); - } - if ((ifa->src_is_priv) && (dest_is_global)) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:7\n"); - return (NULL); - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "YES\n"); - /* its a preferred address */ - return (ifa); -} - -static struct sctp_ifa * -sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa, - uint8_t dest_is_loop, - uint8_t dest_is_priv, - sa_family_t fam) -{ - uint8_t dest_is_global = 0; - - /** - * Here we determine if its a acceptable address. A acceptable - * address means it is the same scope or higher scope but we can - * allow for NAT which means its ok to have a global dest and a - * private src. - * - * L = loopback, P = private, G = global - * ----------------------------------------- - * src | dest | result - * ----------------------------------------- - * L | L | yes - * ----------------------------------------- - * P | L | yes-v4 no-v6 - * ----------------------------------------- - * G | L | yes - * ----------------------------------------- - * L | P | no - * ----------------------------------------- - * P | P | yes - * ----------------------------------------- - * G | P | yes - May not work - * ----------------------------------------- - * L | G | no - * ----------------------------------------- - * P | G | yes - May not work - * ----------------------------------------- - * G | G | yes - * ----------------------------------------- - */ - - if (ifa->address.sa.sa_family != fam) { - /* forget non matching family */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa_fam:%d fam:%d\n", - ifa->address.sa.sa_family, fam); - return (NULL); - } - /* Ok the address may be ok */ - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, &ifa->address.sa); - SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst_is_loop:%d dest_is_priv:%d\n", - dest_is_loop, dest_is_priv); - if ((dest_is_loop == 0) && (dest_is_priv == 0)) { - dest_is_global = 1; - } -#ifdef INET6 - if (fam == AF_INET6) { - /* ok to use deprecated addresses? */ - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - return (NULL); - } - if (ifa->src_is_priv) { - /* Special case, linklocal to loop */ - if (dest_is_loop) - return (NULL); - } - } -#endif - /* - * Now that we know what is what, implement our table. - * This could in theory be done slicker (it used to be), but this - * is straightforward and easier to validate :-) - */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_priv:%d\n", - ifa->src_is_loop, - dest_is_priv); - if ((ifa->src_is_loop == 1) && (dest_is_priv)) { - return (NULL); - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_glob:%d\n", - ifa->src_is_loop, - dest_is_global); - if ((ifa->src_is_loop == 1) && (dest_is_global)) { - return (NULL); - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "address is acceptable\n"); - /* its an acceptable address */ - return (ifa); -} - -int -sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) -{ - struct sctp_laddr *laddr; - - if (stcb == NULL) { - /* There are no restrictions, no TCB :-) */ - return (0); - } - LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", - __func__); - continue; - } - if (laddr->ifa == ifa) { - /* Yes it is on the list */ - return (1); - } - } - return (0); -} - -int -sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa) -{ - struct sctp_laddr *laddr; - - if (ifa == NULL) - return (0); - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", - __func__); - continue; - } - if ((laddr->ifa == ifa) && laddr->action == 0) - /* same pointer */ - return (1); - } - return (0); -} - -static struct sctp_ifa * -sctp_choose_boundspecific_inp(struct sctp_inpcb *inp, - sctp_route_t *ro, - uint32_t vrf_id, - int non_asoc_addr_ok, - uint8_t dest_is_priv, - uint8_t dest_is_loop, - sa_family_t fam) -{ - struct sctp_laddr *laddr, *starting_point; - void *ifn; - int resettotop = 0; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa, *sifa; - struct sctp_vrf *vrf; - uint32_t ifn_index; - - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) - return (NULL); - - ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); - ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); - sctp_ifn = sctp_find_ifn(ifn, ifn_index); - /* - * first question, is the ifn we will emit on in our list, if so, we - * want such an address. Note that we first looked for a - * preferred address. - */ - if (sctp_ifn) { - /* is a preferred one on the interface we route out? */ - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) - continue; - sifa = sctp_is_ifa_addr_preferred(sctp_ifa, - dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) - continue; - if (sctp_is_addr_in_ep(inp, sifa)) { - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - } - } - /* - * ok, now we now need to find one on the list of the addresses. - * We can't get one on the emitting interface so let's find first - * a preferred one. If not that an acceptable one otherwise... - * we return NULL. - */ - starting_point = inp->next_addr_touse; - once_again: - if (inp->next_addr_touse == NULL) { - inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list); - resettotop = 1; - } - for (laddr = inp->next_addr_touse; laddr; - laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { - if (laddr->ifa == NULL) { - /* address has been removed */ - continue; - } - if (laddr->action == SCTP_DEL_IP_ADDRESS) { - /* address is being deleted */ - continue; - } - sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) - continue; - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - if (resettotop == 0) { - inp->next_addr_touse = NULL; - goto once_again; - } - - inp->next_addr_touse = starting_point; - resettotop = 0; - once_again_too: - if (inp->next_addr_touse == NULL) { - inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list); - resettotop = 1; - } - - /* ok, what about an acceptable address in the inp */ - for (laddr = inp->next_addr_touse; laddr; - laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { - if (laddr->ifa == NULL) { - /* address has been removed */ - continue; - } - if (laddr->action == SCTP_DEL_IP_ADDRESS) { - /* address is being deleted */ - continue; - } - sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) - continue; - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - if (resettotop == 0) { - inp->next_addr_touse = NULL; - goto once_again_too; - } - - /* - * no address bound can be a source for the destination we are in - * trouble - */ - return (NULL); -} - -static struct sctp_ifa * -sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - sctp_route_t *ro, - uint32_t vrf_id, - uint8_t dest_is_priv, - uint8_t dest_is_loop, - int non_asoc_addr_ok, - sa_family_t fam) -{ - struct sctp_laddr *laddr, *starting_point; - void *ifn; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa, *sifa; - uint8_t start_at_beginning = 0; - struct sctp_vrf *vrf; - uint32_t ifn_index; - - /* - * first question, is the ifn we will emit on in our list, if so, we - * want that one. - */ - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) - return (NULL); - - ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); - ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); - sctp_ifn = sctp_find_ifn(ifn, ifn_index); - - /* - * first question, is the ifn we will emit on in our list? If so, - * we want that one. First we look for a preferred. Second, we go - * for an acceptable. - */ - if (sctp_ifn) { - /* first try for a preferred address on the ep */ - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) - continue; - if (sctp_is_addr_in_ep(inp, sctp_ifa)) { - sifa = sctp_is_ifa_addr_preferred(sctp_ifa, dest_is_loop, dest_is_priv, fam); - if (sifa == NULL) - continue; - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* on the no-no list */ - continue; - } - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - } - /* next try for an acceptable address on the ep */ - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) - continue; - if (sctp_is_addr_in_ep(inp, sctp_ifa)) { - sifa= sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv,fam); - if (sifa == NULL) - continue; - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* on the no-no list */ - continue; - } - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - } - } - /* - * if we can't find one like that then we must look at all - * addresses bound to pick one at first preferable then - * secondly acceptable. - */ - starting_point = stcb->asoc.last_used_address; - sctp_from_the_top: - if (stcb->asoc.last_used_address == NULL) { - start_at_beginning = 1; - stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list); - } - /* search beginning with the last used address */ - for (laddr = stcb->asoc.last_used_address; laddr; - laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { - if (laddr->ifa == NULL) { - /* address has been removed */ - continue; - } - if (laddr->action == SCTP_DEL_IP_ADDRESS) { - /* address is being deleted */ - continue; - } - sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam); - if (sifa == NULL) - continue; - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* on the no-no list */ - continue; - } - stcb->asoc.last_used_address = laddr; - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - if (start_at_beginning == 0) { - stcb->asoc.last_used_address = NULL; - goto sctp_from_the_top; - } - /* now try for any higher scope than the destination */ - stcb->asoc.last_used_address = starting_point; - start_at_beginning = 0; - sctp_from_the_top2: - if (stcb->asoc.last_used_address == NULL) { - start_at_beginning = 1; - stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list); - } - /* search beginning with the last used address */ - for (laddr = stcb->asoc.last_used_address; laddr; - laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { - if (laddr->ifa == NULL) { - /* address has been removed */ - continue; - } - if (laddr->action == SCTP_DEL_IP_ADDRESS) { - /* address is being deleted */ - continue; - } - sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) - continue; - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* on the no-no list */ - continue; - } - stcb->asoc.last_used_address = laddr; - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } - if (start_at_beginning == 0) { - stcb->asoc.last_used_address = NULL; - goto sctp_from_the_top2; - } - return (NULL); -} - -static struct sctp_ifa * -sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct sctp_inpcb *inp, -#else - struct sctp_inpcb *inp SCTP_UNUSED, -#endif - struct sctp_tcb *stcb, - int non_asoc_addr_ok, - uint8_t dest_is_loop, - uint8_t dest_is_priv, - int addr_wanted, - sa_family_t fam, - sctp_route_t *ro) -{ - struct sctp_ifa *ifa, *sifa; - int num_eligible_addr = 0; -#ifdef INET6 -#ifdef SCTP_EMBEDDED_V6_SCOPE - struct sockaddr_in6 sin6, lsa6; - - if (fam == AF_INET6) { - memcpy(&sin6, &ro->ro_dst, sizeof(struct sockaddr_in6)); -#ifdef SCTP_KAME - (void)sa6_recoverscope(&sin6); -#else - (void)in6_recoverscope(&sin6, &sin6.sin6_addr, NULL); -#endif /* SCTP_KAME */ - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#endif /* INET6 */ - LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) - continue; - sifa = sctp_is_ifa_addr_preferred(ifa, dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) - continue; -#ifdef INET6 - if (fam == AF_INET6 && - dest_is_loop && - sifa->src_is_loop && sifa->src_is_priv) { - /* don't allow fe80::1 to be a src on loop ::1, we don't list it - * to the peer so we will get an abort. - */ - continue; - } -#ifdef SCTP_EMBEDDED_V6_SCOPE - if (fam == AF_INET6 && - IN6_IS_ADDR_LINKLOCAL(&sifa->address.sin6.sin6_addr) && - IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { - /* link-local <-> link-local must belong to the same scope. */ - memcpy(&lsa6, &sifa->address.sin6, sizeof(struct sockaddr_in6)); -#ifdef SCTP_KAME - (void)sa6_recoverscope(&lsa6); -#else - (void)in6_recoverscope(&lsa6, &lsa6.sin6_addr, NULL); -#endif /* SCTP_KAME */ - if (sin6.sin6_scope_id != lsa6.sin6_scope_id) { - continue; - } - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#endif /* INET6 */ - -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) - /* Check if the IPv6 address matches to next-hop. - In the mobile case, old IPv6 address may be not deleted - from the interface. Then, the interface has previous and - new addresses. We should use one corresponding to the - next-hop. (by micchie) - */ -#ifdef INET6 - if (stcb && fam == AF_INET6 && - sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { - if (sctp_v6src_match_nexthop(&sifa->address.sin6, ro) == 0) { - continue; - } - } -#endif -#ifdef INET - /* Avoid topologically incorrect IPv4 address */ - if (stcb && fam == AF_INET && - sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { - if (sctp_v4src_match_nexthop(sifa, ro) == 0) { - continue; - } - } -#endif -#endif - if (stcb) { - if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { - continue; - } - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* - * It is restricted for some reason.. - * probably not yet added. - */ - continue; - } - } - if (num_eligible_addr >= addr_wanted) { - return (sifa); - } - num_eligible_addr++; - } - return (NULL); -} - -static int -sctp_count_num_preferred_boundall(struct sctp_ifn *ifn, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct sctp_inpcb *inp, -#else - struct sctp_inpcb *inp SCTP_UNUSED, -#endif - struct sctp_tcb *stcb, - int non_asoc_addr_ok, - uint8_t dest_is_loop, - uint8_t dest_is_priv, - sa_family_t fam) -{ - struct sctp_ifa *ifa, *sifa; - int num_eligible_addr = 0; - - LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((ifa->address.sa.sa_family == AF_INET6) && - (stcb != NULL) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) { - continue; - } - sifa = sctp_is_ifa_addr_preferred(ifa, dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) { - continue; - } - if (stcb) { - if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { - continue; - } - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* - * It is restricted for some reason.. - * probably not yet added. - */ - continue; - } - } - num_eligible_addr++; - } - return (num_eligible_addr); -} - -static struct sctp_ifa * -sctp_choose_boundall(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net, - sctp_route_t *ro, - uint32_t vrf_id, - uint8_t dest_is_priv, - uint8_t dest_is_loop, - int non_asoc_addr_ok, - sa_family_t fam) -{ - int cur_addr_num = 0, num_preferred = 0; - void *ifn; - struct sctp_ifn *sctp_ifn, *looked_at = NULL, *emit_ifn; - struct sctp_ifa *sctp_ifa, *sifa; - uint32_t ifn_index; - struct sctp_vrf *vrf; -#ifdef INET - int retried = 0; -#endif - - /*- - * For boundall we can use any address in the association. - * If non_asoc_addr_ok is set we can use any address (at least in - * theory). So we look for preferred addresses first. If we find one, - * we use it. Otherwise we next try to get an address on the - * interface, which we should be able to do (unless non_asoc_addr_ok - * is false and we are routed out that way). In these cases where we - * can't use the address of the interface we go through all the - * ifn's looking for an address we can use and fill that in. Punting - * means we send back address 0, which will probably cause problems - * actually since then IP will fill in the address of the route ifn, - * which means we probably already rejected it.. i.e. here comes an - * abort :-<. - */ - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) - return (NULL); - - ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); - ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); - SCTPDBG(SCTP_DEBUG_OUTPUT2,"ifn from route:%p ifn_index:%d\n", ifn, ifn_index); - emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index); - if (sctp_ifn == NULL) { - /* ?? We don't have this guy ?? */ - SCTPDBG(SCTP_DEBUG_OUTPUT2,"No ifn emit interface?\n"); - goto bound_all_plan_b; - } - SCTPDBG(SCTP_DEBUG_OUTPUT2,"ifn_index:%d name:%s is emit interface\n", - ifn_index, sctp_ifn->ifn_name); - - if (net) { - cur_addr_num = net->indx_of_eligible_next_to_use; - } - num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, - inp, stcb, - non_asoc_addr_ok, - dest_is_loop, - dest_is_priv, fam); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses for intf:%s\n", - num_preferred, sctp_ifn->ifn_name); - if (num_preferred == 0) { - /* - * no eligible addresses, we must use some other interface - * address if we can find one. - */ - goto bound_all_plan_b; - } - /* - * Ok we have num_eligible_addr set with how many we can use, this - * may vary from call to call due to addresses being deprecated - * etc.. - */ - if (cur_addr_num >= num_preferred) { - cur_addr_num = 0; - } - /* - * select the nth address from the list (where cur_addr_num is the - * nth) and 0 is the first one, 1 is the second one etc... - */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "cur_addr_num:%d\n", cur_addr_num); - - sctp_ifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, dest_is_loop, - dest_is_priv, cur_addr_num, fam, ro); - - /* if sctp_ifa is NULL something changed??, fall to plan b. */ - if (sctp_ifa) { - atomic_add_int(&sctp_ifa->refcount, 1); - if (net) { - /* save off where the next one we will want */ - net->indx_of_eligible_next_to_use = cur_addr_num + 1; - } - return (sctp_ifa); - } - /* - * plan_b: Look at all interfaces and find a preferred address. If - * no preferred fall through to plan_c. - */ - bound_all_plan_b: - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan B\n"); - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Examine interface %s\n", - sctp_ifn->ifn_name); - if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* wrong base scope */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "skip\n"); - continue; - } - if ((sctp_ifn == looked_at) && looked_at) { - /* already looked at this guy */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "already seen\n"); - continue; - } - num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, - dest_is_loop, dest_is_priv, fam); - SCTPDBG(SCTP_DEBUG_OUTPUT2, - "Found ifn:%p %d preferred source addresses\n", - ifn, num_preferred); - if (num_preferred == 0) { - /* None on this interface. */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "No preferred -- skipping to next\n"); - continue; - } - SCTPDBG(SCTP_DEBUG_OUTPUT2, - "num preferred:%d on interface:%p cur_addr_num:%d\n", - num_preferred, (void *)sctp_ifn, cur_addr_num); - - /* - * Ok we have num_eligible_addr set with how many we can - * use, this may vary from call to call due to addresses - * being deprecated etc.. - */ - if (cur_addr_num >= num_preferred) { - cur_addr_num = 0; - } - sifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, dest_is_loop, - dest_is_priv, cur_addr_num, fam, ro); - if (sifa == NULL) - continue; - if (net) { - net->indx_of_eligible_next_to_use = cur_addr_num + 1; - SCTPDBG(SCTP_DEBUG_OUTPUT2, "we selected %d\n", - cur_addr_num); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Source:"); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Dest:"); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &net->ro._l_addr.sa); - } - atomic_add_int(&sifa->refcount, 1); - return (sifa); - } -#ifdef INET -again_with_private_addresses_allowed: -#endif - /* plan_c: do we have an acceptable address on the emit interface */ - sifa = NULL; - SCTPDBG(SCTP_DEBUG_OUTPUT2,"Trying Plan C: find acceptable on interface\n"); - if (emit_ifn == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT2,"Jump to Plan D - no emit_ifn\n"); - goto plan_d; - } - LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) { - SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifa:%p\n", (void *)sctp_ifa); -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin.sin_addr) != 0)) { - SCTPDBG(SCTP_DEBUG_OUTPUT2,"Jailed\n"); - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin6.sin6_addr) != 0)) { - SCTPDBG(SCTP_DEBUG_OUTPUT2,"Jailed\n"); - continue; - } -#endif -#endif - if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) { - SCTPDBG(SCTP_DEBUG_OUTPUT2,"Defer\n"); - continue; - } - sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT2, "IFA not acceptable\n"); - continue; - } - if (stcb) { - if (sctp_is_address_in_scope(sifa, &stcb->asoc.scope, 0) == 0) { - SCTPDBG(SCTP_DEBUG_OUTPUT2, "NOT in scope\n"); - sifa = NULL; - continue; - } - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* - * It is restricted for some - * reason.. probably not yet added. - */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its restricted\n"); - sifa = NULL; - continue; - } - } - atomic_add_int(&sifa->refcount, 1); - goto out; - } - plan_d: - /* - * plan_d: We are in trouble. No preferred address on the emit - * interface. And not even a preferred address on all interfaces. - * Go out and see if we can find an acceptable address somewhere - * amongst all interfaces. - */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D looked_at is %p\n", (void *)looked_at); - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* wrong base scope */ - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) - continue; - sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, - dest_is_loop, - dest_is_priv, fam); - if (sifa == NULL) - continue; - if (stcb) { - if (sctp_is_address_in_scope(sifa, &stcb->asoc.scope, 0) == 0) { - sifa = NULL; - continue; - } - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, sifa)) && - (!sctp_is_addr_pending(stcb, sifa)))) { - /* - * It is restricted for some - * reason.. probably not yet added. - */ - sifa = NULL; - continue; - } - } - goto out; - } - } -#ifdef INET - if (stcb) { - if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) { - stcb->asoc.scope.ipv4_local_scope = 1; - retried = 1; - goto again_with_private_addresses_allowed; - } else if (retried == 1) { - stcb->asoc.scope.ipv4_local_scope = 0; - } - } -#endif -out: -#ifdef INET - if (sifa) { - if (retried == 1) { - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* wrong base scope */ - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - struct sctp_ifa *tmp_sifa; - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - if ((sctp_ifa->address.sa.sa_family == AF_INET) && - (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin.sin_addr) != 0)) { - continue; - } -#endif -#ifdef INET6 - if ((sctp_ifa->address.sa.sa_family == AF_INET6) && - (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sctp_ifa->address.sin6.sin6_addr) != 0)) { - continue; - } -#endif -#endif - if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) - continue; - tmp_sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, - dest_is_loop, - dest_is_priv, fam); - if (tmp_sifa == NULL) { - continue; - } - if (tmp_sifa == sifa) { - continue; - } - if (stcb) { - if (sctp_is_address_in_scope(tmp_sifa, - &stcb->asoc.scope, 0) == 0) { - continue; - } - if (((non_asoc_addr_ok == 0) && - (sctp_is_addr_restricted(stcb, tmp_sifa))) || - (non_asoc_addr_ok && - (sctp_is_addr_restricted(stcb, tmp_sifa)) && - (!sctp_is_addr_pending(stcb, tmp_sifa)))) { - /* - * It is restricted for some - * reason.. probably not yet added. - */ - continue; - } - } - if ((tmp_sifa->address.sin.sin_family == AF_INET) && - (IN4_ISPRIVATE_ADDRESS(&(tmp_sifa->address.sin.sin_addr)))) { - sctp_add_local_addr_restricted(stcb, tmp_sifa); - } - } - } - } - atomic_add_int(&sifa->refcount, 1); - } -#endif - return (sifa); -} - -/* tcb may be NULL */ -struct sctp_ifa * -sctp_source_address_selection(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - sctp_route_t *ro, - struct sctp_nets *net, - int non_asoc_addr_ok, uint32_t vrf_id) -{ - struct sctp_ifa *answer; - uint8_t dest_is_priv, dest_is_loop; - sa_family_t fam; -#ifdef INET - struct sockaddr_in *to = (struct sockaddr_in *)&ro->ro_dst; -#endif -#ifdef INET6 - struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ro->ro_dst; -#endif - - /** - * Rules: - * - Find the route if needed, cache if I can. - * - Look at interface address in route, Is it in the bound list. If so we - * have the best source. - * - If not we must rotate amongst the addresses. - * - * Caveats and issues - * - * Do we need to pay attention to scope. We can have a private address - * or a global address we are sourcing or sending to. So if we draw - * it out - * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - * For V4 - * ------------------------------------------ - * source * dest * result - * ----------------------------------------- - * Private * Global * NAT - * ----------------------------------------- - * Private * Private * No problem - * ----------------------------------------- - * Global * Private * Huh, How will this work? - * ----------------------------------------- - * Global * Global * No Problem - *------------------------------------------ - * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - * For V6 - *------------------------------------------ - * source * dest * result - * ----------------------------------------- - * Linklocal * Global * - * ----------------------------------------- - * Linklocal * Linklocal * No problem - * ----------------------------------------- - * Global * Linklocal * Huh, How will this work? - * ----------------------------------------- - * Global * Global * No Problem - *------------------------------------------ - * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - * - * And then we add to that what happens if there are multiple addresses - * assigned to an interface. Remember the ifa on a ifn is a linked - * list of addresses. So one interface can have more than one IP - * address. What happens if we have both a private and a global - * address? Do we then use context of destination to sort out which - * one is best? And what about NAT's sending P->G may get you a NAT - * translation, or should you select the G thats on the interface in - * preference. - * - * Decisions: - * - * - count the number of addresses on the interface. - * - if it is one, no problem except case . - * For we will assume a NAT out there. - * - if there are more than one, then we need to worry about scope P - * or G. We should prefer G -> G and P -> P if possible. - * Then as a secondary fall back to mixed types G->P being a last - * ditch one. - * - The above all works for bound all, but bound specific we need to - * use the same concept but instead only consider the bound - * addresses. If the bound set is NOT assigned to the interface then - * we must use rotation amongst the bound addresses.. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (ro->ro_nh == NULL) { -#else - if (ro->ro_rt == NULL) { -#endif - /* - * Need a route to cache. - */ - SCTP_RTALLOC(ro, vrf_id, inp->fibnum); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (ro->ro_nh == NULL) { -#else - if (ro->ro_rt == NULL) { -#endif - return (NULL); - } -#if defined(_WIN32) - /* On Windows the sa_family is U_SHORT or ADDRESS_FAMILY */ - fam = (sa_family_t)ro->ro_dst.sa_family; -#else - fam = ro->ro_dst.sa_family; -#endif - dest_is_priv = dest_is_loop = 0; - /* Setup our scopes for the destination */ - switch (fam) { -#ifdef INET - case AF_INET: - /* Scope based on outbound address */ - if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { - dest_is_loop = 1; - if (net != NULL) { - /* mark it as local */ - net->addr_is_local = 1; - } - } else if ((IN4_ISPRIVATE_ADDRESS(&to->sin_addr))) { - dest_is_priv = 1; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - /* Scope based on outbound address */ -#if defined(_WIN32) - if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { -#else - if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr) || - SCTP_ROUTE_IS_REAL_LOOP(ro)) { -#endif - /* - * If the address is a loopback address, which - * consists of "::1" OR "fe80::1%lo0", we are loopback - * scope. But we don't use dest_is_priv (link local - * addresses). - */ - dest_is_loop = 1; - if (net != NULL) { - /* mark it as local */ - net->addr_is_local = 1; - } - } else if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { - dest_is_priv = 1; - } - break; -#endif - } - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Select source addr for:"); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&ro->ro_dst); - SCTP_IPI_ADDR_RLOCK(); - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* - * Bound all case - */ - answer = sctp_choose_boundall(inp, stcb, net, ro, vrf_id, - dest_is_priv, dest_is_loop, - non_asoc_addr_ok, fam); - SCTP_IPI_ADDR_RUNLOCK(); - return (answer); - } - /* - * Subset bound case - */ - if (stcb) { - answer = sctp_choose_boundspecific_stcb(inp, stcb, ro, - vrf_id, dest_is_priv, - dest_is_loop, - non_asoc_addr_ok, fam); - } else { - answer = sctp_choose_boundspecific_inp(inp, ro, vrf_id, - non_asoc_addr_ok, - dest_is_priv, - dest_is_loop, fam); - } - SCTP_IPI_ADDR_RUNLOCK(); - return (answer); -} - -static bool -sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) -{ -#if defined(_WIN32) - WSACMSGHDR cmh; -#else - struct cmsghdr cmh; -#endif - struct sctp_sndinfo sndinfo; - struct sctp_prinfo prinfo; - struct sctp_authinfo authinfo; - int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; - bool found; - - /* - * Independent of how many mbufs, find the c_type inside the control - * structure and copy out the data. - */ - found = false; - tot_len = SCTP_BUF_LEN(control); - for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { - rem_len = tot_len - off; - if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { - /* There is not enough room for one more. */ - return (found); - } - m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); - if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { - /* We dont't have a complete CMSG header. */ - return (found); - } - if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { - /* We don't have the complete CMSG. */ - return (found); - } - cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); - cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); - if ((cmh.cmsg_level == IPPROTO_SCTP) && - ((c_type == cmh.cmsg_type) || - ((c_type == SCTP_SNDRCV) && - ((cmh.cmsg_type == SCTP_SNDINFO) || - (cmh.cmsg_type == SCTP_PRINFO) || - (cmh.cmsg_type == SCTP_AUTHINFO))))) { - if (c_type == cmh.cmsg_type) { - if (cpsize > INT_MAX) { - return (found); - } - if (cmsg_data_len < (int)cpsize) { - return (found); - } - /* It is exactly what we want. Copy it out. */ - m_copydata(control, cmsg_data_off, (int)cpsize, (caddr_t)data); - return (1); - } else { - struct sctp_sndrcvinfo *sndrcvinfo; - - sndrcvinfo = (struct sctp_sndrcvinfo *)data; - if (!found) { - if (cpsize < sizeof(struct sctp_sndrcvinfo)) { - return (found); - } - memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); - } - switch (cmh.cmsg_type) { - case SCTP_SNDINFO: - if (cmsg_data_len < (int)sizeof(struct sctp_sndinfo)) { - return (found); - } - m_copydata(control, cmsg_data_off, sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo); - sndrcvinfo->sinfo_stream = sndinfo.snd_sid; - sndrcvinfo->sinfo_flags = sndinfo.snd_flags; - sndrcvinfo->sinfo_ppid = sndinfo.snd_ppid; - sndrcvinfo->sinfo_context = sndinfo.snd_context; - sndrcvinfo->sinfo_assoc_id = sndinfo.snd_assoc_id; - break; - case SCTP_PRINFO: - if (cmsg_data_len < (int)sizeof(struct sctp_prinfo)) { - return (found); - } - m_copydata(control, cmsg_data_off, sizeof(struct sctp_prinfo), (caddr_t)&prinfo); - if (prinfo.pr_policy != SCTP_PR_SCTP_NONE) { - sndrcvinfo->sinfo_timetolive = prinfo.pr_value; - } else { - sndrcvinfo->sinfo_timetolive = 0; - } - sndrcvinfo->sinfo_flags |= prinfo.pr_policy; - break; - case SCTP_AUTHINFO: - if (cmsg_data_len < (int)sizeof(struct sctp_authinfo)) { - return (found); - } - m_copydata(control, cmsg_data_off, sizeof(struct sctp_authinfo), (caddr_t)&authinfo); - sndrcvinfo->sinfo_keynumber_valid = 1; - sndrcvinfo->sinfo_keynumber = authinfo.auth_keynumber; - break; - default: - return (found); - } - found = true; - } - } - } - return (found); -} - -static int -sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *error) -{ -#if defined(_WIN32) - WSACMSGHDR cmh; -#else - struct cmsghdr cmh; -#endif - struct sctp_initmsg initmsg; -#ifdef INET - struct sockaddr_in sin; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; - - tot_len = SCTP_BUF_LEN(control); - for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { - rem_len = tot_len - off; - if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { - /* There is not enough room for one more. */ - *error = EINVAL; - return (1); - } - m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); - if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { - /* We dont't have a complete CMSG header. */ - *error = EINVAL; - return (1); - } - if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { - /* We don't have the complete CMSG. */ - *error = EINVAL; - return (1); - } - cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); - cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); - if (cmh.cmsg_level == IPPROTO_SCTP) { - switch (cmh.cmsg_type) { - case SCTP_INIT: - if (cmsg_data_len < (int)sizeof(struct sctp_initmsg)) { - *error = EINVAL; - return (1); - } - m_copydata(control, cmsg_data_off, sizeof(struct sctp_initmsg), (caddr_t)&initmsg); - if (initmsg.sinit_max_attempts) - stcb->asoc.max_init_times = initmsg.sinit_max_attempts; - if (initmsg.sinit_num_ostreams) - stcb->asoc.pre_open_streams = initmsg.sinit_num_ostreams; - if (initmsg.sinit_max_instreams) - stcb->asoc.max_inbound_streams = initmsg.sinit_max_instreams; - if (initmsg.sinit_max_init_timeo) - stcb->asoc.initial_init_rto_max = initmsg.sinit_max_init_timeo; - if (stcb->asoc.streamoutcnt < stcb->asoc.pre_open_streams) { - struct sctp_stream_out *tmp_str; - unsigned int i; -#if defined(SCTP_DETAILED_STR_STATS) - int j; -#endif - - /* Default is NOT correct */ - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, default:%d pre_open:%d\n", - stcb->asoc.streamoutcnt, stcb->asoc.pre_open_streams); - SCTP_TCB_UNLOCK(stcb); - SCTP_MALLOC(tmp_str, - struct sctp_stream_out *, - (stcb->asoc.pre_open_streams * sizeof(struct sctp_stream_out)), - SCTP_M_STRMO); - SCTP_TCB_LOCK(stcb); - if (tmp_str != NULL) { - SCTP_FREE(stcb->asoc.strmout, SCTP_M_STRMO); - stcb->asoc.strmout = tmp_str; - stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt = stcb->asoc.pre_open_streams; - } else { - stcb->asoc.pre_open_streams = stcb->asoc.streamoutcnt; - } - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); - stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); - stcb->asoc.strmout[i].chunks_on_queues = 0; -#if defined(SCTP_DETAILED_STR_STATS) - for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { - stcb->asoc.strmout[i].abandoned_sent[j] = 0; - stcb->asoc.strmout[i].abandoned_unsent[j] = 0; - } -#else - stcb->asoc.strmout[i].abandoned_sent[0] = 0; - stcb->asoc.strmout[i].abandoned_unsent[0] = 0; -#endif - stcb->asoc.strmout[i].next_mid_ordered = 0; - stcb->asoc.strmout[i].next_mid_unordered = 0; - stcb->asoc.strmout[i].sid = i; - stcb->asoc.strmout[i].last_msg_incomplete = 0; - stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING; - } - } - break; -#ifdef INET - case SCTP_DSTADDRV4: - if (cmsg_data_len < (int)sizeof(struct in_addr)) { - *error = EINVAL; - return (1); - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin.sin_len = sizeof(struct sockaddr_in); -#endif - sin.sin_port = stcb->rport; - m_copydata(control, cmsg_data_off, sizeof(struct in_addr), (caddr_t)&sin.sin_addr); - if ((sin.sin_addr.s_addr == INADDR_ANY) || - (sin.sin_addr.s_addr == INADDR_BROADCAST) || - IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { - *error = EINVAL; - return (1); - } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { - *error = ENOBUFS; - return (1); - } - break; -#endif -#ifdef INET6 - case SCTP_DSTADDRV6: - if (cmsg_data_len < (int)sizeof(struct in6_addr)) { - *error = EINVAL; - return (1); - } - memset(&sin6, 0, sizeof(struct sockaddr_in6)); - sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6.sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6.sin6_port = stcb->rport; - m_copydata(control, cmsg_data_off, sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr); - if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) || - IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) { - *error = EINVAL; - return (1); - } -#ifdef INET - if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { - in6_sin6_2_sin(&sin, &sin6); - if ((sin.sin_addr.s_addr == INADDR_ANY) || - (sin.sin_addr.s_addr == INADDR_BROADCAST) || - IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { - *error = EINVAL; - return (1); - } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { - *error = ENOBUFS; - return (1); - } - } else -#endif - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { - *error = ENOBUFS; - return (1); - } - break; -#endif - default: - break; - } - } - } - return (0); -} - -#if defined(INET) || defined(INET6) -static struct sctp_tcb * -sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p, - uint16_t port, - struct mbuf *control, - struct sctp_nets **net_p, - int *error) -{ -#if defined(_WIN32) - WSACMSGHDR cmh; -#else - struct cmsghdr cmh; -#endif - struct sctp_tcb *stcb; - struct sockaddr *addr; -#ifdef INET - struct sockaddr_in sin; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; - - tot_len = SCTP_BUF_LEN(control); - for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { - rem_len = tot_len - off; - if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { - /* There is not enough room for one more. */ - *error = EINVAL; - return (NULL); - } - m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); - if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { - /* We dont't have a complete CMSG header. */ - *error = EINVAL; - return (NULL); - } - if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { - /* We don't have the complete CMSG. */ - *error = EINVAL; - return (NULL); - } - cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); - cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); - if (cmh.cmsg_level == IPPROTO_SCTP) { - switch (cmh.cmsg_type) { -#ifdef INET - case SCTP_DSTADDRV4: - if (cmsg_data_len < (int)sizeof(struct in_addr)) { - *error = EINVAL; - return (NULL); - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin.sin_len = sizeof(struct sockaddr_in); -#endif - sin.sin_port = port; - m_copydata(control, cmsg_data_off, sizeof(struct in_addr), (caddr_t)&sin.sin_addr); - addr = (struct sockaddr *)&sin; - break; -#endif -#ifdef INET6 - case SCTP_DSTADDRV6: - if (cmsg_data_len < (int)sizeof(struct in6_addr)) { - *error = EINVAL; - return (NULL); - } - memset(&sin6, 0, sizeof(struct sockaddr_in6)); - sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6.sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6.sin6_port = port; - m_copydata(control, cmsg_data_off, sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr); -#ifdef INET - if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { - in6_sin6_2_sin(&sin, &sin6); - addr = (struct sockaddr *)&sin; - } else -#endif - addr = (struct sockaddr *)&sin6; - break; -#endif - default: - addr = NULL; - break; - } - if (addr) { - stcb = sctp_findassociation_ep_addr(inp_p, addr, net_p, NULL, NULL); - if (stcb != NULL) { - return (stcb); - } - } - } - } - return (NULL); -} -#endif - -static struct mbuf * -sctp_add_cookie(struct mbuf *init, int init_offset, - struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in, uint8_t **signature) -{ - struct mbuf *copy_init, *copy_initack, *m_at, *sig, *mret; - struct sctp_state_cookie *stc; - struct sctp_paramhdr *ph; - uint16_t cookie_sz; - - mret = sctp_get_mbuf_for_msg((sizeof(struct sctp_state_cookie) + - sizeof(struct sctp_paramhdr)), 0, - M_NOWAIT, 1, MT_DATA); - if (mret == NULL) { - return (NULL); - } - copy_init = SCTP_M_COPYM(init, init_offset, M_COPYALL, M_NOWAIT); - if (copy_init == NULL) { - sctp_m_freem(mret); - return (NULL); - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(copy_init, SCTP_MBUF_ICOPY); - } -#endif - copy_initack = SCTP_M_COPYM(initack, initack_offset, M_COPYALL, - M_NOWAIT); - if (copy_initack == NULL) { - sctp_m_freem(mret); - sctp_m_freem(copy_init); - return (NULL); - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(copy_initack, SCTP_MBUF_ICOPY); - } -#endif - /* easy side we just drop it on the end */ - ph = mtod(mret, struct sctp_paramhdr *); - SCTP_BUF_LEN(mret) = sizeof(struct sctp_state_cookie) + - sizeof(struct sctp_paramhdr); - stc = (struct sctp_state_cookie *)((caddr_t)ph + - sizeof(struct sctp_paramhdr)); - ph->param_type = htons(SCTP_STATE_COOKIE); - ph->param_length = 0; /* fill in at the end */ - /* Fill in the stc cookie data */ - memcpy(stc, stc_in, sizeof(struct sctp_state_cookie)); - - /* tack the INIT and then the INIT-ACK onto the chain */ - cookie_sz = 0; - for (m_at = mret; m_at; m_at = SCTP_BUF_NEXT(m_at)) { - cookie_sz += SCTP_BUF_LEN(m_at); - if (SCTP_BUF_NEXT(m_at) == NULL) { - SCTP_BUF_NEXT(m_at) = copy_init; - break; - } - } - for (m_at = copy_init; m_at; m_at = SCTP_BUF_NEXT(m_at)) { - cookie_sz += SCTP_BUF_LEN(m_at); - if (SCTP_BUF_NEXT(m_at) == NULL) { - SCTP_BUF_NEXT(m_at) = copy_initack; - break; - } - } - for (m_at = copy_initack; m_at; m_at = SCTP_BUF_NEXT(m_at)) { - cookie_sz += SCTP_BUF_LEN(m_at); - if (SCTP_BUF_NEXT(m_at) == NULL) { - break; - } - } - sig = sctp_get_mbuf_for_msg(SCTP_SIGNATURE_SIZE, 0, M_NOWAIT, 1, MT_DATA); - if (sig == NULL) { - /* no space, so free the entire chain */ - sctp_m_freem(mret); - return (NULL); - } - SCTP_BUF_NEXT(m_at) = sig; - SCTP_BUF_LEN(sig) = SCTP_SIGNATURE_SIZE; - cookie_sz += SCTP_SIGNATURE_SIZE; - ph->param_length = htons(cookie_sz); - *signature = (uint8_t *)mtod(sig, caddr_t); - memset(*signature, 0, SCTP_SIGNATURE_SIZE); - return (mret); -} - -static uint8_t -sctp_get_ect(struct sctp_tcb *stcb) -{ - if ((stcb != NULL) && (stcb->asoc.ecn_supported == 1)) { - return (SCTP_ECT0_BIT); - } else { - return (0); - } -} - -#if defined(INET) || defined(INET6) -static void -sctp_handle_no_route(struct sctp_tcb *stcb, - struct sctp_nets *net, - int so_locked) -{ - SCTPDBG(SCTP_DEBUG_OUTPUT1, "dropped packet - no valid source addr\n"); - - if (net) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination was "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT1, &net->ro._l_addr.sa); - if (net->dest_state & SCTP_ADDR_CONFIRMED) { - if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "no route takes interface %p down\n", (void *)net); - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, 0, - (void *)net, - so_locked); - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state &= ~SCTP_ADDR_PF; - } - } - if (stcb) { - if (net == stcb->asoc.primary_destination) { - /* need a new primary */ - struct sctp_nets *alt; - - alt = sctp_find_alternate_net(stcb, net, 0); - if (alt != net) { - if (stcb->asoc.alternate) { - sctp_free_remote_addr(stcb->asoc.alternate); - } - stcb->asoc.alternate = alt; - atomic_add_int(&stcb->asoc.alternate->ref_count, 1); - if (net->ro._s_addr) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - } - net->src_addr_selected = 0; - } - } - } - } -} -#endif - -static int -sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, /* may be NULL */ - struct sctp_nets *net, - struct sockaddr *to, - struct mbuf *m, - uint32_t auth_offset, - struct sctp_auth_chunk *auth, - uint16_t auth_keyid, - int nofragment_flag, - int ecn_ok, - int out_of_asoc_ok, - uint16_t src_port, - uint16_t dest_port, - uint32_t v_tag, - uint16_t port, - union sctp_sockstore *over_addr, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - bool use_zero_crc, - int so_locked) -/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */ -{ - /** - * Given a mbuf chain (via SCTP_BUF_NEXT()) that holds a packet header - * WITH an SCTPHDR but no IP header, endpoint inp and sa structure: - * - fill in the HMAC digest of any AUTH chunk in the packet. - * - calculate and fill in the SCTP checksum. - * - prepend an IP address header. - * - if boundall use INADDR_ANY. - * - if boundspecific do source address selection. - * - set fragmentation option for ipV4. - * - On return from IP output, check/adjust mtu size of output - * interface and smallest_mtu size as well. - */ - /* Will need ifdefs around this */ - struct mbuf *newm; - struct sctphdr *sctphdr; - int packet_length; - int ret; -#if defined(INET) || defined(INET6) - uint32_t vrf_id; -#endif -#if defined(INET) || defined(INET6) - struct mbuf *o_pak; - sctp_route_t *ro = NULL; - struct udphdr *udp = NULL; -#endif - uint8_t tos_value; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so = NULL; -#endif - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - SCTP_TCB_LOCK_ASSERT(stcb); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - if ((net) && (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); - sctp_m_freem(m); - return (EFAULT); - } -#if defined(INET) || defined(INET6) - if (stcb) { - vrf_id = stcb->asoc.vrf_id; - } else { - vrf_id = inp->def_vrf_id; - } -#endif - /* fill in the HMAC digest for any AUTH chunk in the packet */ - if ((auth != NULL) && (stcb != NULL)) { - sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid); - } - - if (net) { - tos_value = net->dscp; - } else if (stcb) { - tos_value = stcb->asoc.default_dscp; - } else { - tos_value = inp->sctp_ep.default_dscp; - } - - switch (to->sa_family) { -#ifdef INET - case AF_INET: - { - struct ip *ip = NULL; - sctp_route_t iproute; - int len; - - len = SCTP_MIN_V4_OVERHEAD; - if (port) { - len += sizeof(struct udphdr); - } - newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); - if (newm == NULL) { - sctp_m_freem(m); - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_ALIGN_TO_END(newm, len); - SCTP_BUF_LEN(newm) = len; - SCTP_BUF_NEXT(newm) = m; - m = newm; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net != NULL) { - m->m_pkthdr.flowid = net->flowid; - M_HASHTYPE_SET(m, net->flowtype); - } else { - m->m_pkthdr.flowid = mflowid; - M_HASHTYPE_SET(m, mflowtype); - } -#endif - packet_length = sctp_calculate_len(m); - ip = mtod(m, struct ip *); - ip->ip_v = IPVERSION; - ip->ip_hl = (sizeof(struct ip) >> 2); - if (tos_value == 0) { - /* - * This means especially, that it is not set at the - * SCTP layer. So use the value from the IP layer. - */ - tos_value = inp->ip_inp.inp.inp_ip_tos; - } - tos_value &= 0xfc; - if (ecn_ok) { - tos_value |= sctp_get_ect(stcb); - } - if ((nofragment_flag) && (port == 0)) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - ip->ip_off = htons(IP_DF); -#elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) - ip->ip_off = IP_DF; -#else - ip->ip_off = htons(IP_DF); -#endif - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - ip->ip_off = htons(0); -#else - ip->ip_off = 0; -#endif - } -#if defined(__Userspace__) - ip->ip_id = htons(SCTP_IP_ID(inp)++); -#elif defined(__FreeBSD__) - /* FreeBSD has a function for ip_id's */ - ip_fillid(ip); -#elif defined(__APPLE__) -#if RANDOM_IP_ID - ip->ip_id = ip_randomid(); -#else - ip->ip_id = htons(ip_id++); -#endif -#else - ip->ip_id = SCTP_IP_ID(inp)++; -#endif - - ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl; -#if defined(__FreeBSD__) && !defined(__Userspace__) - ip->ip_len = htons(packet_length); -#else - ip->ip_len = packet_length; -#endif - ip->ip_tos = tos_value; - if (port) { - ip->ip_p = IPPROTO_UDP; - } else { - ip->ip_p = IPPROTO_SCTP; - } - ip->ip_sum = 0; - if (net == NULL) { - ro = &iproute; - memset(&iproute, 0, sizeof(iproute)); -#ifdef HAVE_SA_LEN - memcpy(&ro->ro_dst, to, to->sa_len); -#else - memcpy(&ro->ro_dst, to, sizeof(struct sockaddr_in)); -#endif - } else { - ro = (sctp_route_t *)&net->ro; - } - /* Now the address selection part */ - ip->ip_dst.s_addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; - - /* call the routine to select the src address */ - if (net && out_of_asoc_ok == 0) { - if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED|SCTP_ADDR_IFA_UNUSEABLE))) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(ro); -#else - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } -#endif - } - if (net->src_addr_selected == 0) { - /* Cache the source address */ - net->ro._s_addr = sctp_source_address_selection(inp,stcb, - ro, net, 0, - vrf_id); - net->src_addr_selected = 1; - } - if (net->ro._s_addr == NULL) { - /* No route to host */ - net->src_addr_selected = 0; - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - ip->ip_src = net->ro._s_addr->address.sin.sin_addr; - } else { - if (over_addr == NULL) { - struct sctp_ifa *_lsrc; - - _lsrc = sctp_source_address_selection(inp, stcb, ro, - net, - out_of_asoc_ok, - vrf_id); - if (_lsrc == NULL) { - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - ip->ip_src = _lsrc->address.sin.sin_addr; - sctp_free_ifa(_lsrc); - } else { - ip->ip_src = over_addr->sin.sin_addr; - SCTP_RTALLOC(ro, vrf_id, inp->fibnum); - } - } - if (port) { - if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) { - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip)); - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip))); -#if !defined(__Userspace__) -#if defined(__FreeBSD__) - if (V_udp_cksum) { - udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); - } else { - udp->uh_sum = 0; - } -#else - udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); -#endif -#else - udp->uh_sum = 0; -#endif - sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); - } else { - sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(struct ip)); - } - - sctphdr->src_port = src_port; - sctphdr->dest_port = dest_port; - sctphdr->v_tag = v_tag; - sctphdr->checksum = 0; - - /* - * If source address selection fails and we find no route - * then the ip_output should fail as well with a - * NO_ROUTE_TO_HOST type error. We probably should catch - * that somewhere and abort the association right away - * (assuming this is an INIT being sent). - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (ro->ro_nh == NULL) { -#else - if (ro->ro_rt == NULL) { -#endif - /* - * src addr selection failed to find a route (or - * valid source addr), so we can't get there from - * here (yet)! - */ - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - if (ro != &iproute) { - memcpy(&iproute, ro, sizeof(*ro)); - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Calling ipv4 output routine from low level src addr:%x\n", - (uint32_t) (ntohl(ip->ip_src.s_addr))); - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Destination is %x\n", - (uint32_t)(ntohl(ip->ip_dst.s_addr))); -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n", - (void *)ro->ro_nh); -#else - SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n", - (void *)ro->ro_rt); -#endif - - if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { - /* failed to prepend data, give up */ - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - sctp_m_freem(m); - return (ENOMEM); - } - SCTP_ATTACH_CHAIN(o_pak, m, packet_length); - if (port) { - if (use_zero_crc) { - SCTP_STAT_INCR(sctps_sendzerocrc); - } else { - sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); - } -#if !defined(__Userspace__) -#if defined(__FreeBSD__) - if (V_udp_cksum) { - SCTP_ENABLE_UDP_CSUM(o_pak); - } -#else - SCTP_ENABLE_UDP_CSUM(o_pak); -#endif -#endif - } else { - if (use_zero_crc) { - SCTP_STAT_INCR(sctps_sendzerocrc); - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - m->m_pkthdr.csum_flags = CSUM_SCTP; - m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); - SCTP_STAT_INCR(sctps_sendhwcrc); -#else - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && (stcb->asoc.scope.loopback_scope))) { - sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip)); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendhwcrc); - } -#endif - } - } -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) - sctp_packet_log(o_pak); -#endif - /* send it out. table id is taken from stcb */ -#if defined(__APPLE__) && !defined(__Userspace__) - if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { - so = SCTP_INP_SO(inp); - SCTP_SOCKET_UNLOCK(so, 0); - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(send, NULL, stcb, ip, stcb, sctphdr); -#endif - SCTP_IP_OUTPUT(ret, o_pak, ro, inp, vrf_id); -#if defined(__APPLE__) && !defined(__Userspace__) - if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 0); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (port) { - UDPSTAT_INC(udps_opackets); - } -#endif - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - if (ret) - SCTP_STAT_INCR(sctps_senderrors); - - SCTPDBG(SCTP_DEBUG_OUTPUT3, "IP output returns %d\n", ret); - if (net == NULL) { - /* free tempy routes */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(ro); -#else - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } -#endif - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - if ((ro->ro_nh != NULL) && (net->ro._s_addr) && -#else - if ((ro->ro_rt != NULL) && (net->ro._s_addr) && -#endif - ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) { - uint32_t mtu; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_nh); -#else - mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); -#endif - if (mtu > 0) { - if (net->port) { - mtu -= sizeof(struct udphdr); - } - if (mtu < net->mtu) { - net->mtu = mtu; - if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { - sctp_pathmtu_adjustment(stcb, mtu, true); - } - } - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else if (ro->ro_nh == NULL) { -#else - } else if (ro->ro_rt == NULL) { -#endif - /* route was freed */ - if (net->ro._s_addr && - net->src_addr_selected) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - } - net->src_addr_selected = 0; - } - } - return (ret); - } -#endif -#ifdef INET6 - case AF_INET6: - { - uint32_t flowlabel, flowinfo; - struct ip6_hdr *ip6h; - struct route_in6 ip6route; -#if !defined(__Userspace__) - struct ifnet *ifp; -#endif - struct sockaddr_in6 *sin6, tmp, *lsa6, lsa6_tmp; - int prev_scope = 0; -#ifdef SCTP_EMBEDDED_V6_SCOPE - struct sockaddr_in6 lsa6_storage; - int error; -#endif - u_short prev_port = 0; - int len; - - if (net) { - flowlabel = net->flowlabel; - } else if (stcb) { - flowlabel = stcb->asoc.default_flowlabel; - } else { - flowlabel = inp->sctp_ep.default_flowlabel; - } - if (flowlabel == 0) { - /* - * This means especially, that it is not set at the - * SCTP layer. So use the value from the IP layer. - */ -#if defined(__APPLE__) && !defined(__Userspace__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) - flowlabel = ntohl(inp->ip_inp.inp.inp_flow); -#else - flowlabel = ntohl(((struct inpcb *)inp)->inp_flow); -#endif - } - flowlabel &= 0x000fffff; - len = SCTP_MIN_OVERHEAD; - if (port) { - len += sizeof(struct udphdr); - } - newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); - if (newm == NULL) { - sctp_m_freem(m); - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_ALIGN_TO_END(newm, len); - SCTP_BUF_LEN(newm) = len; - SCTP_BUF_NEXT(newm) = m; - m = newm; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net != NULL) { - m->m_pkthdr.flowid = net->flowid; - M_HASHTYPE_SET(m, net->flowtype); - } else { - m->m_pkthdr.flowid = mflowid; - M_HASHTYPE_SET(m, mflowtype); - } -#endif - packet_length = sctp_calculate_len(m); - - ip6h = mtod(m, struct ip6_hdr *); - /* protect *sin6 from overwrite */ - sin6 = (struct sockaddr_in6 *)to; - tmp = *sin6; - sin6 = &tmp; - -#ifdef SCTP_EMBEDDED_V6_SCOPE - /* KAME hack: embed scopeid */ -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0) -#else - if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL) != 0) -#endif -#elif defined(SCTP_KAME) - if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) -#else - if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) -#endif - { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - sctp_m_freem(m); - return (EINVAL); - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - if (net == NULL) { - memset(&ip6route, 0, sizeof(ip6route)); - ro = (sctp_route_t *)&ip6route; -#ifdef HAVE_SIN6_LEN - memcpy(&ro->ro_dst, sin6, sin6->sin6_len); -#else - memcpy(&ro->ro_dst, sin6, sizeof(struct sockaddr_in6)); -#endif - } else { - ro = (sctp_route_t *)&net->ro; - } - /* - * We assume here that inp_flow is in host byte order within - * the TCB! - */ - if (tos_value == 0) { - /* - * This means especially, that it is not set at the - * SCTP layer. So use the value from the IP layer. - */ -#if defined(__APPLE__) && !defined(__Userspace__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) - tos_value = (ntohl(inp->ip_inp.inp.inp_flow) >> 20) & 0xff; -#else - tos_value = (ntohl(((struct inpcb *)inp)->inp_flow) >> 20) & 0xff; -#endif - } - tos_value &= 0xfc; - if (ecn_ok) { - tos_value |= sctp_get_ect(stcb); - } - flowinfo = 0x06; - flowinfo <<= 8; - flowinfo |= tos_value; - flowinfo <<= 20; - flowinfo |= flowlabel; - ip6h->ip6_flow = htonl(flowinfo); - if (port) { - ip6h->ip6_nxt = IPPROTO_UDP; - } else { - ip6h->ip6_nxt = IPPROTO_SCTP; - } - ip6h->ip6_plen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); - ip6h->ip6_dst = sin6->sin6_addr; - - /* - * Add SRC address selection here: we can only reuse to a - * limited degree the kame src-addr-sel, since we can try - * their selection but it may not be bound. - */ - memset(&lsa6_tmp, 0, sizeof(lsa6_tmp)); - lsa6_tmp.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - lsa6_tmp.sin6_len = sizeof(lsa6_tmp); -#endif - lsa6 = &lsa6_tmp; - if (net && out_of_asoc_ok == 0) { - if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED|SCTP_ADDR_IFA_UNUSEABLE))) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(ro); -#else - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } -#endif - } - if (net->src_addr_selected == 0) { -#ifdef SCTP_EMBEDDED_V6_SCOPE - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; - /* KAME hack: embed scopeid */ -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0) -#else - if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL) != 0) -#endif -#elif defined(SCTP_KAME) - if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) -#else - if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) -#endif - { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - sctp_m_freem(m); - return (EINVAL); - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - /* Cache the source address */ - net->ro._s_addr = sctp_source_address_selection(inp, - stcb, - ro, - net, - 0, - vrf_id); -#ifdef SCTP_EMBEDDED_V6_SCOPE -#ifdef SCTP_KAME - (void)sa6_recoverscope(sin6); -#else - (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); -#endif /* SCTP_KAME */ -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - net->src_addr_selected = 1; - } - if (net->ro._s_addr == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "V6:No route to host\n"); - net->src_addr_selected = 0; - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - lsa6->sin6_addr = net->ro._s_addr->address.sin6.sin6_addr; - } else { -#ifdef SCTP_EMBEDDED_V6_SCOPE - sin6 = (struct sockaddr_in6 *)&ro->ro_dst; - /* KAME hack: embed scopeid */ -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0) -#else - if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL) != 0) -#endif -#elif defined(SCTP_KAME) - if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) -#else - if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) -#endif - { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - sctp_m_freem(m); - return (EINVAL); - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - if (over_addr == NULL) { - struct sctp_ifa *_lsrc; - - _lsrc = sctp_source_address_selection(inp, stcb, ro, - net, - out_of_asoc_ok, - vrf_id); - if (_lsrc == NULL) { - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr; - sctp_free_ifa(_lsrc); - } else { - lsa6->sin6_addr = over_addr->sin6.sin6_addr; - SCTP_RTALLOC(ro, vrf_id, inp->fibnum); - } -#ifdef SCTP_EMBEDDED_V6_SCOPE -#ifdef SCTP_KAME - (void)sa6_recoverscope(sin6); -#else - (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); -#endif /* SCTP_KAME */ -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - } - lsa6->sin6_port = inp->sctp_lport; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (ro->ro_nh == NULL) { -#else - if (ro->ro_rt == NULL) { -#endif - /* - * src addr selection failed to find a route (or - * valid source addr), so we can't get there from - * here! - */ - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } -#ifndef SCOPEDROUTING -#ifdef SCTP_EMBEDDED_V6_SCOPE - /* - * XXX: sa6 may not have a valid sin6_scope_id in the - * non-SCOPEDROUTING case. - */ - memset(&lsa6_storage, 0, sizeof(lsa6_storage)); - lsa6_storage.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - lsa6_storage.sin6_len = sizeof(lsa6_storage); -#endif -#ifdef SCTP_KAME - lsa6_storage.sin6_addr = lsa6->sin6_addr; - if ((error = sa6_recoverscope(&lsa6_storage)) != 0) { -#else - if ((error = in6_recoverscope(&lsa6_storage, &lsa6->sin6_addr, - NULL)) != 0) { -#endif /* SCTP_KAME */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "recover scope fails error %d\n", error); - sctp_m_freem(m); - return (error); - } - /* XXX */ - lsa6_storage.sin6_addr = lsa6->sin6_addr; - lsa6_storage.sin6_port = inp->sctp_lport; - lsa6 = &lsa6_storage; -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#endif /* SCOPEDROUTING */ - ip6h->ip6_src = lsa6->sin6_addr; - - if (port) { - if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) { - sctp_handle_no_route(stcb, net, so_locked); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); - sctp_m_freem(m); - return (EHOSTUNREACH); - } - udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); - udp->uh_sum = 0; - sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); - } else { - sctphdr = (struct sctphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); - } - - sctphdr->src_port = src_port; - sctphdr->dest_port = dest_port; - sctphdr->v_tag = v_tag; - sctphdr->checksum = 0; - - /* - * We set the hop limit now since there is a good chance - * that our ro pointer is now filled - */ - ip6h->ip6_hlim = SCTP_GET_HLIM(inp, ro); -#if !defined(__Userspace__) - ifp = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); -#endif - -#ifdef SCTP_DEBUG - /* Copy to be sure something bad is not happening */ - sin6->sin6_addr = ip6h->ip6_dst; - lsa6->sin6_addr = ip6h->ip6_src; -#endif - - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Calling ipv6 output routine from low level\n"); - SCTPDBG(SCTP_DEBUG_OUTPUT3, "src: "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, (struct sockaddr *)lsa6); - SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst: "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, (struct sockaddr *)sin6); - if (net) { - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; - /* preserve the port and scope for link local send */ - prev_scope = sin6->sin6_scope_id; - prev_port = sin6->sin6_port; - } - - if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { - /* failed to prepend data, give up */ - sctp_m_freem(m); - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_ATTACH_CHAIN(o_pak, m, packet_length); - if (port) { - sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); -#if !defined(__Userspace__) -#if defined(_WIN32) - udp->uh_sum = 0; -#else - if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { - udp->uh_sum = 0xffff; - } -#endif -#endif - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - m->m_pkthdr.csum_flags = CSUM_SCTP_IPV6; - m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); - SCTP_STAT_INCR(sctps_sendhwcrc); -#else - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && (stcb->asoc.scope.loopback_scope))) { - sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr)); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendhwcrc); - } -#endif - } - /* send it out. table id is taken from stcb */ -#if defined(__APPLE__) && !defined(__Userspace__) - if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { - so = SCTP_INP_SO(inp); - SCTP_SOCKET_UNLOCK(so, 0); - } -#endif -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) - sctp_packet_log(o_pak); -#endif -#if !defined(__Userspace__) -#if defined(__FreeBSD__) - SCTP_PROBE5(send, NULL, stcb, ip6h, stcb, sctphdr); -#endif - SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, &ifp, inp, vrf_id); -#else - SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, NULL, inp, vrf_id); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 0); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } -#endif - if (net) { - /* for link local this must be done */ - sin6->sin6_scope_id = prev_scope; - sin6->sin6_port = prev_port; - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret); -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (port) { - UDPSTAT_INC(udps_opackets); - } -#endif - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - if (ret) { - SCTP_STAT_INCR(sctps_senderrors); - } - if (net == NULL) { - /* Now if we had a temp route free it */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(ro); -#else - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } -#endif - } else { - /* PMTU check versus smallest asoc MTU goes here */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (ro->ro_nh == NULL) { -#else - if (ro->ro_rt == NULL) { -#endif - /* Route was freed */ - if (net->ro._s_addr && - net->src_addr_selected) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - } - net->src_addr_selected = 0; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if ((ro->ro_nh != NULL) && (net->ro._s_addr) && -#else - if ((ro->ro_rt != NULL) && (net->ro._s_addr) && -#endif - ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) { - uint32_t mtu; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_nh); -#else - mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); -#endif - if (mtu > 0) { - if (net->port) { - mtu -= sizeof(struct udphdr); - } - if (mtu < net->mtu) { - net->mtu = mtu; - if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { - sctp_pathmtu_adjustment(stcb, mtu, false); - } - } - } - } -#if !defined(__Userspace__) - else if (ifp != NULL) { -#if defined(_WIN32) -#define ND_IFINFO(ifp) (ifp) -#define linkmtu if_mtu -#endif - if ((ND_IFINFO(ifp)->linkmtu > 0) && - (stcb->asoc.smallest_mtu > ND_IFINFO(ifp)->linkmtu)) { - sctp_pathmtu_adjustment(stcb, ND_IFINFO(ifp)->linkmtu, false); - } - } -#endif - } - return (ret); - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - char *buffer; - struct sockaddr_conn *sconn; - int len; - - sconn = (struct sockaddr_conn *)to; - len = sizeof(struct sctphdr); - newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); - if (newm == NULL) { - sctp_m_freem(m); - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_ALIGN_TO_END(newm, len); - SCTP_BUF_LEN(newm) = len; - SCTP_BUF_NEXT(newm) = m; - m = newm; - packet_length = sctp_calculate_len(m); - m->m_pkthdr.len = packet_length; - sctphdr = mtod(m, struct sctphdr *); - sctphdr->src_port = src_port; - sctphdr->dest_port = dest_port; - sctphdr->v_tag = v_tag; - sctphdr->checksum = 0; - if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { - sctphdr->checksum = sctp_calculate_cksum(m, 0); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendhwcrc); - } - if (tos_value == 0) { - tos_value = inp->ip_inp.inp.inp_ip_tos; - } - tos_value &= 0xfc; - if (ecn_ok) { - tos_value |= sctp_get_ect(stcb); - } - /* Don't alloc/free for each packet */ - if ((buffer = malloc(packet_length)) != NULL) { - m_copydata(m, 0, packet_length, buffer); - ret = SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, packet_length, tos_value, nofragment_flag); - free(buffer); - } else { - ret = ENOMEM; - } - sctp_m_freem(m); - return (ret); - } -#endif - default: - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Unknown protocol (TSNH) type %d\n", - ((struct sockaddr *)to)->sa_family); - sctp_m_freem(m); - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); - return (EFAULT); - } -} - -void -sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked) -{ - struct mbuf *m, *m_last; - struct sctp_nets *net; - struct sctp_init_chunk *init; - struct sctp_supported_addr_param *sup_addr; - struct sctp_adaptation_layer_indication *ali; - struct sctp_zero_checksum_acceptable *zero_chksum; - struct sctp_supported_chunk_types_param *pr_supported; - struct sctp_paramhdr *ph; - int cnt_inits_to = 0; - int error; - uint16_t num_ext, chunk_len, padding_len, parameter_len; - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - /* INIT's always go to the primary (and usually ONLY address) */ - net = stcb->asoc.primary_destination; - if (net == NULL) { - net = TAILQ_FIRST(&stcb->asoc.nets); - if (net == NULL) { - /* TSNH */ - return; - } - /* we confirm any address we send an INIT to */ - net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; - (void)sctp_set_primary_addr(stcb, NULL, net); - } else { - /* we confirm any address we send an INIT to */ - net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; - } - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT\n"); -#ifdef INET6 - if (net->ro._l_addr.sa.sa_family == AF_INET6) { - /* - * special hook, if we are sending to link local it will not - * show up in our private address count. - */ - if (IN6_IS_ADDR_LINKLOCAL(&net->ro._l_addr.sin6.sin6_addr)) - cnt_inits_to = 1; - } -#endif - if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - /* This case should not happen */ - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - failed timer?\n"); - return; - } - /* start the INIT timer */ - sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net); - - m = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_NOWAIT, 1, MT_DATA); - if (m == NULL) { - /* No memory, INIT timer will re-attempt. */ - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n"); - return; - } - chunk_len = (uint16_t)sizeof(struct sctp_init_chunk); - padding_len = 0; - /* Now lets put the chunk header in place */ - init = mtod(m, struct sctp_init_chunk *); - /* now the chunk header */ - init->ch.chunk_type = SCTP_INITIATION; - init->ch.chunk_flags = 0; - /* fill in later from mbuf we build */ - init->ch.chunk_length = 0; - /* place in my tag */ - init->init.initiate_tag = htonl(stcb->asoc.my_vtag); - /* set up some of the credits. */ - init->init.a_rwnd = htonl(max(inp->sctp_socket?SCTP_SB_LIMIT_RCV(inp->sctp_socket):0, - SCTP_MINIMAL_RWND)); - init->init.num_outbound_streams = htons(stcb->asoc.pre_open_streams); - init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams); - init->init.initial_tsn = htonl(stcb->asoc.init_seq_number); - - /* Adaptation layer indication parameter */ - if (inp->sctp_ep.adaptation_layer_indicator_provided) { - parameter_len = (uint16_t)sizeof(struct sctp_adaptation_layer_indication); - ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t) + chunk_len); - ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); - ali->ph.param_length = htons(parameter_len); - ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator); - chunk_len += parameter_len; - } - - /* ECN parameter */ - if (stcb->asoc.ecn_supported == 1) { - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); - ph->param_type = htons(SCTP_ECN_CAPABLE); - ph->param_length = htons(parameter_len); - chunk_len += parameter_len; - } - - /* PR-SCTP supported parameter */ - if (stcb->asoc.prsctp_supported == 1) { - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); - ph->param_type = htons(SCTP_PRSCTP_SUPPORTED); - ph->param_length = htons(parameter_len); - chunk_len += parameter_len; - } - - /* Zero checksum acceptable parameter */ - if (stcb->asoc.rcv_edmid != SCTP_EDMID_NONE) { - parameter_len = (uint16_t)sizeof(struct sctp_zero_checksum_acceptable); - zero_chksum = (struct sctp_zero_checksum_acceptable *)(mtod(m, caddr_t) + chunk_len); - zero_chksum->ph.param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE); - zero_chksum->ph.param_length = htons(parameter_len); - zero_chksum->edmid = htonl(stcb->asoc.rcv_edmid); - chunk_len += parameter_len; - } - - /* Add NAT friendly parameter. */ - if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); - ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); - ph->param_length = htons(parameter_len); - chunk_len += parameter_len; - } - - /* And now tell the peer which extensions we support */ - num_ext = 0; - pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t) + chunk_len); - if (stcb->asoc.prsctp_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; - if (stcb->asoc.idata_supported) { - pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN; - } - } - if (stcb->asoc.auth_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; - } - if (stcb->asoc.asconf_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; - } - if (stcb->asoc.reconfig_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; - } - if (stcb->asoc.idata_supported) { - pr_supported->chunk_types[num_ext++] = SCTP_IDATA; - } - if (stcb->asoc.nrsack_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; - } - if (stcb->asoc.pktdrop_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; - } - if (num_ext > 0) { - parameter_len = (uint16_t)sizeof(struct sctp_supported_chunk_types_param) + num_ext; - pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); - pr_supported->ph.param_length = htons(parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - } - /* add authentication parameters */ - if (stcb->asoc.auth_supported) { - /* attach RANDOM parameter, if available */ - if (stcb->asoc.authinfo.random != NULL) { - struct sctp_auth_random *randp; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - randp = (struct sctp_auth_random *)(mtod(m, caddr_t) + chunk_len); - parameter_len = (uint16_t)sizeof(struct sctp_auth_random) + stcb->asoc.authinfo.random_len; - /* random key already contains the header */ - memcpy(randp, stcb->asoc.authinfo.random->key, parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - } - /* add HMAC_ALGO parameter */ - if (stcb->asoc.local_hmacs != NULL) { - struct sctp_auth_hmac_algo *hmacs; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t) + chunk_len); - parameter_len = (uint16_t)(sizeof(struct sctp_auth_hmac_algo) + - stcb->asoc.local_hmacs->num_algo * sizeof(uint16_t)); - hmacs->ph.param_type = htons(SCTP_HMAC_LIST); - hmacs->ph.param_length = htons(parameter_len); - sctp_serialize_hmaclist(stcb->asoc.local_hmacs, (uint8_t *)hmacs->hmac_ids); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - } - /* add CHUNKS parameter */ - if (stcb->asoc.local_auth_chunks != NULL) { - struct sctp_auth_chunk_list *chunks; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t) + chunk_len); - parameter_len = (uint16_t)(sizeof(struct sctp_auth_chunk_list) + - sctp_auth_get_chklist_size(stcb->asoc.local_auth_chunks)); - chunks->ph.param_type = htons(SCTP_CHUNK_LIST); - chunks->ph.param_length = htons(parameter_len); - sctp_serialize_auth_chunks(stcb->asoc.local_auth_chunks, chunks->chunk_types); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - } - } - - /* now any cookie time extensions */ - if (stcb->asoc.cookie_preserve_req > 0) { - struct sctp_cookie_perserve_param *cookie_preserve; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - parameter_len = (uint16_t)sizeof(struct sctp_cookie_perserve_param); - cookie_preserve = (struct sctp_cookie_perserve_param *)(mtod(m, caddr_t) + chunk_len); - cookie_preserve->ph.param_type = htons(SCTP_COOKIE_PRESERVE); - cookie_preserve->ph.param_length = htons(parameter_len); - cookie_preserve->time = htonl(stcb->asoc.cookie_preserve_req); - stcb->asoc.cookie_preserve_req = 0; - chunk_len += parameter_len; - } - - if (stcb->asoc.scope.ipv4_addr_legal || stcb->asoc.scope.ipv6_addr_legal) { - uint8_t i; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - if (stcb->asoc.scope.ipv4_addr_legal) { - parameter_len += (uint16_t)sizeof(uint16_t); - } - if (stcb->asoc.scope.ipv6_addr_legal) { - parameter_len += (uint16_t)sizeof(uint16_t); - } - sup_addr = (struct sctp_supported_addr_param *)(mtod(m, caddr_t) + chunk_len); - sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE); - sup_addr->ph.param_length = htons(parameter_len); - i = 0; - if (stcb->asoc.scope.ipv4_addr_legal) { - sup_addr->addr_type[i++] = htons(SCTP_IPV4_ADDRESS); - } - if (stcb->asoc.scope.ipv6_addr_legal) { - sup_addr->addr_type[i++] = htons(SCTP_IPV6_ADDRESS); - } - padding_len = 4 - 2 * i; - chunk_len += parameter_len; - } - - SCTP_BUF_LEN(m) = chunk_len; - /* now the addresses */ - /* To optimize this we could put the scoping stuff - * into a structure and remove the individual uint8's from - * the assoc structure. Then we could just sifa in the - * address within the stcb. But for now this is a quick - * hack to get the address stuff teased apart. - */ - m_last = sctp_add_addresses_to_i_ia(inp, stcb, &stcb->asoc.scope, - m, cnt_inits_to, - &padding_len, &chunk_len); - - init->ch.chunk_length = htons(chunk_len); - if (padding_len > 0) { - if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) { - sctp_m_freem(m); - return; - } - } - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n"); - if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, - (struct sockaddr *)&net->ro._l_addr, - m, 0, NULL, 0, 0, 0, 0, - inp->sctp_lport, stcb->rport, htonl(0), - net->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - false, so_locked))) { - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error); - if (error == ENOBUFS) { - stcb->asoc.ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - } else { - stcb->asoc.ifp_had_enobuf = 0; - } - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time); -} - -struct mbuf * -sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, - int param_offset, int *abort_processing, - struct sctp_chunkhdr *cp, - int *nat_friendly, - int *cookie_found) -{ - /* - * Given a mbuf containing an INIT or INIT-ACK with the param_offset - * being equal to the beginning of the params i.e. (iphlen + - * sizeof(struct sctp_init_msg) parse through the parameters to the - * end of the mbuf verifying that all parameters are known. - * - * For unknown parameters build and return a mbuf with - * UNRECOGNIZED_PARAMETER errors. If the flags indicate to stop - * processing this chunk stop, and set *abort_processing to 1. - * - * By having param_offset be pre-set to where parameters begin it is - * hoped that this routine may be reused in the future by new - * features. - */ - struct sctp_paramhdr *phdr, params; - - struct mbuf *mat, *m_tmp, *op_err, *op_err_last; - int at, limit, pad_needed; - uint16_t ptype, plen, padded_size; - - *abort_processing = 0; - if (cookie_found != NULL) { - *cookie_found = 0; - } - mat = in_initpkt; - limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk); - at = param_offset; - op_err = NULL; - op_err_last = NULL; - pad_needed = 0; - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Check for unrecognized param's\n"); - phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); - while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) { - ptype = ntohs(phdr->param_type); - plen = ntohs(phdr->param_length); - if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) { - /* wacked parameter */ - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error %d\n", plen); - goto invalid_size; - } - limit -= SCTP_SIZE32(plen); - /*- - * All parameters for all chunks that we know/understand are - * listed here. We process them other places and make - * appropriate stop actions per the upper bits. However this - * is the generic routine processor's can call to get back - * an operr.. to either incorporate (init-ack) or send. - */ - padded_size = SCTP_SIZE32(plen); - switch (ptype) { - /* Param's with variable size */ - case SCTP_HEARTBEAT_INFO: - case SCTP_UNRECOG_PARAM: - case SCTP_ERROR_CAUSE_IND: - /* ok skip fwd */ - at += padded_size; - break; - case SCTP_STATE_COOKIE: - if (cookie_found != NULL) { - *cookie_found = 1; - } - at += padded_size; - break; - /* Param's with variable size within a range */ - case SCTP_CHUNK_LIST: - case SCTP_SUPPORTED_CHUNK_EXT: - if (padded_size > (sizeof(struct sctp_supported_chunk_types_param) + (sizeof(uint8_t) * SCTP_MAX_SUPPORTED_EXT))) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error chklist %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_SUPPORTED_ADDRTYPE: - if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error supaddrtype %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_RANDOM: - if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error random %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_SET_PRIM_ADDR: - case SCTP_DEL_IP_ADDRESS: - case SCTP_ADD_IP_ADDRESS: - if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) && - (padded_size != sizeof(struct sctp_asconf_addr_param))) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error setprim %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - /* Param's with a fixed size */ - case SCTP_IPV4_ADDRESS: - if (padded_size != sizeof(struct sctp_ipv4addr_param)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ipv4 addr %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_IPV6_ADDRESS: - if (padded_size != sizeof(struct sctp_ipv6addr_param)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ipv6 addr %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_COOKIE_PRESERVE: - if (padded_size != sizeof(struct sctp_cookie_perserve_param)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error cookie-preserve %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_HAS_NAT_SUPPORT: - *nat_friendly = 1; - /* FALLTHROUGH */ - case SCTP_PRSCTP_SUPPORTED: - if (padded_size != sizeof(struct sctp_paramhdr)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error prsctp/nat support %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_ECN_CAPABLE: - if (padded_size != sizeof(struct sctp_paramhdr)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ecn %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_ULP_ADAPTATION: - if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error adapatation %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_SUCCESS_REPORT: - if (padded_size != sizeof(struct sctp_asconf_paramhdr)) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error success %d\n", plen); - goto invalid_size; - } - at += padded_size; - break; - case SCTP_HOSTNAME_ADDRESS: - { - /* Hostname parameters are deprecated. */ - struct sctp_gen_error_cause *cause; - int l_len; - - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Can't handle hostname addresses.. abort processing\n"); - *abort_processing = 1; - sctp_m_freem(op_err); - op_err = NULL; - op_err_last = NULL; -#ifdef INET6 - l_len = SCTP_MIN_OVERHEAD; -#else - l_len = SCTP_MIN_V4_OVERHEAD; -#endif - l_len += sizeof(struct sctp_chunkhdr); - l_len += sizeof(struct sctp_gen_error_cause); - op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); - if (op_err != NULL) { - /* - * Pre-reserve space for IP, SCTP, and - * chunk header. - */ -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); - cause = mtod(op_err, struct sctp_gen_error_cause *); - cause->code = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR); - cause->length = htons((uint16_t)(sizeof(struct sctp_gen_error_cause) + plen)); - SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT); - if (SCTP_BUF_NEXT(op_err) == NULL) { - sctp_m_freem(op_err); - op_err = NULL; - op_err_last = NULL; - } - } - return (op_err); - } - default: - /* - * we do not recognize the parameter figure out what - * we do. - */ - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Hit default param %x\n", ptype); - if ((ptype & 0x4000) == 0x4000) { - /* Report bit is set?? */ - SCTPDBG(SCTP_DEBUG_OUTPUT1, "report op err\n"); - if (op_err == NULL) { - int l_len; - /* Ok need to try to get an mbuf */ -#ifdef INET6 - l_len = SCTP_MIN_OVERHEAD; -#else - l_len = SCTP_MIN_V4_OVERHEAD; -#endif - l_len += sizeof(struct sctp_chunkhdr); - l_len += sizeof(struct sctp_paramhdr); - op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); - if (op_err) { - SCTP_BUF_LEN(op_err) = 0; -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - op_err_last = op_err; - } - } - if (op_err != NULL) { - /* If we have space */ - struct sctp_paramhdr *param; - - if (pad_needed > 0) { - op_err_last = sctp_add_pad_tombuf(op_err_last, pad_needed); - } - if (op_err_last == NULL) { - sctp_m_freem(op_err); - op_err = NULL; - op_err_last = NULL; - goto more_processing; - } - if (M_TRAILINGSPACE(op_err_last) < (int)sizeof(struct sctp_paramhdr)) { - m_tmp = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); - if (m_tmp == NULL) { - sctp_m_freem(op_err); - op_err = NULL; - op_err_last = NULL; - goto more_processing; - } - SCTP_BUF_LEN(m_tmp) = 0; - SCTP_BUF_NEXT(m_tmp) = NULL; - SCTP_BUF_NEXT(op_err_last) = m_tmp; - op_err_last = m_tmp; - } - param = (struct sctp_paramhdr *)(mtod(op_err_last, caddr_t) + SCTP_BUF_LEN(op_err_last)); - param->param_type = htons(SCTP_UNRECOG_PARAM); - param->param_length = htons((uint16_t)sizeof(struct sctp_paramhdr) + plen); - SCTP_BUF_LEN(op_err_last) += sizeof(struct sctp_paramhdr); - SCTP_BUF_NEXT(op_err_last) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT); - if (SCTP_BUF_NEXT(op_err_last) == NULL) { - sctp_m_freem(op_err); - op_err = NULL; - op_err_last = NULL; - goto more_processing; - } else { - while (SCTP_BUF_NEXT(op_err_last) != NULL) { - op_err_last = SCTP_BUF_NEXT(op_err_last); - } - } - if (plen % 4 != 0) { - pad_needed = 4 - (plen % 4); - } else { - pad_needed = 0; - } - } - } - more_processing: - if ((ptype & 0x8000) == 0x0000) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "stop proc\n"); - return (op_err); - } else { - /* skip this chunk and continue processing */ - SCTPDBG(SCTP_DEBUG_OUTPUT1, "move on\n"); - at += SCTP_SIZE32(plen); - } - break; - } - phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); - } - return (op_err); - invalid_size: - SCTPDBG(SCTP_DEBUG_OUTPUT1, "abort flag set\n"); - *abort_processing = 1; - sctp_m_freem(op_err); - op_err = NULL; - op_err_last = NULL; - if (phdr != NULL) { - struct sctp_paramhdr *param; - int l_len; -#ifdef INET6 - l_len = SCTP_MIN_OVERHEAD; -#else - l_len = SCTP_MIN_V4_OVERHEAD; -#endif - l_len += sizeof(struct sctp_chunkhdr); - l_len += (2 * sizeof(struct sctp_paramhdr)); - op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); - if (op_err) { - SCTP_BUF_LEN(op_err) = 0; -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - SCTP_BUF_LEN(op_err) = 2 * sizeof(struct sctp_paramhdr); - param = mtod(op_err, struct sctp_paramhdr *); - param->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); - param->param_length = htons(2 * sizeof(struct sctp_paramhdr)); - param++; - param->param_type = htons(ptype); - param->param_length = htons(plen); - } - } - return (op_err); -} - -/* - * Given a INIT chunk, look through the parameters to verify that there - * are no new addresses. - * Return true, if there is a new address or there is a problem parsing - the parameters. Provide an optional error cause used when sending an ABORT. - * Return false, if there are no new addresses and there is no problem in - parameter processing. - */ -static bool -sctp_are_there_new_addresses(struct sctp_association *asoc, - struct mbuf *in_initpkt, int offset, int limit, struct sockaddr *src, - struct mbuf **op_err) -{ - struct sockaddr *sa_touse; - struct sockaddr *sa; - struct sctp_paramhdr *phdr, params; - struct sctp_nets *net; -#ifdef INET - struct sockaddr_in sin4, *sa4; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6, *sa6; -#endif -#if defined(__Userspace__) - struct sockaddr_conn *sac; -#endif - uint16_t ptype, plen; - bool fnd, check_src; - - *op_err = NULL; -#ifdef INET - memset(&sin4, 0, sizeof(sin4)); - sin4.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin4.sin_len = sizeof(sin4); -#endif -#endif -#ifdef INET6 - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6.sin6_len = sizeof(sin6); -#endif -#endif - /* First what about the src address of the pkt ? */ - check_src = false; - switch (src->sa_family) { -#ifdef INET - case AF_INET: - if (asoc->scope.ipv4_addr_legal) { - check_src = true; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (asoc->scope.ipv6_addr_legal) { - check_src = true; - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (asoc->scope.conn_addr_legal) { - check_src = true; - } - break; -#endif - default: - /* TSNH */ - break; - } - if (check_src) { - fnd = false; - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - sa = (struct sockaddr *)&net->ro._l_addr; - if (sa->sa_family == src->sa_family) { -#ifdef INET - if (sa->sa_family == AF_INET) { - struct sockaddr_in *src4; - - sa4 = (struct sockaddr_in *)sa; - src4 = (struct sockaddr_in *)src; - if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) { - fnd = true; - break; - } - } -#endif -#ifdef INET6 - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *src6; - - sa6 = (struct sockaddr_in6 *)sa; - src6 = (struct sockaddr_in6 *)src; - if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) { - fnd = true; - break; - } - } -#endif -#if defined(__Userspace__) - if (sa->sa_family == AF_CONN) { - struct sockaddr_conn *srcc; - - sac = (struct sockaddr_conn *)sa; - srcc = (struct sockaddr_conn *)src; - if (sac->sconn_addr == srcc->sconn_addr) { - fnd = true; - break; - } - } -#endif - } - } - if (!fnd) { - /* - * If sending an ABORT in case of an additional address, - * don't use the new address error cause. - * This looks no different than if no listener was - * present. - */ - *op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Address added"); - return (true); - } - } - /* Ok so far lets munge through the rest of the packet */ - offset += sizeof(struct sctp_init_chunk); - phdr = sctp_get_next_param(in_initpkt, offset, ¶ms, sizeof(params)); - while (phdr) { - sa_touse = NULL; - ptype = ntohs(phdr->param_type); - plen = ntohs(phdr->param_length); - if (offset + plen > limit) { - *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Partial parameter"); - return (true); - } - if (plen < sizeof(struct sctp_paramhdr)) { - *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length too small"); - return (true); - } - switch (ptype) { -#ifdef INET - case SCTP_IPV4_ADDRESS: - { - struct sctp_ipv4addr_param *p4, p4_buf; - - if (plen != sizeof(struct sctp_ipv4addr_param)) { - *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length illegal"); - return (true); - } - phdr = sctp_get_next_param(in_initpkt, offset, - (struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf)); - if (phdr == NULL) { - *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); - return (true); - } - if (asoc->scope.ipv4_addr_legal) { - p4 = (struct sctp_ipv4addr_param *)phdr; - sin4.sin_addr.s_addr = p4->addr; - sa_touse = (struct sockaddr *)&sin4; - } - break; - } -#endif -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - { - struct sctp_ipv6addr_param *p6, p6_buf; - - if (plen != sizeof(struct sctp_ipv6addr_param)) { - *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length illegal"); - return (true); - } - phdr = sctp_get_next_param(in_initpkt, offset, - (struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf)); - if (phdr == NULL) { - *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); - return (true); - } - if (asoc->scope.ipv6_addr_legal) { - p6 = (struct sctp_ipv6addr_param *)phdr; - memcpy((caddr_t)&sin6.sin6_addr, p6->addr, - sizeof(p6->addr)); - sa_touse = (struct sockaddr *)&sin6; - } - break; - } -#endif - default: - sa_touse = NULL; - break; - } - if (sa_touse) { - /* ok, sa_touse points to one to check */ - fnd = false; - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - sa = (struct sockaddr *)&net->ro._l_addr; - if (sa->sa_family != sa_touse->sa_family) { - continue; - } -#ifdef INET - if (sa->sa_family == AF_INET) { - sa4 = (struct sockaddr_in *)sa; - if (sa4->sin_addr.s_addr == - sin4.sin_addr.s_addr) { - fnd = true; - break; - } - } -#endif -#ifdef INET6 - if (sa->sa_family == AF_INET6) { - sa6 = (struct sockaddr_in6 *)sa; - if (SCTP6_ARE_ADDR_EQUAL( - sa6, &sin6)) { - fnd = true; - break; - } - } -#endif - } - if (!fnd) { - /* - * If sending an ABORT in case of an additional - * address, don't use the new address error - * cause. - * This looks no different than if no listener - * was present. - */ - *op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Address added"); - return (true); - } - } - offset += SCTP_SIZE32(plen); - if (offset >= limit) { - break; - } - phdr = sctp_get_next_param(in_initpkt, offset, ¶ms, sizeof(params)); - } - return (false); -} - -/* - * Given a MBUF chain that was sent into us containing an INIT. Build a - * INIT-ACK with COOKIE and send back. We assume that the in_initpkt has done - * a pullup to include IPv6/4header, SCTP header and initial part of INIT - * message (i.e. the struct sctp_init_msg). - */ -void -sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *src_net, struct mbuf *init_pkt, - int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_init_chunk *init_chk, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_association *asoc; - struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err; - struct sctp_init_ack_chunk *initack; - struct sctp_adaptation_layer_indication *ali; - struct sctp_zero_checksum_acceptable *zero_chksum; - struct sctp_supported_chunk_types_param *pr_supported; - struct sctp_paramhdr *ph; - union sctp_sockstore *over_addr; - struct sctp_scoping scp; - struct timeval now; -#ifdef INET - struct sockaddr_in *dst4 = (struct sockaddr_in *)dst; - struct sockaddr_in *src4 = (struct sockaddr_in *)src; - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; - struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)src; - struct sockaddr_in6 *sin6; -#endif -#if defined(__Userspace__) - struct sockaddr_conn *dstconn = (struct sockaddr_conn *)dst; - struct sockaddr_conn *srcconn = (struct sockaddr_conn *)src; - struct sockaddr_conn *sconn; -#endif - struct sockaddr *to; - struct sctp_state_cookie stc; - struct sctp_nets *net = NULL; - uint8_t *signature = NULL; - int cnt_inits_to = 0; - uint16_t his_limit, i_want; - int abort_flag; - int nat_friendly = 0; - int error; - struct socket *so; - uint16_t num_ext, chunk_len, padding_len, parameter_len; - - if (stcb) { - asoc = &stcb->asoc; - } else { - asoc = NULL; - } - if ((asoc != NULL) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT)) { - if (sctp_are_there_new_addresses(asoc, init_pkt, offset, offset + ntohs(init_chk->ch.chunk_length), src, &op_err)) { - /* - * new addresses, out of here in non-cookie-wait states - */ - sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - return; - } - if (src_net != NULL && (src_net->port != port)) { - /* - * change of remote encapsulation port, out of here in - * non-cookie-wait states - * - * Send an ABORT, without an specific error cause. - * This looks no different than if no listener - * was present. - */ - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Remote encapsulation port changed"); - sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - return; - } - } - abort_flag = 0; - op_err = sctp_arethere_unrecognized_parameters(init_pkt, - (offset + sizeof(struct sctp_init_chunk)), - &abort_flag, - (struct sctp_chunkhdr *)init_chk, - &nat_friendly, NULL); - if (abort_flag) { - do_a_abort: - if (op_err == NULL) { - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "%s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - } - sctp_send_abort(init_pkt, iphlen, src, dst, sh, - init_chk->init.initiate_tag, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - return; - } - m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (m == NULL) { - /* No memory, INIT timer will re-attempt. */ - sctp_m_freem(op_err); - return; - } - chunk_len = (uint16_t)sizeof(struct sctp_init_ack_chunk); - padding_len = 0; - - /* - * We might not overwrite the identification[] completely and on - * some platforms time_entered will contain some padding. - * Therefore zero out the cookie to avoid putting - * uninitialized memory on the wire. - */ - memset(&stc, 0, sizeof(struct sctp_state_cookie)); - - /* the time I built cookie */ - (void)SCTP_GETTIME_TIMEVAL(&now); - stc.time_entered.tv_sec = now.tv_sec; - stc.time_entered.tv_usec = now.tv_usec; - - /* populate any tie tags */ - if (asoc != NULL) { - /* unlock before tag selections */ - stc.tie_tag_my_vtag = asoc->my_vtag_nonce; - stc.tie_tag_peer_vtag = asoc->peer_vtag_nonce; - stc.cookie_life = asoc->cookie_life; - net = asoc->primary_destination; - } else { - stc.tie_tag_my_vtag = 0; - stc.tie_tag_peer_vtag = 0; - /* life I will award this cookie */ - stc.cookie_life = inp->sctp_ep.def_cookie_life; - } - - /* copy in the ports for later check */ - stc.myport = sh->dest_port; - stc.peerport = sh->src_port; - - /* - * If we wanted to honor cookie life extensions, we would add to - * stc.cookie_life. For now we should NOT honor any extension - */ - stc.site_scope = stc.local_scope = stc.loopback_scope = 0; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - stc.ipv6_addr_legal = 1; - if (SCTP_IPV6_V6ONLY(inp)) { - stc.ipv4_addr_legal = 0; - } else { - stc.ipv4_addr_legal = 1; - } -#if defined(__Userspace__) - stc.conn_addr_legal = 0; -#endif - } else { - stc.ipv6_addr_legal = 0; -#if defined(__Userspace__) - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - stc.conn_addr_legal = 1; - stc.ipv4_addr_legal = 0; - } else { - stc.conn_addr_legal = 0; - stc.ipv4_addr_legal = 1; - } -#else - stc.ipv4_addr_legal = 1; -#endif - } - stc.ipv4_scope = 0; - if (net == NULL) { - to = src; - switch (dst->sa_family) { -#ifdef INET - case AF_INET: - { - /* lookup address */ - stc.address[0] = src4->sin_addr.s_addr; - stc.address[1] = 0; - stc.address[2] = 0; - stc.address[3] = 0; - stc.addr_type = SCTP_IPV4_ADDRESS; - /* local from address */ - stc.laddress[0] = dst4->sin_addr.s_addr; - stc.laddress[1] = 0; - stc.laddress[2] = 0; - stc.laddress[3] = 0; - stc.laddr_type = SCTP_IPV4_ADDRESS; - /* scope_id is only for v6 */ - stc.scope_id = 0; - if ((IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) || - (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))) { - stc.ipv4_scope = 1; - } - /* Must use the address in this case */ - if (sctp_is_address_on_local_host(src, vrf_id)) { - stc.loopback_scope = 1; - stc.ipv4_scope = 1; - stc.site_scope = 1; - stc.local_scope = 0; - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - stc.addr_type = SCTP_IPV6_ADDRESS; - memcpy(&stc.address, &src6->sin6_addr, sizeof(struct in6_addr)); -#if defined(__FreeBSD__) && !defined(__Userspace__) - stc.scope_id = ntohs(in6_getscope(&src6->sin6_addr)); -#else - stc.scope_id = 0; -#endif - if (sctp_is_address_on_local_host(src, vrf_id)) { - stc.loopback_scope = 1; - stc.local_scope = 0; - stc.site_scope = 1; - stc.ipv4_scope = 1; - } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr) || - IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) { - /* - * If the new destination or source is a - * LINK_LOCAL we must have common both site and - * local scope. Don't set local scope though - * since we must depend on the source to be - * added implicitly. We cannot assure just - * because we share one link that all links are - * common. - */ -#if defined(__APPLE__) && !defined(__Userspace__) - /* Mac OS X currently doesn't have in6_getscope() */ - stc.scope_id = src6->sin6_addr.s6_addr16[1]; -#endif - stc.local_scope = 0; - stc.site_scope = 1; - stc.ipv4_scope = 1; - /* - * we start counting for the private address - * stuff at 1. since the link local we - * source from won't show up in our scoped - * count. - */ - cnt_inits_to = 1; - /* pull out the scope_id from incoming pkt */ - } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr) || - IN6_IS_ADDR_SITELOCAL(&dst6->sin6_addr)) { - /* - * If the new destination or source is - * SITE_LOCAL then we must have site scope in - * common. - */ - stc.site_scope = 1; - } - memcpy(&stc.laddress, &dst6->sin6_addr, sizeof(struct in6_addr)); - stc.laddr_type = SCTP_IPV6_ADDRESS; - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - /* lookup address */ - stc.address[0] = 0; - stc.address[1] = 0; - stc.address[2] = 0; - stc.address[3] = 0; - memcpy(&stc.address, &srcconn->sconn_addr, sizeof(void *)); - stc.addr_type = SCTP_CONN_ADDRESS; - /* local from address */ - stc.laddress[0] = 0; - stc.laddress[1] = 0; - stc.laddress[2] = 0; - stc.laddress[3] = 0; - memcpy(&stc.laddress, &dstconn->sconn_addr, sizeof(void *)); - stc.laddr_type = SCTP_CONN_ADDRESS; - /* scope_id is only for v6 */ - stc.scope_id = 0; - break; - } -#endif - default: - /* TSNH */ - goto do_a_abort; - break; - } - } else { - /* set the scope per the existing tcb */ - -#ifdef INET6 - struct sctp_nets *lnet; -#endif - - stc.loopback_scope = asoc->scope.loopback_scope; - stc.ipv4_scope = asoc->scope.ipv4_local_scope; - stc.site_scope = asoc->scope.site_scope; - stc.local_scope = asoc->scope.local_scope; -#ifdef INET6 - /* Why do we not consider IPv4 LL addresses? */ - TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { - if (lnet->ro._l_addr.sin6.sin6_family == AF_INET6) { - if (IN6_IS_ADDR_LINKLOCAL(&lnet->ro._l_addr.sin6.sin6_addr)) { - /* - * if we have a LL address, start - * counting at 1. - */ - cnt_inits_to = 1; - } - } - } -#endif - /* use the net pointer */ - to = (struct sockaddr *)&net->ro._l_addr; - switch (to->sa_family) { -#ifdef INET - case AF_INET: - sin = (struct sockaddr_in *)to; - stc.address[0] = sin->sin_addr.s_addr; - stc.address[1] = 0; - stc.address[2] = 0; - stc.address[3] = 0; - stc.addr_type = SCTP_IPV4_ADDRESS; - if (net->src_addr_selected == 0) { - /* - * strange case here, the INIT should have - * did the selection. - */ - net->ro._s_addr = sctp_source_address_selection(inp, - stcb, (sctp_route_t *)&net->ro, - net, 0, vrf_id); - if (net->ro._s_addr == NULL) { - sctp_m_freem(op_err); - sctp_m_freem(m); - return; - } - - net->src_addr_selected = 1; - } - stc.laddress[0] = net->ro._s_addr->address.sin.sin_addr.s_addr; - stc.laddress[1] = 0; - stc.laddress[2] = 0; - stc.laddress[3] = 0; - stc.laddr_type = SCTP_IPV4_ADDRESS; - /* scope_id is only for v6 */ - stc.scope_id = 0; - break; -#endif -#ifdef INET6 - case AF_INET6: - sin6 = (struct sockaddr_in6 *)to; - memcpy(&stc.address, &sin6->sin6_addr, - sizeof(struct in6_addr)); - stc.addr_type = SCTP_IPV6_ADDRESS; - stc.scope_id = sin6->sin6_scope_id; - if (net->src_addr_selected == 0) { - /* - * strange case here, the INIT should have - * done the selection. - */ - net->ro._s_addr = sctp_source_address_selection(inp, - stcb, (sctp_route_t *)&net->ro, - net, 0, vrf_id); - if (net->ro._s_addr == NULL) { - sctp_m_freem(op_err); - sctp_m_freem(m); - return; - } - - net->src_addr_selected = 1; - } - memcpy(&stc.laddress, &net->ro._s_addr->address.sin6.sin6_addr, - sizeof(struct in6_addr)); - stc.laddr_type = SCTP_IPV6_ADDRESS; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - sconn = (struct sockaddr_conn *)to; - stc.address[0] = 0; - stc.address[1] = 0; - stc.address[2] = 0; - stc.address[3] = 0; - memcpy(&stc.address, &sconn->sconn_addr, sizeof(void *)); - stc.addr_type = SCTP_CONN_ADDRESS; - stc.laddress[0] = 0; - stc.laddress[1] = 0; - stc.laddress[2] = 0; - stc.laddress[3] = 0; - memcpy(&stc.laddress, &sconn->sconn_addr, sizeof(void *)); - stc.laddr_type = SCTP_CONN_ADDRESS; - stc.scope_id = 0; - break; -#endif - } - } - if (asoc != NULL) { - stc.rcv_edmid = asoc->rcv_edmid; - } else { - stc.rcv_edmid = inp->rcv_edmid; - } - /* Now lets put the SCTP header in place */ - initack = mtod(m, struct sctp_init_ack_chunk *); - /* Save it off for quick ref */ - stc.peers_vtag = ntohl(init_chk->init.initiate_tag); - /* who are we */ - memcpy(stc.identification, SCTP_VERSION_STRING, - min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification))); - memset(stc.reserved, 0, SCTP_RESERVE_SPACE); - /* now the chunk header */ - initack->ch.chunk_type = SCTP_INITIATION_ACK; - initack->ch.chunk_flags = 0; - /* fill in later from mbuf we build */ - initack->ch.chunk_length = 0; - /* place in my tag */ - if ((asoc != NULL) && - ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_INUSE) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED))) { - /* re-use the v-tags and init-seq here */ - initack->init.initiate_tag = htonl(asoc->my_vtag); - initack->init.initial_tsn = htonl(asoc->init_seq_number); - } else { - uint32_t vtag, itsn; - - if (asoc) { - atomic_add_int(&asoc->refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - new_tag: - SCTP_INP_INFO_RLOCK(); - vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); - SCTP_INP_INFO_RUNLOCK(); - if ((asoc->peer_supports_nat) && (vtag == asoc->my_vtag)) { - /* Got a duplicate vtag on some guy behind a nat - * make sure we don't use it. - */ - goto new_tag; - } - initack->init.initiate_tag = htonl(vtag); - /* get a TSN to use too */ - itsn = sctp_select_initial_TSN(&inp->sctp_ep); - initack->init.initial_tsn = htonl(itsn); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&asoc->refcnt, 1); - } else { - SCTP_INP_INCR_REF(inp); - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RLOCK(); - vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); - SCTP_INP_INFO_RUNLOCK(); - initack->init.initiate_tag = htonl(vtag); - /* get a TSN to use too */ - initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); - SCTP_INP_RLOCK(inp); - SCTP_INP_DECR_REF(inp); - } - } - /* save away my tag to */ - stc.my_vtag = initack->init.initiate_tag; - - /* set up some of the credits. */ - so = inp->sctp_socket; - if (so == NULL) { - /* memory problem */ - sctp_m_freem(op_err); - sctp_m_freem(m); - return; - } else { - initack->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND)); - } - /* set what I want */ - his_limit = ntohs(init_chk->init.num_inbound_streams); - /* choose what I want */ - if (asoc != NULL) { - if (asoc->streamoutcnt > asoc->pre_open_streams) { - i_want = asoc->streamoutcnt; - } else { - i_want = asoc->pre_open_streams; - } - } else { - i_want = inp->sctp_ep.pre_open_stream_count; - } - if (his_limit < i_want) { - /* I Want more :< */ - initack->init.num_outbound_streams = init_chk->init.num_inbound_streams; - } else { - /* I can have what I want :> */ - initack->init.num_outbound_streams = htons(i_want); - } - /* tell him his limit. */ - initack->init.num_inbound_streams = - htons(inp->sctp_ep.max_open_streams_intome); - - /* adaptation layer indication parameter */ - if (inp->sctp_ep.adaptation_layer_indicator_provided) { - parameter_len = (uint16_t)sizeof(struct sctp_adaptation_layer_indication); - ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t) + chunk_len); - ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); - ali->ph.param_length = htons(parameter_len); - ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator); - chunk_len += parameter_len; - } - - /* ECN parameter */ - if (((asoc != NULL) && (asoc->ecn_supported == 1)) || - ((asoc == NULL) && (inp->ecn_supported == 1))) { - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); - ph->param_type = htons(SCTP_ECN_CAPABLE); - ph->param_length = htons(parameter_len); - chunk_len += parameter_len; - } - - /* PR-SCTP supported parameter */ - if (((asoc != NULL) && (asoc->prsctp_supported == 1)) || - ((asoc == NULL) && (inp->prsctp_supported == 1))) { - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); - ph->param_type = htons(SCTP_PRSCTP_SUPPORTED); - ph->param_length = htons(parameter_len); - chunk_len += parameter_len; - } - - /* Zero checksum acceptable parameter */ - if (((asoc != NULL) && (asoc->rcv_edmid != SCTP_EDMID_NONE)) || - ((asoc == NULL) && (inp->rcv_edmid != SCTP_EDMID_NONE))) { - parameter_len = (uint16_t)sizeof(struct sctp_zero_checksum_acceptable); - zero_chksum = (struct sctp_zero_checksum_acceptable *)(mtod(m, caddr_t) + chunk_len); - zero_chksum->ph.param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE); - zero_chksum->ph.param_length = htons(parameter_len); - if (asoc != NULL) { - zero_chksum->edmid = htonl(asoc->rcv_edmid); - } else { - zero_chksum->edmid = htonl(inp->rcv_edmid); - } - chunk_len += parameter_len; - } - - /* Add NAT friendly parameter */ - if (nat_friendly) { - parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); - ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); - ph->param_length = htons(parameter_len); - chunk_len += parameter_len; - } - - /* And now tell the peer which extensions we support */ - num_ext = 0; - pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t) + chunk_len); - if (((asoc != NULL) && (asoc->prsctp_supported == 1)) || - ((asoc == NULL) && (inp->prsctp_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; - if (((asoc != NULL) && (asoc->idata_supported == 1)) || - ((asoc == NULL) && (inp->idata_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN; - } - } - if (((asoc != NULL) && (asoc->auth_supported == 1)) || - ((asoc == NULL) && (inp->auth_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; - } - if (((asoc != NULL) && (asoc->asconf_supported == 1)) || - ((asoc == NULL) && (inp->asconf_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; - } - if (((asoc != NULL) && (asoc->reconfig_supported == 1)) || - ((asoc == NULL) && (inp->reconfig_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; - } - if (((asoc != NULL) && (asoc->idata_supported == 1)) || - ((asoc == NULL) && (inp->idata_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_IDATA; - } - if (((asoc != NULL) && (asoc->nrsack_supported == 1)) || - ((asoc == NULL) && (inp->nrsack_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; - } - if (((asoc != NULL) && (asoc->pktdrop_supported == 1)) || - ((asoc == NULL) && (inp->pktdrop_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; - } - if (num_ext > 0) { - parameter_len = (uint16_t)sizeof(struct sctp_supported_chunk_types_param) + num_ext; - pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); - pr_supported->ph.param_length = htons(parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - } - - /* add authentication parameters */ - if (((asoc != NULL) && (asoc->auth_supported == 1)) || - ((asoc == NULL) && (inp->auth_supported == 1))) { - struct sctp_auth_random *randp; - struct sctp_auth_hmac_algo *hmacs; - struct sctp_auth_chunk_list *chunks; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - /* generate and add RANDOM parameter */ - randp = (struct sctp_auth_random *)(mtod(m, caddr_t) + chunk_len); - parameter_len = (uint16_t)sizeof(struct sctp_auth_random) + - SCTP_AUTH_RANDOM_SIZE_DEFAULT; - randp->ph.param_type = htons(SCTP_RANDOM); - randp->ph.param_length = htons(parameter_len); - SCTP_READ_RANDOM(randp->random_data, SCTP_AUTH_RANDOM_SIZE_DEFAULT); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - /* add HMAC_ALGO parameter */ - hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t) + chunk_len); - parameter_len = (uint16_t)sizeof(struct sctp_auth_hmac_algo) + - sctp_serialize_hmaclist(inp->sctp_ep.local_hmacs, - (uint8_t *)hmacs->hmac_ids); - hmacs->ph.param_type = htons(SCTP_HMAC_LIST); - hmacs->ph.param_length = htons(parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - padding_len = 0; - } - /* add CHUNKS parameter */ - chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t) + chunk_len); - parameter_len = (uint16_t)sizeof(struct sctp_auth_chunk_list) + - sctp_serialize_auth_chunks(inp->sctp_ep.local_auth_chunks, - chunks->chunk_types); - chunks->ph.param_type = htons(SCTP_CHUNK_LIST); - chunks->ph.param_length = htons(parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - } - SCTP_BUF_LEN(m) = chunk_len; - m_last = m; - /* now the addresses */ - /* To optimize this we could put the scoping stuff - * into a structure and remove the individual uint8's from - * the stc structure. Then we could just sifa in the - * address within the stc.. but for now this is a quick - * hack to get the address stuff teased apart. - */ - scp.ipv4_addr_legal = stc.ipv4_addr_legal; - scp.ipv6_addr_legal = stc.ipv6_addr_legal; -#if defined(__Userspace__) - scp.conn_addr_legal = stc.conn_addr_legal; -#endif - scp.loopback_scope = stc.loopback_scope; - scp.ipv4_local_scope = stc.ipv4_scope; - scp.local_scope = stc.local_scope; - scp.site_scope = stc.site_scope; - m_last = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_last, - cnt_inits_to, - &padding_len, &chunk_len); - /* padding_len can only be positive, if no addresses have been added */ - if (padding_len > 0) { - memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); - chunk_len += padding_len; - SCTP_BUF_LEN(m) += padding_len; - padding_len = 0; - } - - /* tack on the operational error if present */ - if (op_err) { - parameter_len = 0; - for (m_tmp = op_err; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) { - parameter_len += SCTP_BUF_LEN(m_tmp); - } - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - SCTP_BUF_NEXT(m_last) = op_err; - while (SCTP_BUF_NEXT(m_last) != NULL) { - m_last = SCTP_BUF_NEXT(m_last); - } - chunk_len += parameter_len; - } - if (padding_len > 0) { - m_last = sctp_add_pad_tombuf(m_last, padding_len); - if (m_last == NULL) { - /* Houston we have a problem, no space */ - sctp_m_freem(m); - return; - } - chunk_len += padding_len; - padding_len = 0; - } - /* Now we must build a cookie */ - m_cookie = sctp_add_cookie(init_pkt, offset, m, 0, &stc, &signature); - if (m_cookie == NULL) { - /* memory problem */ - sctp_m_freem(m); - return; - } - /* Now append the cookie to the end and update the space/size */ - SCTP_BUF_NEXT(m_last) = m_cookie; - parameter_len = 0; - for (m_tmp = m_cookie; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) { - parameter_len += SCTP_BUF_LEN(m_tmp); - if (SCTP_BUF_NEXT(m_tmp) == NULL) { - m_last = m_tmp; - } - } - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - - /* Place in the size, but we don't include - * the last pad (if any) in the INIT-ACK. - */ - initack->ch.chunk_length = htons(chunk_len); - - /* Time to sign the cookie, we don't sign over the cookie - * signature though thus we set trailer. - */ - (void)sctp_hmac_m(SCTP_HMAC, - (uint8_t *)inp->sctp_ep.secret_key[(int)(inp->sctp_ep.current_secret_number)], - SCTP_SECRET_SIZE, m_cookie, sizeof(struct sctp_paramhdr), - (uint8_t *)signature, SCTP_SIGNATURE_SIZE); -#if defined(__Userspace__) - /* - * Don't put AF_CONN addresses on the wire, in case this is critical - * for the application. However, they are protected by the HMAC and - * need to be reconstructed before checking the HMAC. - * Clearing is only done in the mbuf chain, since the local stc is - * not used anymore. - */ - if (stc.addr_type == SCTP_CONN_ADDRESS) { - const void *p = NULL; - - m_copyback(m_cookie, sizeof(struct sctp_paramhdr) + offsetof(struct sctp_state_cookie, address), - (int)sizeof(void *), (caddr_t)&p); - } - if (stc.laddr_type == SCTP_CONN_ADDRESS) { - const void *p = NULL; - - m_copyback(m_cookie, sizeof(struct sctp_paramhdr) + offsetof(struct sctp_state_cookie, laddress), - (int)sizeof(void *), (caddr_t)&p); - } -#endif - /* - * We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return - * here since the timer will drive a retranmission. - */ - if (padding_len > 0) { - if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) { - sctp_m_freem(m); - return; - } - } - if (stc.loopback_scope) { - over_addr = (union sctp_sockstore *)dst; - } else { - over_addr = NULL; - } - - if ((error = sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0, - 0, 0, - inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag, - port, over_addr, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, -#endif - false, /* XXXMT: Improve this! */ - SCTP_SO_NOT_LOCKED))) { - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error); - if (error == ENOBUFS) { - if (asoc != NULL) { - asoc->ifp_had_enobuf = 1; - } - SCTP_STAT_INCR(sctps_lowlevelerr); - } - } else { - if (asoc != NULL) { - asoc->ifp_had_enobuf = 0; - } - } - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); -} - -static void -sctp_prune_prsctp(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_nonpad_sndrcvinfo *srcv, - int dataout) -{ - int freed_spc = 0; - struct sctp_tmit_chunk *chk, *nchk; - - SCTP_TCB_LOCK_ASSERT(stcb); - if ((asoc->prsctp_supported) && - (asoc->sent_queue_cnt_removeable > 0)) { - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - /* - * Look for chunks marked with the PR_SCTP flag AND - * the buffer space flag. If the one being sent is - * equal or greater priority then purge the old one - * and free some space. - */ - if (PR_SCTP_BUF_ENABLED(chk->flags)) { - /* - * This one is PR-SCTP AND buffer space - * limited type - */ - if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) { - /* - * Lower numbers equates to higher - * priority. So if the one we are - * looking at has a larger priority, - * we want to drop the data and NOT - * retransmit it. - */ - if (chk->data) { - /* - * We release the book_size - * if the mbuf is here - */ - int ret_spc; - uint8_t sent; - - if (chk->sent > SCTP_DATAGRAM_UNSENT) - sent = 1; - else - sent = 0; - ret_spc = sctp_release_pr_sctp_chunk(stcb, chk, - sent, - SCTP_SO_LOCKED); - freed_spc += ret_spc; - if (freed_spc >= dataout) { - return; - } - } /* if chunk was present */ - } /* if of sufficient priority */ - } /* if chunk has enabled */ - } /* tailqforeach */ - - TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { - /* Here we must move to the sent queue and mark */ - if (PR_SCTP_BUF_ENABLED(chk->flags)) { - if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) { - if (chk->data) { - /* - * We release the book_size - * if the mbuf is here - */ - int ret_spc; - - ret_spc = sctp_release_pr_sctp_chunk(stcb, chk, - 0, SCTP_SO_LOCKED); - - freed_spc += ret_spc; - if (freed_spc >= dataout) { - return; - } - } /* end if chk->data */ - } /* end if right class */ - } /* end if chk pr-sctp */ - } /* tailqforeachsafe (chk) */ - } /* if enabled in asoc */ -} - -uint32_t -sctp_get_frag_point(struct sctp_tcb *stcb) -{ - struct sctp_association *asoc; - uint32_t frag_point, overhead; - - asoc = &stcb->asoc; - /* Consider IP header and SCTP common header. */ - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - overhead = SCTP_MIN_OVERHEAD; - } else { -#if defined(__Userspace__) - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - overhead = sizeof(struct sctphdr); - } else { - overhead = SCTP_MIN_V4_OVERHEAD; - } -#else - overhead = SCTP_MIN_V4_OVERHEAD; -#endif - } - /* Consider DATA/IDATA chunk header and AUTH header, if needed. */ - if (asoc->idata_supported) { - overhead += sizeof(struct sctp_idata_chunk); - if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) { - overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); - } - } else { - overhead += sizeof(struct sctp_data_chunk); - if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) { - overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); - } - } - KASSERT(overhead % 4 == 0, - ("overhead (%u) not a multiple of 4", overhead)); - /* Consider padding. */ - if (asoc->smallest_mtu % 4 > 0) { - overhead += (asoc->smallest_mtu % 4); - } - KASSERT(asoc->smallest_mtu > overhead, - ("Association MTU (%u) too small for overhead (%u)", - asoc->smallest_mtu, overhead)); - frag_point = asoc->smallest_mtu - overhead; - KASSERT(frag_point % 4 == 0, - ("frag_point (%u) not a multiple of 4", frag_point)); - /* Honor MAXSEG socket option. */ - if ((asoc->sctp_frag_point > 0) && - (asoc->sctp_frag_point < frag_point)) { - frag_point = asoc->sctp_frag_point; - } - return (frag_point); -} - -static void -sctp_set_prsctp_policy(struct sctp_stream_queue_pending *sp) -{ - /* - * We assume that the user wants PR_SCTP_TTL if the user - * provides a positive lifetime but does not specify any - * PR_SCTP policy. - */ - if (PR_SCTP_ENABLED(sp->sinfo_flags)) { - sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags); - } else if (sp->timetolive > 0) { - sp->sinfo_flags |= SCTP_PR_SCTP_TTL; - sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags); - } else { - return; - } - switch (PR_SCTP_POLICY(sp->sinfo_flags)) { - case CHUNK_FLAGS_PR_SCTP_BUF: - /* - * Time to live is a priority stored in tv_sec when - * doing the buffer drop thing. - */ - sp->ts.tv_sec = sp->timetolive; - sp->ts.tv_usec = 0; - break; - case CHUNK_FLAGS_PR_SCTP_TTL: - { - struct timeval tv; - (void)SCTP_GETTIME_TIMEVAL(&sp->ts); - tv.tv_sec = sp->timetolive / 1000; - tv.tv_usec = (sp->timetolive * 1000) % 1000000; - /* TODO sctp_constants.h needs alternative time macros when - * _KERNEL is undefined. - */ -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - timeradd(&sp->ts, &tv, &sp->ts); -#else - timevaladd(&sp->ts, &tv); -#endif - } - break; - case CHUNK_FLAGS_PR_SCTP_RTX: - /* - * Time to live is a the number or retransmissions - * stored in tv_sec. - */ - sp->ts.tv_sec = sp->timetolive; - sp->ts.tv_usec = 0; - break; - default: - SCTPDBG(SCTP_DEBUG_USRREQ1, - "Unknown PR_SCTP policy %u.\n", - PR_SCTP_POLICY(sp->sinfo_flags)); - break; - } -} - -static int -sctp_msg_append(struct sctp_tcb *stcb, - struct sctp_nets *net, - struct mbuf *m, - struct sctp_nonpad_sndrcvinfo *srcv) -{ - int error = 0; - struct mbuf *at; - struct sctp_stream_queue_pending *sp = NULL; - struct sctp_stream_out *strm; - - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Given an mbuf chain, put it - * into the association send queue and - * place it on the wheel - */ - if (srcv->sinfo_stream >= stcb->asoc.streamoutcnt) { - /* Invalid stream number */ - SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_now; - } - if ((stcb->asoc.stream_locked) && - (stcb->asoc.stream_locked_on != srcv->sinfo_stream)) { - SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_now; - } - if ((stcb->asoc.strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPEN) && - (stcb->asoc.strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPENING)) { - /* - * Can't queue any data while stream reset is underway. - */ - if (stcb->asoc.strmout[srcv->sinfo_stream].state > SCTP_STREAM_OPEN) { - error = EAGAIN; - } else { - error = EINVAL; - } - goto out_now; - } - /* Now can we send this? */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || - (stcb->asoc.state & SCTP_STATE_SHUTDOWN_PENDING)) { - /* got data while shutting down */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EPIPE); - error = EPIPE; - goto out_now; - } - sctp_alloc_a_strmoq(stcb, sp); - if (sp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - error = ENOMEM; - goto out_now; - } - sp->sinfo_flags = srcv->sinfo_flags; - sp->timetolive = srcv->sinfo_timetolive; - sp->ppid = srcv->sinfo_ppid; - sp->context = srcv->sinfo_context; - sp->fsn = 0; - if (sp->sinfo_flags & SCTP_ADDR_OVER) { - sp->net = net; - atomic_add_int(&sp->net->ref_count, 1); - } else { - sp->net = NULL; - } - (void)SCTP_GETTIME_TIMEVAL(&sp->ts); - sp->sid = srcv->sinfo_stream; - sp->msg_is_complete = 1; - sp->sender_all_done = 1; - sp->some_taken = 0; - sp->data = m; - sp->tail_mbuf = NULL; - sctp_set_prsctp_policy(sp); - /* We could in theory (for sendall) sifa the length - * in, but we would still have to hunt through the - * chain since we need to setup the tail_mbuf - */ - sp->length = 0; - for (at = m; at; at = SCTP_BUF_NEXT(at)) { - if (SCTP_BUF_NEXT(at) == NULL) - sp->tail_mbuf = at; - sp->length += SCTP_BUF_LEN(at); - } - if (srcv->sinfo_keynumber_valid) { - sp->auth_keyid = srcv->sinfo_keynumber; - } else { - sp->auth_keyid = stcb->asoc.authinfo.active_keyid; - } - if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { - sctp_auth_key_acquire(stcb, sp->auth_keyid); - sp->holds_key_ref = 1; - } - strm = &stcb->asoc.strmout[srcv->sinfo_stream]; - sctp_snd_sb_alloc(stcb, sp->length); - atomic_add_int(&stcb->asoc.stream_queue_cnt, 1); - TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc, strm, sp); - m = NULL; -out_now: - if (m) { - sctp_m_freem(m); - } - return (error); -} - -static struct mbuf * -sctp_copy_mbufchain(struct mbuf *clonechain, - struct mbuf *outchain, - struct mbuf **endofchain, - int can_take_mbuf, - int sizeofcpy, - uint8_t copy_by_ref) -{ - struct mbuf *m; - struct mbuf *appendchain; - caddr_t cp; - int len; - - if (endofchain == NULL) { - /* error */ - error_out: - if (outchain) - sctp_m_freem(outchain); - return (NULL); - } - if (can_take_mbuf) { - appendchain = clonechain; - } else { - if (!copy_by_ref && - (sizeofcpy <= (int)((((SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count) - 1) * MLEN) + MHLEN)))) { - /* Its not in a cluster */ - if (*endofchain == NULL) { - /* lets get a mbuf cluster */ - if (outchain == NULL) { - /* This is the general case */ - new_mbuf: - outchain = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_HEADER); - if (outchain == NULL) { - goto error_out; - } - SCTP_BUF_LEN(outchain) = 0; - *endofchain = outchain; - /* get the prepend space */ - SCTP_BUF_RESV_UF(outchain, (SCTP_FIRST_MBUF_RESV+4)); - } else { - /* We really should not get a NULL in endofchain */ - /* find end */ - m = outchain; - while (m) { - if (SCTP_BUF_NEXT(m) == NULL) { - *endofchain = m; - break; - } - m = SCTP_BUF_NEXT(m); - } - /* sanity */ - if (*endofchain == NULL) { - /* huh, TSNH XXX maybe we should panic */ - sctp_m_freem(outchain); - goto new_mbuf; - } - } - /* get the new end of length */ - len = (int)M_TRAILINGSPACE(*endofchain); - } else { - /* how much is left at the end? */ - len = (int)M_TRAILINGSPACE(*endofchain); - } - /* Find the end of the data, for appending */ - cp = (mtod((*endofchain), caddr_t) + SCTP_BUF_LEN((*endofchain))); - - /* Now lets copy it out */ - if (len >= sizeofcpy) { - /* It all fits, copy it in */ - m_copydata(clonechain, 0, sizeofcpy, cp); - SCTP_BUF_LEN((*endofchain)) += sizeofcpy; - } else { - /* fill up the end of the chain */ - if (len > 0) { - m_copydata(clonechain, 0, len, cp); - SCTP_BUF_LEN((*endofchain)) += len; - /* now we need another one */ - sizeofcpy -= len; - } - m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_HEADER); - if (m == NULL) { - /* We failed */ - goto error_out; - } - SCTP_BUF_NEXT((*endofchain)) = m; - *endofchain = m; - cp = mtod((*endofchain), caddr_t); - m_copydata(clonechain, len, sizeofcpy, cp); - SCTP_BUF_LEN((*endofchain)) += sizeofcpy; - } - return (outchain); - } else { - /* copy the old fashion way */ - appendchain = SCTP_M_COPYM(clonechain, 0, M_COPYALL, M_NOWAIT); -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(appendchain, SCTP_MBUF_ICOPY); - } -#endif - } - } - if (appendchain == NULL) { - /* error */ - if (outchain) - sctp_m_freem(outchain); - return (NULL); - } - if (outchain) { - /* tack on to the end */ - if (*endofchain != NULL) { - SCTP_BUF_NEXT(((*endofchain))) = appendchain; - } else { - m = outchain; - while (m) { - if (SCTP_BUF_NEXT(m) == NULL) { - SCTP_BUF_NEXT(m) = appendchain; - break; - } - m = SCTP_BUF_NEXT(m); - } - } - /* - * save off the end and update the end-chain - * position - */ - m = appendchain; - while (m) { - if (SCTP_BUF_NEXT(m) == NULL) { - *endofchain = m; - break; - } - m = SCTP_BUF_NEXT(m); - } - return (outchain); - } else { - /* save off the end and update the end-chain position */ - m = appendchain; - while (m) { - if (SCTP_BUF_NEXT(m) == NULL) { - *endofchain = m; - break; - } - m = SCTP_BUF_NEXT(m); - } - return (appendchain); - } -} - -static int -sctp_med_chunk_output(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_association *asoc, - int *num_out, - int *reason_code, - int control_only, int from_where, - struct timeval *now, int *now_filled, - uint32_t frag_point, int so_locked); - -static void -sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, - uint32_t val SCTP_UNUSED) -{ - struct sctp_copy_all *ca; - struct mbuf *m; - int ret = 0; - int added_control = 0; - int un_sent, do_chunk_output = 1; - struct sctp_association *asoc; - struct sctp_nets *net; - - ca = (struct sctp_copy_all *)ptr; - if (ca->m == NULL) { - return; - } - if (ca->inp != inp) { - /* TSNH */ - return; - } - if (ca->sndlen > 0) { - m = SCTP_M_COPYM(ca->m, 0, M_COPYALL, M_NOWAIT); - if (m == NULL) { - /* can't copy so we are done */ - ca->cnt_failed++; - return; - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(m, SCTP_MBUF_ICOPY); - } -#endif - } else { - m = NULL; - } - SCTP_TCB_LOCK_ASSERT(stcb); - if (stcb->asoc.alternate) { - net = stcb->asoc.alternate; - } else { - net = stcb->asoc.primary_destination; - } - if (ca->sndrcv.sinfo_flags & SCTP_ABORT) { - /* Abort this assoc with m as the user defined reason */ - if (m != NULL) { - SCTP_BUF_PREPEND(m, sizeof(struct sctp_paramhdr), M_NOWAIT); - } else { - m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), - 0, M_NOWAIT, 1, MT_DATA); - SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr); - } - if (m != NULL) { - struct sctp_paramhdr *ph; - - ph = mtod(m, struct sctp_paramhdr *); - ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); - ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + ca->sndlen)); - } - /* We add one here to keep the assoc from - * dis-appearing on us. - */ - atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_abort_an_association(inp, stcb, m, false, SCTP_SO_NOT_LOCKED); - /* sctp_abort_an_association calls sctp_free_asoc() - * free association will NOT free it since we - * incremented the refcnt .. we do this to prevent - * it being freed and things getting tricky since - * we could end up (from free_asoc) calling inpcb_free - * which would get a recursive lock call to the - * iterator lock.. But as a consequence of that the - * stcb will return to us un-locked.. since free_asoc - * returns with either no TCB or the TCB unlocked, we - * must relock.. to unlock in the iterator timer :-0 - */ - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - goto no_chunk_output; - } else { - if (m != NULL) { - ret = sctp_msg_append(stcb, net, m, &ca->sndrcv); - } - asoc = &stcb->asoc; - if (ca->sndrcv.sinfo_flags & SCTP_EOF) { - /* shutdown this assoc */ - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED) == 0) { - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - goto abort_anyway; - } - /* there is nothing queued to send, so I'm done... */ - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - /* only send SHUTDOWN the first time through */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - NULL); - added_control = 1; - do_chunk_output = 0; - } - } else { - /* - * we still got (or just got) data to send, so set - * SHUTDOWN_PENDING - */ - /* - * XXX sockets draft says that SCTP_EOF should be - * sent with no data. currently, we will allow user - * data to be sent first and move to - * SHUTDOWN-PENDING - */ - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - abort_anyway: - SCTP_SNPRINTF(msg, sizeof(msg), - "%s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_abort_an_association(stcb->sctp_ep, stcb, - op_err, false, SCTP_SO_NOT_LOCKED); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - goto no_chunk_output; - } - } - } - } - } - un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + - (stcb->asoc.stream_queue_cnt * SCTP_DATA_CHUNK_OVERHEAD(stcb))); - - if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && - (stcb->asoc.total_flight > 0) && - (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) { - do_chunk_output = 0; - } - if (do_chunk_output) - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED); - else if (added_control) { - struct timeval now; - int num_out, reason, now_filled = 0; - - (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, 1, &now, &now_filled, - sctp_get_frag_point(stcb), - SCTP_SO_NOT_LOCKED); - } - no_chunk_output: - if (ret) { - ca->cnt_failed++; - } else { - ca->cnt_sent++; - } -} - -static void -sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED) -{ - struct sctp_copy_all *ca; - - ca = (struct sctp_copy_all *)ptr; - /* - * Do a notify here? Kacheong suggests that the notify be done at - * the send time.. so you would push up a notification if any send - * failed. Don't know if this is feasible since the only failures we - * have is "memory" related and if you cannot get an mbuf to send - * the data you surely can't get an mbuf to send up to notify the - * user you can't send the data :-> - */ - - /* now free everything */ - if (ca->inp) { - /* Lets clear the flag to allow others to run. */ - SCTP_INP_WLOCK(ca->inp); - ca->inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; - SCTP_INP_WUNLOCK(ca->inp); - } - sctp_m_freem(ca->m); - SCTP_FREE(ca, SCTP_M_COPYAL); -} - -static struct mbuf * -sctp_copy_out_all(struct uio *uio, ssize_t len) -{ - struct mbuf *ret, *at; - ssize_t left, willcpy, cancpy, error; - - ret = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_WAITOK, 1, MT_DATA); - if (ret == NULL) { - /* TSNH */ - return (NULL); - } - left = len; - SCTP_BUF_LEN(ret) = 0; - /* save space for the data chunk header */ - cancpy = (int)M_TRAILINGSPACE(ret); - willcpy = min(cancpy, left); - at = ret; - while (left > 0) { - /* Align data to the end */ - error = uiomove(mtod(at, caddr_t), (int)willcpy, uio); - if (error) { - err_out_now: - sctp_m_freem(at); - return (NULL); - } - SCTP_BUF_LEN(at) = (int)willcpy; - SCTP_BUF_NEXT_PKT(at) = SCTP_BUF_NEXT(at) = 0; - left -= willcpy; - if (left > 0) { - SCTP_BUF_NEXT(at) = sctp_get_mbuf_for_msg((unsigned int)left, 0, M_WAITOK, 1, MT_DATA); - if (SCTP_BUF_NEXT(at) == NULL) { - goto err_out_now; - } - at = SCTP_BUF_NEXT(at); - SCTP_BUF_LEN(at) = 0; - cancpy = (int)M_TRAILINGSPACE(at); - willcpy = min(cancpy, left); - } - } - return (ret); -} - -static int -sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, - struct sctp_nonpad_sndrcvinfo *srcv) -{ - int ret; - struct sctp_copy_all *ca; - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if (uio->uio_resid > SCTP_BASE_SYSCTL(sctp_sendall_limit)) { -#else - if (uio_resid(uio) > SCTP_BASE_SYSCTL(sctp_sendall_limit)) { -#endif -#else - if (uio->uio_resid > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) { -#endif - /* You must not be larger than the limit! */ - return (EMSGSIZE); - } - SCTP_MALLOC(ca, struct sctp_copy_all *, sizeof(struct sctp_copy_all), - SCTP_M_COPYAL); - if (ca == NULL) { - sctp_m_freem(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - memset(ca, 0, sizeof(struct sctp_copy_all)); - - ca->inp = inp; - if (srcv != NULL) { - memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo)); - } - - /* Serialize. */ - SCTP_INP_WLOCK(inp); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SND_ITERATOR_UP) != 0) { - SCTP_INP_WUNLOCK(inp); - sctp_m_freem(m); - SCTP_FREE(ca, SCTP_M_COPYAL); - return (EBUSY); - } - inp->sctp_flags |= SCTP_PCB_FLAGS_SND_ITERATOR_UP; - SCTP_INP_WUNLOCK(inp); - - /* - * take off the sendall flag, it would be bad if we failed to do - * this :-0 - */ - ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL; - /* get length and mbuf chain */ - if (uio) { -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - ca->sndlen = uio->uio_resid; -#else - ca->sndlen = uio_resid(uio); -#endif -#else - ca->sndlen = uio->uio_resid; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 0); -#endif - ca->m = sctp_copy_out_all(uio, ca->sndlen); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 0); -#endif - if (ca->m == NULL) { - SCTP_FREE(ca, SCTP_M_COPYAL); - sctp_m_freem(m); - SCTP_INP_WLOCK(inp); - inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; - SCTP_INP_WUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - } else { - /* Gather the length of the send */ - struct mbuf *mat; - - ca->sndlen = 0; - for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { - ca->sndlen += SCTP_BUF_LEN(mat); - } - } - ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL, - SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES, - SCTP_ASOC_ANY_STATE, - (void *)ca, 0, - sctp_sendall_completes, inp, 1); - if (ret) { - SCTP_INP_WLOCK(inp); - inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; - SCTP_INP_WUNLOCK(inp); - SCTP_FREE(ca, SCTP_M_COPYAL); - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); - return (EFAULT); - } - return (0); -} - -void -sctp_toss_old_cookies(struct sctp_tcb *stcb, struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *chk, *nchk; - - TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { - if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt--; - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - } -} - -void -sctp_toss_old_asconf(struct sctp_tcb *stcb) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_asconf_chunk *acp; - - asoc = &stcb->asoc; - TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { - /* find SCTP_ASCONF chunk in queue */ - if (chk->rec.chunk_id.id == SCTP_ASCONF) { - if (chk->data) { - acp = mtod(chk->data, struct sctp_asconf_chunk *); - if (SCTP_TSN_GT(ntohl(acp->serial_number), asoc->asconf_seq_out_acked)) { - /* Not Acked yet */ - break; - } - } - TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt--; - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - } -} - -static void -sctp_clean_up_datalist(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_tmit_chunk **data_list, - int bundle_at, - struct sctp_nets *net) -{ - int i; - struct sctp_tmit_chunk *tp1; - - for (i = 0; i < bundle_at; i++) { - /* off of the send queue */ - TAILQ_REMOVE(&asoc->send_queue, data_list[i], sctp_next); - asoc->send_queue_cnt--; - if (i > 0) { - /* - * Any chunk NOT 0 you zap the time chunk 0 gets - * zapped or set based on if a RTO measurement is - * needed. - */ - data_list[i]->do_rtt = 0; - } - /* record time */ - data_list[i]->sent_rcv_time = net->last_sent_time; - data_list[i]->rec.data.cwnd_at_send = net->cwnd; - data_list[i]->rec.data.fast_retran_tsn = data_list[i]->rec.data.tsn; - if (data_list[i]->whoTo == NULL) { - data_list[i]->whoTo = net; - atomic_add_int(&net->ref_count, 1); - } - /* on to the sent queue */ - tp1 = TAILQ_LAST(&asoc->sent_queue, sctpchunk_listhead); - if ((tp1) && SCTP_TSN_GT(tp1->rec.data.tsn, data_list[i]->rec.data.tsn)) { - struct sctp_tmit_chunk *tpp; - - /* need to move back */ - back_up_more: - tpp = TAILQ_PREV(tp1, sctpchunk_listhead, sctp_next); - if (tpp == NULL) { - TAILQ_INSERT_BEFORE(tp1, data_list[i], sctp_next); - goto all_done; - } - tp1 = tpp; - if (SCTP_TSN_GT(tp1->rec.data.tsn, data_list[i]->rec.data.tsn)) { - goto back_up_more; - } - TAILQ_INSERT_AFTER(&asoc->sent_queue, tp1, data_list[i], sctp_next); - } else { - TAILQ_INSERT_TAIL(&asoc->sent_queue, - data_list[i], - sctp_next); - } - all_done: - /* This does not lower until the cum-ack passes it */ - asoc->sent_queue_cnt++; - if ((asoc->peers_rwnd <= 0) && - (asoc->total_flight == 0) && - (bundle_at == 1)) { - /* Mark the chunk as being a window probe */ - SCTP_STAT_INCR(sctps_windowprobed); - } -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xC2, 3); -#endif - data_list[i]->sent = SCTP_DATAGRAM_SENT; - data_list[i]->snd_count = 1; - data_list[i]->rec.data.chunk_was_revoked = 0; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_UP, - data_list[i]->whoTo->flight_size, - data_list[i]->book_size, - (uint32_t)(uintptr_t)data_list[i]->whoTo, - data_list[i]->rec.data.tsn); - } - sctp_flight_size_increase(data_list[i]); - sctp_total_flight_increase(stcb, data_list[i]); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { - sctp_log_rwnd(SCTP_DECREASE_PEER_RWND, - asoc->peers_rwnd, data_list[i]->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); - } - asoc->peers_rwnd = sctp_sbspace_sub(asoc->peers_rwnd, - (uint32_t) (data_list[i]->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))); - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - } - if (asoc->cc_functions.sctp_cwnd_update_packet_transmitted) { - (*asoc->cc_functions.sctp_cwnd_update_packet_transmitted)(stcb, net); - } -} - -static void -sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_locked) -{ - struct sctp_tmit_chunk *chk, *nchk; - - TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { - if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || - (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK) || /* EY */ - (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) || - (chk->rec.chunk_id.id == SCTP_HEARTBEAT_ACK) || - (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) || - (chk->rec.chunk_id.id == SCTP_SHUTDOWN) || - (chk->rec.chunk_id.id == SCTP_SHUTDOWN_ACK) || - (chk->rec.chunk_id.id == SCTP_OPERATION_ERROR) || - (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || - (chk->rec.chunk_id.id == SCTP_COOKIE_ACK) || - (chk->rec.chunk_id.id == SCTP_ECN_CWR) || - (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { - /* Stray chunks must be cleaned up */ - clean_up_anyway: - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt--; - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { - asoc->fwd_tsn_cnt--; - } - sctp_free_a_chunk(stcb, chk, so_locked); - } else if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) { - /* special handling, we must look into the param */ - if (chk != asoc->str_reset) { - goto clean_up_anyway; - } - } - } -} - -static uint32_t -sctp_can_we_split_this(struct sctp_tcb *stcb, uint32_t length, - uint32_t space_left, uint32_t frag_point, int eeor_on) -{ - /* Make a decision on if I should split a - * msg into multiple parts. This is only asked of - * incomplete messages. - */ - if (eeor_on) { - /* If we are doing EEOR we need to always send - * it if its the entire thing, since it might - * be all the guy is putting in the hopper. - */ - if (space_left >= length) { - /*- - * If we have data outstanding, - * we get another chance when the sack - * arrives to transmit - wait for more data - */ - if (stcb->asoc.total_flight == 0) { - /* If nothing is in flight, we zero - * the packet counter. - */ - return (length); - } - return (0); - - } else { - /* You can fill the rest */ - return (space_left); - } - } - /*- - * For those strange folk that make the send buffer - * smaller than our fragmentation point, we can't - * get a full msg in so we have to allow splitting. - */ - if (SCTP_SB_LIMIT_SND(stcb->sctp_socket) < frag_point) { - return (length); - } - if ((length <= space_left) || - ((length - space_left) < SCTP_BASE_SYSCTL(sctp_min_residual))) { - /* Sub-optimal residual don't split in non-eeor mode. */ - return (0); - } - /* If we reach here length is larger - * than the space_left. Do we wish to split - * it for the sake of packet putting together? - */ - if (space_left >= min(SCTP_BASE_SYSCTL(sctp_min_split_point), frag_point)) { - /* Its ok to split it */ - return (min(space_left, frag_point)); - } - /* Nope, can't split */ - return (0); -} - -static uint32_t -sctp_move_to_outqueue(struct sctp_tcb *stcb, - struct sctp_nets *net, - struct sctp_stream_out *strq, - uint32_t space_left, - uint32_t frag_point, - int *giveup, - int eeor_mode, - int *bail, - int so_locked) -{ - /* Move from the stream to the send_queue keeping track of the total */ - struct sctp_association *asoc; - struct sctp_stream_queue_pending *sp; - struct sctp_tmit_chunk *chk; - struct sctp_data_chunk *dchkh=NULL; - struct sctp_idata_chunk *ndchkh=NULL; - uint32_t to_move, length; - int leading; - uint8_t rcv_flags = 0; - uint8_t some_taken; - - SCTP_TCB_LOCK_ASSERT(stcb); - asoc = &stcb->asoc; -one_more_time: - /*sa_ignore FREED_MEMORY*/ - sp = TAILQ_FIRST(&strq->outqueue); - if (sp == NULL) { - sp = TAILQ_FIRST(&strq->outqueue); - if (sp) { - goto one_more_time; - } - if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_EXPLICIT_EOR) == 0) && - (stcb->asoc.idata_supported == 0) && - (strq->last_msg_incomplete)) { - SCTP_PRINTF("Huh? Stream:%d lm_in_c=%d but queue is NULL\n", - strq->sid, - strq->last_msg_incomplete); - strq->last_msg_incomplete = 0; - } - to_move = 0; - goto out_of; - } - if ((sp->msg_is_complete) && (sp->length == 0)) { - if (sp->sender_all_done) { - /* We are doing deferred cleanup. Last - * time through when we took all the data - * the sender_all_done was not set. - */ - if ((sp->put_last_out == 0) && (sp->discard_rest == 0)) { - SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n"); - SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", - sp->sender_all_done, - sp->length, - sp->msg_is_complete, - sp->put_last_out); - } - atomic_subtract_int(&asoc->stream_queue_cnt, 1); - TAILQ_REMOVE(&strq->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp); - if ((strq->state == SCTP_STREAM_RESET_PENDING) && - (strq->chunks_on_queues == 0) && - TAILQ_EMPTY(&strq->outqueue)) { - stcb->asoc.trigger_reset = 1; - } - if (sp->net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - } - sctp_free_a_strmoq(stcb, sp, so_locked); - /* back to get the next msg */ - goto one_more_time; - } else { - /* sender just finished this but - * still holds a reference - */ - *giveup = 1; - to_move = 0; - goto out_of; - } - } else { - /* is there some to get */ - if (sp->length == 0) { - /* no */ - *giveup = 1; - to_move = 0; - goto out_of; - } else if (sp->discard_rest) { - /* Whack down the size */ - atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length); - if ((stcb->sctp_socket != NULL) && - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { - SCTP_SB_DECR(&stcb->sctp_socket->so_snd, sp->length); - } - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - sp->tail_mbuf = NULL; - } - sp->length = 0; - sp->some_taken = 1; - *giveup = 1; - to_move = 0; - goto out_of; - } - } - some_taken = sp->some_taken; - length = sp->length; - if (sp->msg_is_complete) { - /* The message is complete */ - to_move = min(length, frag_point); - if (to_move == length) { - /* All of it fits in the MTU */ - if (sp->some_taken) { - rcv_flags |= SCTP_DATA_LAST_FRAG; - } else { - rcv_flags |= SCTP_DATA_NOT_FRAG; - } - sp->put_last_out = 1; - if (sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) { - rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY; - } - } else { - /* Not all of it fits, we fragment */ - if (sp->some_taken == 0) { - rcv_flags |= SCTP_DATA_FIRST_FRAG; - } - sp->some_taken = 1; - } - } else { - to_move = sctp_can_we_split_this(stcb, length, space_left, frag_point, eeor_mode); - if (to_move > 0) { - if (to_move >= length) { - to_move = length; - } - if (sp->some_taken == 0) { - rcv_flags |= SCTP_DATA_FIRST_FRAG; - sp->some_taken = 1; - } - } else { - /* Nothing to take. */ - *giveup = 1; - to_move = 0; - goto out_of; - } - } - - /* If we reach here, we can copy out a chunk */ - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* No chunk memory */ - *giveup = 1; - to_move = 0; - goto out_of; - } - /* Setup for unordered if needed by looking - * at the user sent info flags. - */ - if (sp->sinfo_flags & SCTP_UNORDERED) { - rcv_flags |= SCTP_DATA_UNORDERED; - } - if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && - (sp->sinfo_flags & SCTP_EOF) == SCTP_EOF) { - rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY; - } - /* clear out the chunk before setting up */ - memset(chk, 0, sizeof(*chk)); - chk->rec.data.rcv_flags = rcv_flags; - - if (to_move >= length) { - /* we think we can steal the whole thing */ - if (to_move < sp->length) { - /* bail, it changed */ - goto dont_do_it; - } - chk->data = sp->data; - chk->last_mbuf = sp->tail_mbuf; - /* register the stealing */ - sp->data = sp->tail_mbuf = NULL; - } else { - struct mbuf *m; - dont_do_it: - chk->data = SCTP_M_COPYM(sp->data, 0, to_move, M_NOWAIT); - chk->last_mbuf = NULL; - if (chk->data == NULL) { - sp->some_taken = some_taken; - sctp_free_a_chunk(stcb, chk, so_locked); - *bail = 1; - to_move = 0; - goto out_of; - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(chk->data, SCTP_MBUF_ICOPY); - } -#endif - /* Pull off the data */ - m_adj(sp->data, to_move); - /* Now lets work our way down and compact it */ - m = sp->data; - while (m && (SCTP_BUF_LEN(m) == 0)) { - sp->data = SCTP_BUF_NEXT(m); - SCTP_BUF_NEXT(m) = NULL; - if (sp->tail_mbuf == m) { - /*- - * Freeing tail? TSNH since - * we supposedly were taking less - * than the sp->length. - */ -#ifdef INVARIANTS - panic("Huh, freeing tail? - TSNH"); -#else - SCTP_PRINTF("Huh, freeing tail? - TSNH\n"); - sp->tail_mbuf = sp->data = NULL; - sp->length = 0; -#endif - } - sctp_m_free(m); - m = sp->data; - } - } - if (SCTP_BUF_IS_EXTENDED(chk->data)) { - chk->copy_by_ref = 1; - } else { - chk->copy_by_ref = 0; - } - /* get last_mbuf and counts of mb usage - * This is ugly but hopefully its only one mbuf. - */ - if (chk->last_mbuf == NULL) { - chk->last_mbuf = chk->data; - while (SCTP_BUF_NEXT(chk->last_mbuf) != NULL) { - chk->last_mbuf = SCTP_BUF_NEXT(chk->last_mbuf); - } - } - - if (to_move > length) { - /*- This should not happen either - * since we always lower to_move to the size - * of sp->length if its larger. - */ -#ifdef INVARIANTS - panic("Huh, how can to_move be larger?"); -#else - SCTP_PRINTF("Huh, how can to_move be larger?\n"); - sp->length = 0; -#endif - } else { - atomic_subtract_int(&sp->length, to_move); - } - leading = SCTP_DATA_CHUNK_OVERHEAD(stcb); - if (M_LEADINGSPACE(chk->data) < leading) { - /* Not enough room for a chunk header, get some */ - struct mbuf *m; - - m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 1, MT_DATA); - if (m == NULL) { - /* - * we're in trouble here. _PREPEND below will free - * all the data if there is no leading space, so we - * must put the data back and restore. - */ - if (sp->data == NULL) { - /* unsteal the data */ - sp->data = chk->data; - sp->tail_mbuf = chk->last_mbuf; - } else { - struct mbuf *m_tmp; - /* reassemble the data */ - m_tmp = sp->data; - sp->data = chk->data; - SCTP_BUF_NEXT(chk->last_mbuf) = m_tmp; - } - sp->some_taken = some_taken; - atomic_add_int(&sp->length, to_move); - chk->data = NULL; - *bail = 1; - sctp_free_a_chunk(stcb, chk, so_locked); - to_move = 0; - goto out_of; - } else { - SCTP_BUF_LEN(m) = 0; - SCTP_BUF_NEXT(m) = chk->data; - chk->data = m; - M_ALIGN(chk->data, 4); - } - } - SCTP_BUF_PREPEND(chk->data, SCTP_DATA_CHUNK_OVERHEAD(stcb), M_NOWAIT); - if (chk->data == NULL) { - /* HELP, TSNH since we assured it would not above? */ -#ifdef INVARIANTS - panic("prepend fails HELP?"); -#else - SCTP_PRINTF("prepend fails HELP?\n"); - sctp_free_a_chunk(stcb, chk, so_locked); -#endif - *bail = 1; - to_move = 0; - goto out_of; - } - sctp_snd_sb_alloc(stcb, SCTP_DATA_CHUNK_OVERHEAD(stcb)); - chk->book_size = chk->send_size = (uint16_t)(to_move + SCTP_DATA_CHUNK_OVERHEAD(stcb)); - chk->book_size_scale = 0; - chk->sent = SCTP_DATAGRAM_UNSENT; - - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->pad_inplace = 0; - chk->no_fr_allowed = 0; - if (stcb->asoc.idata_supported == 0) { - if (rcv_flags & SCTP_DATA_UNORDERED) { - /* Just use 0. The receiver ignores the values. */ - chk->rec.data.mid = 0; - } else { - chk->rec.data.mid = strq->next_mid_ordered; - if (rcv_flags & SCTP_DATA_LAST_FRAG) { - strq->next_mid_ordered++; - } - } - } else { - if (rcv_flags & SCTP_DATA_UNORDERED) { - chk->rec.data.mid = strq->next_mid_unordered; - if (rcv_flags & SCTP_DATA_LAST_FRAG) { - strq->next_mid_unordered++; - } - } else { - chk->rec.data.mid = strq->next_mid_ordered; - if (rcv_flags & SCTP_DATA_LAST_FRAG) { - strq->next_mid_ordered++; - } - } - } - chk->rec.data.sid = sp->sid; - chk->rec.data.ppid = sp->ppid; - chk->rec.data.context = sp->context; - chk->rec.data.doing_fast_retransmit = 0; - - chk->rec.data.timetodrop = sp->ts; - chk->flags = sp->act_flags; - - if (sp->net) { - chk->whoTo = sp->net; - atomic_add_int(&chk->whoTo->ref_count, 1); - } else - chk->whoTo = NULL; - - if (sp->holds_key_ref) { - chk->auth_keyid = sp->auth_keyid; - sctp_auth_key_acquire(stcb, chk->auth_keyid); - chk->holds_key_ref = 1; - } - stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, to_move); -#if defined(__FreeBSD__) && !defined(__Userspace__) - chk->rec.data.tsn = atomic_fetchadd_int(&asoc->sending_seq, 1); -#else - chk->rec.data.tsn = asoc->sending_seq++; -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_AT_SEND_2_OUTQ) { - sctp_misc_ints(SCTP_STRMOUT_LOG_SEND, - (uint32_t)(uintptr_t)stcb, sp->length, - (uint32_t)((chk->rec.data.sid << 16) | (0x0000ffff & chk->rec.data.mid)), - chk->rec.data.tsn); - } - if (stcb->asoc.idata_supported == 0) { - dchkh = mtod(chk->data, struct sctp_data_chunk *); - } else { - ndchkh = mtod(chk->data, struct sctp_idata_chunk *); - } - /* - * Put the rest of the things in place now. Size was done - * earlier in previous loop prior to padding. - */ - - SCTP_TCB_LOCK_ASSERT(stcb); -#ifdef SCTP_ASOCLOG_OF_TSNS - if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) { - asoc->tsn_out_at = 0; - asoc->tsn_out_wrapped = 1; - } - asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.tsn; - asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.sid; - asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.mid; - asoc->out_tsnlog[asoc->tsn_out_at].sz = chk->send_size; - asoc->out_tsnlog[asoc->tsn_out_at].flgs = chk->rec.data.rcv_flags; - asoc->out_tsnlog[asoc->tsn_out_at].stcb = (void *)stcb; - asoc->out_tsnlog[asoc->tsn_out_at].in_pos = asoc->tsn_out_at; - asoc->out_tsnlog[asoc->tsn_out_at].in_out = 2; - asoc->tsn_out_at++; -#endif - if (stcb->asoc.idata_supported == 0) { - dchkh->ch.chunk_type = SCTP_DATA; - dchkh->ch.chunk_flags = chk->rec.data.rcv_flags; - dchkh->dp.tsn = htonl(chk->rec.data.tsn); - dchkh->dp.sid = htons(strq->sid); - dchkh->dp.ssn = htons((uint16_t)chk->rec.data.mid); - dchkh->dp.ppid = chk->rec.data.ppid; - dchkh->ch.chunk_length = htons(chk->send_size); - } else { - ndchkh->ch.chunk_type = SCTP_IDATA; - ndchkh->ch.chunk_flags = chk->rec.data.rcv_flags; - ndchkh->dp.tsn = htonl(chk->rec.data.tsn); - ndchkh->dp.sid = htons(strq->sid); - ndchkh->dp.reserved = htons(0); - ndchkh->dp.mid = htonl(chk->rec.data.mid); - if (sp->fsn == 0) - ndchkh->dp.ppid_fsn.ppid = chk->rec.data.ppid; - else - ndchkh->dp.ppid_fsn.fsn = htonl(sp->fsn); - sp->fsn++; - ndchkh->ch.chunk_length = htons(chk->send_size); - } - /* Now advance the chk->send_size by the actual pad needed. */ - if (chk->send_size < SCTP_SIZE32(chk->book_size)) { - /* need a pad */ - struct mbuf *lm; - int pads; - - pads = SCTP_SIZE32(chk->book_size) - chk->send_size; - lm = sctp_pad_lastmbuf(chk->data, pads, chk->last_mbuf); - if (lm != NULL) { - chk->last_mbuf = lm; - chk->pad_inplace = 1; - } - chk->send_size += pads; - } - if (PR_SCTP_ENABLED(chk->flags)) { - asoc->pr_sctp_cnt++; - } - if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) { - /* All done pull and kill the message */ - if (sp->put_last_out == 0) { - SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n"); - SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", - sp->sender_all_done, - sp->length, - sp->msg_is_complete, - sp->put_last_out); - } - atomic_subtract_int(&asoc->stream_queue_cnt, 1); - TAILQ_REMOVE(&strq->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp); - if ((strq->state == SCTP_STREAM_RESET_PENDING) && - (strq->chunks_on_queues == 0) && - TAILQ_EMPTY(&strq->outqueue)) { - stcb->asoc.trigger_reset = 1; - } - if (sp->net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - } - sctp_free_a_strmoq(stcb, sp, so_locked); - } - asoc->chunks_on_out_queue++; - strq->chunks_on_queues++; - TAILQ_INSERT_TAIL(&asoc->send_queue, chk, sctp_next); - asoc->send_queue_cnt++; -out_of: - return (to_move); -} - -static void -sctp_fill_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, - uint32_t frag_point, int eeor_mode, int *quit_now, - int so_locked) -{ - struct sctp_association *asoc; - struct sctp_stream_out *strq; - uint32_t space_left, moved, total_moved; - int bail, giveup; - - SCTP_TCB_LOCK_ASSERT(stcb); - asoc = &stcb->asoc; - total_moved = 0; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - space_left = net->mtu - SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - space_left = net->mtu - SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - space_left = net->mtu - sizeof(struct sctphdr); - break; -#endif - default: - /* TSNH */ - space_left = net->mtu; - break; - } - /* Need an allowance for the data chunk header too */ - space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb); - - /* must make even word boundary */ - space_left &= 0xfffffffc; - strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); - giveup = 0; - bail = 0; - while ((space_left > 0) && (strq != NULL)) { - moved = sctp_move_to_outqueue(stcb, net, strq, space_left, - frag_point, &giveup, eeor_mode, - &bail, so_locked); - if ((giveup != 0) || (bail != 0)) { - break; - } - strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); - total_moved += moved; - if (space_left >= moved) { - space_left -= moved; - } else { - space_left = 0; - } - if (space_left >= SCTP_DATA_CHUNK_OVERHEAD(stcb)) { - space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb); - } else { - space_left = 0; - } - space_left &= 0xfffffffc; - } - if (bail != 0) - *quit_now = 1; - - stcb->asoc.ss_functions.sctp_ss_packet_done(stcb, net, asoc); - - if (total_moved == 0) { - if ((stcb->asoc.sctp_cmt_on_off == 0) && - (net == stcb->asoc.primary_destination)) { - /* ran dry for primary network net */ - SCTP_STAT_INCR(sctps_primary_randry); - } else if (stcb->asoc.sctp_cmt_on_off > 0) { - /* ran dry with CMT on */ - SCTP_STAT_INCR(sctps_cmt_randry); - } - } -} - -void -sctp_fix_ecn_echo(struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *chk; - - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if (chk->rec.chunk_id.id == SCTP_ECN_ECHO) { - chk->sent = SCTP_DATAGRAM_UNSENT; - } - } -} - -void -sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - struct sctp_stream_queue_pending *sp; - unsigned int i; - - if (net == NULL) { - return; - } - asoc = &stcb->asoc; - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - TAILQ_FOREACH(sp, &stcb->asoc.strmout[i].outqueue, next) { - if (sp->net == net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - } - } - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->whoTo == net) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; - } - } -} - -int -sctp_med_chunk_output(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_association *asoc, - int *num_out, - int *reason_code, - int control_only, int from_where, - struct timeval *now, int *now_filled, - uint32_t frag_point, int so_locked) -{ - /** - * Ok this is the generic chunk service queue. we must do the - * following: - * - Service the stream queue that is next, moving any - * message (note I must get a complete message i.e. FIRST/MIDDLE and - * LAST to the out queue in one pass) and assigning TSN's. This - * only applies though if the peer does not support NDATA. For NDATA - * chunks its ok to not send the entire message ;-) - * - Check to see if the cwnd/rwnd allows any output, if so we go ahead and - * formulate and send the low level chunks. Making sure to combine - * any control in the control chunk queue also. - */ - struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL; - struct mbuf *outchain, *endoutchain; - struct sctp_tmit_chunk *chk, *nchk; - - /* temp arrays for unlinking */ - struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; - int no_fragmentflg, error; - unsigned int max_rwnd_per_dest, max_send_per_dest; - int one_chunk, hbflag, skip_data_for_this_net; - int asconf, cookie, no_out_cnt; - int bundle_at, ctl_cnt, no_data_chunks, eeor_mode; - unsigned int mtu, r_mtu, omtu, mx_mtu, to_out; - int tsns_sent = 0; - uint32_t auth_offset; - struct sctp_auth_chunk *auth; - uint16_t auth_keyid; - int override_ok = 1; - int skip_fill_up = 0; - int data_auth_reqd = 0; - /* JRS 5/14/07 - Add flag for whether a heartbeat is sent to - the destination. */ - int quit_now = 0; - bool use_zero_crc; - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - *num_out = 0; - *reason_code = 0; - auth_keyid = stcb->asoc.authinfo.active_keyid; - if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || - (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) { - eeor_mode = 1; - } else { - eeor_mode = 0; - } - ctl_cnt = no_out_cnt = asconf = cookie = 0; - /* - * First lets prime the pump. For each destination, if there is room - * in the flight size, attempt to pull an MTU's worth out of the - * stream queues into the general send_queue - */ -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xC2, 2); -#endif - SCTP_TCB_LOCK_ASSERT(stcb); - hbflag = 0; - if (control_only) - no_data_chunks = 1; - else - no_data_chunks = 0; - - /* Nothing to possible to send? */ - if ((TAILQ_EMPTY(&asoc->control_send_queue) || - (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) && - TAILQ_EMPTY(&asoc->asconf_send_queue) && - TAILQ_EMPTY(&asoc->send_queue) && - sctp_is_there_unsent_data(stcb, so_locked) == 0) { - nothing_to_send: - *reason_code = 9; - return (0); - } - if (asoc->peers_rwnd == 0) { - /* No room in peers rwnd */ - *reason_code = 1; - if (asoc->total_flight > 0) { - /* we are allowed one chunk in flight */ - no_data_chunks = 1; - } - } - if (stcb->asoc.ecn_echo_cnt_onq) { - /* Record where a sack goes, if any */ - if (no_data_chunks && - (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) { - /* Nothing but ECNe to send - we don't do that */ - goto nothing_to_send; - } - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || - (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) { - sack_goes_to = chk->whoTo; - break; - } - } - } - max_rwnd_per_dest = ((asoc->peers_rwnd + asoc->total_flight) / asoc->numnets); - if (stcb->sctp_socket) - max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets; - else - max_send_per_dest = 0; - if (no_data_chunks == 0) { - /* How many non-directed chunks are there? */ - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->whoTo == NULL) { - /* We already have non-directed - * chunks on the queue, no need - * to do a fill-up. - */ - skip_fill_up = 1; - break; - } - } - } - if ((no_data_chunks == 0) && - (skip_fill_up == 0) && - (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) { - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - /* - * This for loop we are in takes in - * each net, if its's got space in cwnd and - * has data sent to it (when CMT is off) then it - * calls sctp_fill_outqueue for the net. This gets - * data on the send queue for that network. - * - * In sctp_fill_outqueue TSN's are assigned and - * data is copied out of the stream buffers. Note - * mostly copy by reference (we hope). - */ - net->window_probe = 0; - if ((net != stcb->asoc.alternate) && - ((net->dest_state & SCTP_ADDR_PF) || - ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) || - (net->dest_state & SCTP_ADDR_UNCONFIRMED))) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 1, - SCTP_CWND_LOG_FILL_OUTQ_CALLED); - } - continue; - } - if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && - (net->flight_size == 0)) { - (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins)(stcb, net); - } - if (net->flight_size >= net->cwnd) { - /* skip this network, no room - can't fill */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 3, - SCTP_CWND_LOG_FILL_OUTQ_CALLED); - } - continue; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 4, SCTP_CWND_LOG_FILL_OUTQ_CALLED); - } - sctp_fill_outqueue(stcb, net, frag_point, eeor_mode, &quit_now, so_locked); - if (quit_now) { - /* memory alloc failure */ - no_data_chunks = 1; - break; - } - } - } - /* now service each destination and send out what we can for it */ - /* Nothing to send? */ - if (TAILQ_EMPTY(&asoc->control_send_queue) && - TAILQ_EMPTY(&asoc->asconf_send_queue) && - TAILQ_EMPTY(&asoc->send_queue)) { - *reason_code = 8; - return (0); - } - - if (asoc->sctp_cmt_on_off > 0) { - /* get the last start point */ - start_at = asoc->last_net_cmt_send_started; - if (start_at == NULL) { - /* null so to beginning */ - start_at = TAILQ_FIRST(&asoc->nets); - } else { - start_at = TAILQ_NEXT(asoc->last_net_cmt_send_started, sctp_next); - if (start_at == NULL) { - start_at = TAILQ_FIRST(&asoc->nets); - } - } - asoc->last_net_cmt_send_started = start_at; - } else { - start_at = TAILQ_FIRST(&asoc->nets); - } - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if (chk->whoTo == NULL) { - if (asoc->alternate) { - chk->whoTo = asoc->alternate; - } else { - chk->whoTo = asoc->primary_destination; - } - atomic_add_int(&chk->whoTo->ref_count, 1); - } - } - old_start_at = NULL; -again_one_more_time: - for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { - /* how much can we send? */ - /* SCTPDBG("Examine for sending net:%x\n", (uint32_t)net); */ - if (old_start_at && (old_start_at == net)) { - /* through list completely. */ - break; - } - tsns_sent = 0xa; - if (TAILQ_EMPTY(&asoc->control_send_queue) && - TAILQ_EMPTY(&asoc->asconf_send_queue) && - (net->flight_size >= net->cwnd)) { - /* Nothing on control or asconf and flight is full, we can skip - * even in the CMT case. - */ - continue; - } - bundle_at = 0; - endoutchain = outchain = NULL; - auth = NULL; - auth_offset = 0; - no_fragmentflg = 1; - one_chunk = 0; - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { - skip_data_for_this_net = 1; - } else { - skip_data_for_this_net = 0; - } - switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { -#ifdef INET - case AF_INET: - mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - mtu = net->mtu - SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - mtu = net->mtu - sizeof(struct sctphdr); - break; -#endif - default: - /* TSNH */ - mtu = net->mtu; - break; - } - mx_mtu = mtu; - to_out = 0; - if (mtu > asoc->peers_rwnd) { - if (asoc->total_flight > 0) { - /* We have a packet in flight somewhere */ - r_mtu = asoc->peers_rwnd; - } else { - /* We are always allowed to send one MTU out */ - one_chunk = 1; - r_mtu = mtu; - } - } else { - r_mtu = mtu; - } - error = 0; - /************************/ - /* ASCONF transmission */ - /************************/ - /* Now first lets go through the asconf queue */ - TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { - if (chk->rec.chunk_id.id != SCTP_ASCONF) { - continue; - } - if (chk->whoTo == NULL) { - if (asoc->alternate == NULL) { - if (asoc->primary_destination != net) { - break; - } - } else { - if (asoc->alternate != net) { - break; - } - } - } else { - if (chk->whoTo != net) { - break; - } - } - if (chk->data == NULL) { - break; - } - if (chk->sent != SCTP_DATAGRAM_UNSENT && - chk->sent != SCTP_DATAGRAM_RESEND) { - break; - } - /* - * if no AUTH is yet included and this chunk - * requires it, make sure to account for it. We - * don't apply the size until the AUTH chunk is - * actually added below in case there is no room for - * this chunk. NOTE: we overload the use of "omtu" - * here - */ - if ((auth == NULL) && - sctp_auth_is_required_chunk(chk->rec.chunk_id.id, - stcb->asoc.peer_auth_chunks)) { - omtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - } else - omtu = 0; - /* Here we do NOT factor the r_mtu */ - if ((chk->send_size < (int)(mtu - omtu)) || - (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { - /* - * We probably should glom the mbuf chain - * from the chk->data for control but the - * problem is it becomes yet one more level - * of tracking to do if for some reason - * output fails. Then I have got to - * reconstruct the merged control chain.. el - * yucko.. for now we take the easy way and - * do the copy - */ - /* - * Add an AUTH chunk, if chunk requires it - * save the offset into the chain for AUTH - */ - if ((auth == NULL) && - (sctp_auth_is_required_chunk(chk->rec.chunk_id.id, - stcb->asoc.peer_auth_chunks))) { - outchain = sctp_add_auth_chunk(outchain, - &endoutchain, - &auth, - &auth_offset, - stcb, - chk->rec.chunk_id.id); - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } - outchain = sctp_copy_mbufchain(chk->data, outchain, &endoutchain, - (int)chk->rec.chunk_id.can_take_data, - chk->send_size, chk->copy_by_ref); - if (outchain == NULL) { - *reason_code = 8; - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - /* update our MTU size */ - if (mtu > (chk->send_size + omtu)) - mtu -= (chk->send_size + omtu); - else - mtu = 0; - to_out += (chk->send_size + omtu); - /* Do clear IP_DF ? */ - if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { - no_fragmentflg = 0; - } - if (chk->rec.chunk_id.can_take_data) - chk->data = NULL; - /* - * set hb flag since we can - * use these for RTO - */ - hbflag = 1; - asconf = 1; - /* - * should sysctl this: don't - * bundle data with ASCONF - * since it requires AUTH - */ - no_data_chunks = 1; - chk->sent = SCTP_DATAGRAM_SENT; - if (chk->whoTo == NULL) { - chk->whoTo = net; - atomic_add_int(&net->ref_count, 1); - } - chk->snd_count++; - if (mtu == 0) { - /* - * Ok we are out of room but we can - * output without effecting the - * flight size since this little guy - * is a control only packet. - */ - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net); - /* - * do NOT clear the asconf - * flag as it is used to do - * appropriate source address - * selection. - */ - if (*now_filled == 0) { - (void)SCTP_GETTIME_TIMEVAL(now); - *now_filled = 1; - } - net->last_sent_time = *now; - hbflag = 0; - if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, - (struct sockaddr *)&net->ro._l_addr, - outchain, auth_offset, auth, - stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, asconf, - inp->sctp_lport, stcb->rport, - htonl(stcb->asoc.peer_vtag), - net->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - false, so_locked))) { - /* error, we could not output */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (from_where == 0) { - SCTP_STAT_INCR(sctps_lowlevelerrusr); - } - if (error == ENOBUFS) { - asoc->ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - /* error, could not output */ - if (error == EHOSTUNREACH) { - /* - * Destination went - * unreachable - * during this send - */ - sctp_move_chunks_from_net(stcb, net); - } - asconf = 0; - *reason_code = 7; - break; - } else { - asoc->ifp_had_enobuf = 0; - } - /* - * increase the number we sent, if a - * cookie is sent we don't tell them - * any was sent out. - */ - outchain = endoutchain = NULL; - auth = NULL; - auth_offset = 0; - asconf = 0; - if (!no_out_cnt) - *num_out += ctl_cnt; - /* recalc a clean slate and setup */ - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - mtu = net->mtu - SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - mtu = net->mtu - sizeof(struct sctphdr); - break; -#endif - default: - /* TSNH */ - mtu = net->mtu; - break; - } - to_out = 0; - no_fragmentflg = 1; - } - } - } - if (error != 0) { - /* try next net */ - continue; - } - /************************/ - /* Control transmission */ - /************************/ - /* Now first lets go through the control queue */ - TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { - if ((sack_goes_to) && - (chk->rec.chunk_id.id == SCTP_ECN_ECHO) && - (chk->whoTo != sack_goes_to)) { - /* - * if we have a sack in queue, and we are looking at an - * ecn echo that is NOT queued to where the sack is going.. - */ - if (chk->whoTo == net) { - /* Don't transmit it to where its going (current net) */ - continue; - } else if (sack_goes_to == net) { - /* But do transmit it to this address */ - goto skip_net_check; - } - } - if (chk->whoTo == NULL) { - if (asoc->alternate == NULL) { - if (asoc->primary_destination != net) { - continue; - } - } else { - if (asoc->alternate != net) { - continue; - } - } - } else { - if (chk->whoTo != net) { - continue; - } - } - skip_net_check: - if (chk->data == NULL) { - continue; - } - if (chk->sent != SCTP_DATAGRAM_UNSENT) { - /* - * It must be unsent. Cookies and ASCONF's - * hang around but there timers will force - * when marked for resend. - */ - continue; - } - /* - * if no AUTH is yet included and this chunk - * requires it, make sure to account for it. We - * don't apply the size until the AUTH chunk is - * actually added below in case there is no room for - * this chunk. NOTE: we overload the use of "omtu" - * here - */ - if ((auth == NULL) && - sctp_auth_is_required_chunk(chk->rec.chunk_id.id, - stcb->asoc.peer_auth_chunks)) { - omtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - } else - omtu = 0; - /* Here we do NOT factor the r_mtu */ - if ((chk->send_size <= (int)(mtu - omtu)) || - (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { - /* - * We probably should glom the mbuf chain - * from the chk->data for control but the - * problem is it becomes yet one more level - * of tracking to do if for some reason - * output fails. Then I have got to - * reconstruct the merged control chain.. el - * yucko.. for now we take the easy way and - * do the copy - */ - /* - * Add an AUTH chunk, if chunk requires it - * save the offset into the chain for AUTH - */ - if ((auth == NULL) && - (sctp_auth_is_required_chunk(chk->rec.chunk_id.id, - stcb->asoc.peer_auth_chunks))) { - outchain = sctp_add_auth_chunk(outchain, - &endoutchain, - &auth, - &auth_offset, - stcb, - chk->rec.chunk_id.id); - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } - outchain = sctp_copy_mbufchain(chk->data, outchain, &endoutchain, - (int)chk->rec.chunk_id.can_take_data, - chk->send_size, chk->copy_by_ref); - if (outchain == NULL) { - *reason_code = 8; - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - /* update our MTU size */ - if (mtu > (chk->send_size + omtu)) - mtu -= (chk->send_size + omtu); - else - mtu = 0; - to_out += (chk->send_size + omtu); - /* Do clear IP_DF ? */ - if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { - no_fragmentflg = 0; - } - if (chk->rec.chunk_id.can_take_data) - chk->data = NULL; - /* Mark things to be removed, if needed */ - if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || - (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK) || /* EY */ - (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) || - (chk->rec.chunk_id.id == SCTP_HEARTBEAT_ACK) || - (chk->rec.chunk_id.id == SCTP_SHUTDOWN) || - (chk->rec.chunk_id.id == SCTP_SHUTDOWN_ACK) || - (chk->rec.chunk_id.id == SCTP_OPERATION_ERROR) || - (chk->rec.chunk_id.id == SCTP_COOKIE_ACK) || - (chk->rec.chunk_id.id == SCTP_ECN_CWR) || - (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || - (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { - if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) { - hbflag = 1; - } - /* remove these chunks at the end */ - if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || - (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) { - /* turn off the timer */ - if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - inp, stcb, NULL, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1); - } - } - ctl_cnt++; - } else { - /* - * Other chunks, since they have - * timers running (i.e. COOKIE) - * we just "trust" that it - * gets sent or retransmitted. - */ - ctl_cnt++; - if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { - cookie = 1; - no_out_cnt = 1; - } else if (chk->rec.chunk_id.id == SCTP_ECN_ECHO) { - /* - * Increment ecne send count here - * this means we may be over-zealous in - * our counting if the send fails, but its - * the best place to do it (we used to do - * it in the queue of the chunk, but that did - * not tell how many times it was sent. - */ - SCTP_STAT_INCR(sctps_sendecne); - } - chk->sent = SCTP_DATAGRAM_SENT; - if (chk->whoTo == NULL) { - chk->whoTo = net; - atomic_add_int(&net->ref_count, 1); - } - chk->snd_count++; - } - if (mtu == 0) { - /* - * Ok we are out of room but we can - * output without effecting the - * flight size since this little guy - * is a control only packet. - */ - switch (asoc->snd_edmid) { - case SCTP_EDMID_LOWER_LAYER_DTLS: - use_zero_crc = true; - break; - default: - use_zero_crc = false; - break; - } - if (asconf) { - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net); - use_zero_crc = false; - /* - * do NOT clear the asconf - * flag as it is used to do - * appropriate source address - * selection. - */ - } - if (cookie) { - sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); - use_zero_crc = false; - cookie = 0; - } - /* Only HB or ASCONF advances time */ - if (hbflag) { - if (*now_filled == 0) { - (void)SCTP_GETTIME_TIMEVAL(now); - *now_filled = 1; - } - net->last_sent_time = *now; - hbflag = 0; - } - if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, - (struct sockaddr *)&net->ro._l_addr, - outchain, - auth_offset, auth, - stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, asconf, - inp->sctp_lport, stcb->rport, - htonl(stcb->asoc.peer_vtag), - net->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - use_zero_crc, so_locked))) { - /* error, we could not output */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (from_where == 0) { - SCTP_STAT_INCR(sctps_lowlevelerrusr); - } - if (error == ENOBUFS) { - asoc->ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - if (error == EHOSTUNREACH) { - /* - * Destination went - * unreachable - * during this send - */ - sctp_move_chunks_from_net(stcb, net); - } - asconf = 0; - *reason_code = 7; - break; - } else { - asoc->ifp_had_enobuf = 0; - } - /* - * increase the number we sent, if a - * cookie is sent we don't tell them - * any was sent out. - */ - outchain = endoutchain = NULL; - auth = NULL; - auth_offset = 0; - asconf = 0; - if (!no_out_cnt) - *num_out += ctl_cnt; - /* recalc a clean slate and setup */ - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - mtu = net->mtu - SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - mtu = net->mtu - sizeof(struct sctphdr); - break; -#endif - default: - /* TSNH */ - mtu = net->mtu; - break; - } - to_out = 0; - no_fragmentflg = 1; - } - } - } - if (error != 0) { - /* try next net */ - continue; - } - /* JRI: if dest is in PF state, do not send data to it */ - if ((asoc->sctp_cmt_on_off > 0) && - (net != stcb->asoc.alternate) && - (net->dest_state & SCTP_ADDR_PF)) { - goto no_data_fill; - } - if (net->flight_size >= net->cwnd) { - goto no_data_fill; - } - if ((asoc->sctp_cmt_on_off > 0) && - (SCTP_BASE_SYSCTL(sctp_buffer_splitting) & SCTP_RECV_BUFFER_SPLITTING) && - (net->flight_size > max_rwnd_per_dest)) { - goto no_data_fill; - } - /* - * We need a specific accounting for the usage of the - * send buffer. We also need to check the number of messages - * per net. For now, this is better than nothing and it - * disabled by default... - */ - if ((asoc->sctp_cmt_on_off > 0) && - (SCTP_BASE_SYSCTL(sctp_buffer_splitting) & SCTP_SEND_BUFFER_SPLITTING) && - (max_send_per_dest > 0) && - (net->flight_size > max_send_per_dest)) { - goto no_data_fill; - } - /*********************/ - /* Data transmission */ - /*********************/ - /* - * if AUTH for DATA is required and no AUTH has been added - * yet, account for this in the mtu now... if no data can be - * bundled, this adjustment won't matter anyways since the - * packet will be going out... - */ - data_auth_reqd = sctp_auth_is_required_chunk(SCTP_DATA, - stcb->asoc.peer_auth_chunks); - if (data_auth_reqd && (auth == NULL)) { - mtu -= sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - } - /* now lets add any data within the MTU constraints */ - switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { -#ifdef INET - case AF_INET: - if (net->mtu > SCTP_MIN_V4_OVERHEAD) - omtu = net->mtu - SCTP_MIN_V4_OVERHEAD; - else - omtu = 0; - break; -#endif -#ifdef INET6 - case AF_INET6: - if (net->mtu > SCTP_MIN_OVERHEAD) - omtu = net->mtu - SCTP_MIN_OVERHEAD; - else - omtu = 0; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (net->mtu > sizeof(struct sctphdr)) { - omtu = net->mtu - sizeof(struct sctphdr); - } else { - omtu = 0; - } - break; -#endif - default: - /* TSNH */ - omtu = 0; - break; - } - if ((((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) && - (skip_data_for_this_net == 0)) || - (cookie)) { - TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { - if (no_data_chunks) { - /* let only control go out */ - *reason_code = 1; - break; - } - if (net->flight_size >= net->cwnd) { - /* skip this net, no room for data */ - *reason_code = 2; - break; - } - if ((chk->whoTo != NULL) && - (chk->whoTo != net)) { - /* Don't send the chunk on this net */ - continue; - } - - if (asoc->sctp_cmt_on_off == 0) { - if ((asoc->alternate) && - (asoc->alternate != net) && - (chk->whoTo == NULL)) { - continue; - } else if ((net != asoc->primary_destination) && - (asoc->alternate == NULL) && - (chk->whoTo == NULL)) { - continue; - } - } - if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) { - /*- - * strange, we have a chunk that is - * to big for its destination and - * yet no fragment ok flag. - * Something went wrong when the - * PMTU changed...we did not mark - * this chunk for some reason?? I - * will fix it here by letting IP - * fragment it for now and printing - * a warning. This really should not - * happen ... - */ - SCTP_PRINTF("Warning chunk of %d bytes > mtu:%d and yet PMTU disc missed\n", - chk->send_size, mtu); - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - } - if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && - (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { - struct sctp_data_chunk *dchkh; - - dchkh = mtod(chk->data, struct sctp_data_chunk *); - dchkh->ch.chunk_flags |= SCTP_DATA_SACK_IMMEDIATELY; - } - if (((chk->send_size <= mtu) && (chk->send_size <= r_mtu)) || - ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) && (chk->send_size <= asoc->peers_rwnd))) { - /* ok we will add this one */ - - /* - * Add an AUTH chunk, if chunk - * requires it, save the offset into - * the chain for AUTH - */ - if (data_auth_reqd) { - if (auth == NULL) { - outchain = sctp_add_auth_chunk(outchain, - &endoutchain, - &auth, - &auth_offset, - stcb, - SCTP_DATA); - auth_keyid = chk->auth_keyid; - override_ok = 0; - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } else if (override_ok) { - /* use this data's keyid */ - auth_keyid = chk->auth_keyid; - override_ok = 0; - } else if (auth_keyid != chk->auth_keyid) { - /* different keyid, so done bundling */ - break; - } - } - outchain = sctp_copy_mbufchain(chk->data, outchain, &endoutchain, 0, - chk->send_size, chk->copy_by_ref); - if (outchain == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "No memory?\n"); - if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - } - *reason_code = 3; - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - /* update our MTU size */ - /* Do clear IP_DF ? */ - if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { - no_fragmentflg = 0; - } - /* unsigned subtraction of mtu */ - if (mtu > chk->send_size) - mtu -= chk->send_size; - else - mtu = 0; - /* unsigned subtraction of r_mtu */ - if (r_mtu > chk->send_size) - r_mtu -= chk->send_size; - else - r_mtu = 0; - - to_out += chk->send_size; - if ((to_out > mx_mtu) && no_fragmentflg) { -#ifdef INVARIANTS - panic("Exceeding mtu of %d out size is %d", mx_mtu, to_out); -#else - SCTP_PRINTF("Exceeding mtu of %d out size is %d\n", - mx_mtu, to_out); -#endif - } - chk->window_probe = 0; - data_list[bundle_at++] = chk; - if (bundle_at >= SCTP_MAX_DATA_BUNDLING) { - break; - } - if (chk->sent == SCTP_DATAGRAM_UNSENT) { - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { - SCTP_STAT_INCR_COUNTER64(sctps_outorderchunks); - } else { - SCTP_STAT_INCR_COUNTER64(sctps_outunorderchunks); - } - if (((chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) && - ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0)) - /* Count number of user msg's that were fragmented - * we do this by counting when we see a LAST fragment - * only. - */ - SCTP_STAT_INCR_COUNTER64(sctps_fragusrmsgs); - } - if ((mtu == 0) || (r_mtu == 0) || (one_chunk)) { - if ((one_chunk) && (stcb->asoc.total_flight == 0)) { - data_list[0]->window_probe = 1; - net->window_probe = 1; - } - break; - } - } else { - /* - * Must be sent in order of the - * TSN's (on a network) - */ - break; - } - } /* for (chunk gather loop for this net) */ - } /* if asoc.state OPEN */ - no_data_fill: - /* Is there something to send for this destination? */ - if (outchain) { - switch (asoc->snd_edmid) { - case SCTP_EDMID_LOWER_LAYER_DTLS: - use_zero_crc = true; - break; - default: - use_zero_crc = false; - break; - } - /* We may need to start a control timer or two */ - if (asconf) { - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, - stcb, net); - use_zero_crc = false; - /* - * do NOT clear the asconf flag as it is used - * to do appropriate source address selection. - */ - } - if (cookie) { - sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); - use_zero_crc = false; - cookie = 0; - } - /* must start a send timer if data is being sent */ - if (bundle_at && (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) { - /* - * no timer running on this destination - * restart it. - */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - } - if (bundle_at || hbflag) { - /* For data/asconf and hb set time */ - if (*now_filled == 0) { - (void)SCTP_GETTIME_TIMEVAL(now); - *now_filled = 1; - } - net->last_sent_time = *now; - } - /* Now send it, if there is anything to send :> */ - if ((error = sctp_lowlevel_chunk_output(inp, - stcb, - net, - (struct sockaddr *)&net->ro._l_addr, - outchain, - auth_offset, - auth, - auth_keyid, - no_fragmentflg, - bundle_at, - asconf, - inp->sctp_lport, stcb->rport, - htonl(stcb->asoc.peer_vtag), - net->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - use_zero_crc, - so_locked))) { - /* error, we could not output */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (from_where == 0) { - SCTP_STAT_INCR(sctps_lowlevelerrusr); - } - if (error == ENOBUFS) { - asoc->ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - if (error == EHOSTUNREACH) { - /* - * Destination went unreachable - * during this send - */ - sctp_move_chunks_from_net(stcb, net); - } - asconf = 0; - *reason_code = 6; - /*- - * I add this line to be paranoid. As far as - * I can tell the continue, takes us back to - * the top of the for, but just to make sure - * I will reset these again here. - */ - ctl_cnt = 0; - continue; /* This takes us back to the for() for the nets. */ - } else { - asoc->ifp_had_enobuf = 0; - } - endoutchain = NULL; - auth = NULL; - auth_offset = 0; - asconf = 0; - if (!no_out_cnt) { - *num_out += (ctl_cnt + bundle_at); - } - if (bundle_at) { - /* setup for a RTO measurement */ - tsns_sent = data_list[0]->rec.data.tsn; - /* fill time if not already filled */ - if (*now_filled == 0) { - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_last_sent); - *now_filled = 1; - *now = asoc->time_last_sent; - } else { - asoc->time_last_sent = *now; - } - if (net->rto_needed) { - data_list[0]->do_rtt = 1; - net->rto_needed = 0; - } - SCTP_STAT_INCR_BY(sctps_senddata, bundle_at); - sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net); - } - if (one_chunk) { - break; - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, tsns_sent, SCTP_CWND_LOG_FROM_SEND); - } - } - if (old_start_at == NULL) { - old_start_at = start_at; - start_at = TAILQ_FIRST(&asoc->nets); - if (old_start_at) - goto again_one_more_time; - } - - /* - * At the end there should be no NON timed chunks hanging on this - * queue. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, *num_out, SCTP_CWND_LOG_FROM_SEND); - } - if ((*num_out == 0) && (*reason_code == 0)) { - *reason_code = 4; - } else { - *reason_code = 5; - } - sctp_clean_up_ctl(stcb, asoc, so_locked); - return (0); -} - -void -sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) -{ - /*- - * Prepend a OPERATIONAL_ERROR chunk header and put on the end of - * the control chunk queue. - */ - struct sctp_chunkhdr *hdr; - struct sctp_tmit_chunk *chk; - struct mbuf *mat, *last_mbuf; - uint32_t chunk_length; - uint16_t padding_length; - - SCTP_TCB_LOCK_ASSERT(stcb); - SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT); - if (op_err == NULL) { - return; - } - last_mbuf = NULL; - chunk_length = 0; - for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) { - chunk_length += SCTP_BUF_LEN(mat); - if (SCTP_BUF_NEXT(mat) == NULL) { - last_mbuf = mat; - } - } - if (chunk_length > SCTP_MAX_CHUNK_LENGTH) { - sctp_m_freem(op_err); - return; - } - padding_length = chunk_length % 4; - if (padding_length != 0) { - padding_length = 4 - padding_length; - } - if (padding_length != 0) { - if (sctp_add_pad_tombuf(last_mbuf, padding_length) == NULL) { - sctp_m_freem(op_err); - return; - } - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(op_err); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_OPERATION_ERROR; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->send_size = (uint16_t)chunk_length; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->data = op_err; - chk->whoTo = NULL; - hdr = mtod(op_err, struct sctp_chunkhdr *); - hdr->chunk_type = SCTP_OPERATION_ERROR; - hdr->chunk_flags = 0; - hdr->chunk_length = htons(chk->send_size); - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; -} - -int -sctp_send_cookie_echo(struct mbuf *m, - int offset, int limit, - struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - /*- - * pull out the cookie and put it at the front of the control chunk - * queue. - */ - int at; - struct mbuf *cookie; - struct sctp_paramhdr param, *phdr; - struct sctp_chunkhdr *hdr; - struct sctp_tmit_chunk *chk; - uint16_t ptype, plen; - - SCTP_TCB_LOCK_ASSERT(stcb); - /* First find the cookie in the param area */ - cookie = NULL; - at = offset + sizeof(struct sctp_init_chunk); - for (;;) { - phdr = sctp_get_next_param(m, at, ¶m, sizeof(param)); - if (phdr == NULL) { - return (-3); - } - ptype = ntohs(phdr->param_type); - plen = ntohs(phdr->param_length); - if (plen < sizeof(struct sctp_paramhdr)) { - return (-6); - } - if (ptype == SCTP_STATE_COOKIE) { - int pad; - - /* found the cookie */ - if (at + plen > limit) { - return (-7); - } - cookie = SCTP_M_COPYM(m, at, plen, M_NOWAIT); - if (cookie == NULL) { - /* No memory */ - return (-2); - } - if ((pad = (plen % 4)) > 0) { - pad = 4 - pad; - } - if (pad > 0) { - if (sctp_pad_lastmbuf(cookie, pad, NULL) == NULL) { - return (-8); - } - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(cookie, SCTP_MBUF_ICOPY); - } -#endif - break; - } - at += SCTP_SIZE32(plen); - } - /* ok, we got the cookie lets change it into a cookie echo chunk */ - /* first the change from param to cookie */ - hdr = mtod(cookie, struct sctp_chunkhdr *); - hdr->chunk_type = SCTP_COOKIE_ECHO; - hdr->chunk_flags = 0; - /* get the chunk stuff now and place it in the FRONT of the queue */ - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(cookie); - return (-5); - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_COOKIE_ECHO; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = CHUNK_FLAGS_FRAGMENT_OK; - chk->send_size = SCTP_SIZE32(plen); - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->data = cookie; - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; - return (0); -} - -void -sctp_send_heartbeat_ack(struct sctp_tcb *stcb, - struct mbuf *m, - int offset, - int chk_length, - struct sctp_nets *net) -{ - /* - * take a HB request and make it into a HB ack and send it. - */ - struct mbuf *outchain; - struct sctp_chunkhdr *chdr; - struct sctp_tmit_chunk *chk; - - if (net == NULL) - /* must have a net pointer */ - return; - - outchain = SCTP_M_COPYM(m, offset, chk_length, M_NOWAIT); - if (outchain == NULL) { - /* gak out of memory */ - return; - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(outchain, SCTP_MBUF_ICOPY); - } -#endif - chdr = mtod(outchain, struct sctp_chunkhdr *); - chdr->chunk_type = SCTP_HEARTBEAT_ACK; - chdr->chunk_flags = 0; - if (chk_length % 4 != 0) { - sctp_pad_lastmbuf(outchain, 4 - (chk_length % 4), NULL); - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(outchain); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_HEARTBEAT_ACK; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - chk->send_size = chk_length; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->data = outchain; - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; -} - -void -sctp_send_cookie_ack(struct sctp_tcb *stcb) -{ - /* formulate and queue a cookie-ack back to sender */ - struct mbuf *cookie_ack; - struct sctp_chunkhdr *hdr; - struct sctp_tmit_chunk *chk; - - SCTP_TCB_LOCK_ASSERT(stcb); - - cookie_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER); - if (cookie_ack == NULL) { - /* no mbuf's */ - return; - } - SCTP_BUF_RESV_UF(cookie_ack, SCTP_MIN_OVERHEAD); - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(cookie_ack); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_COOKIE_ACK; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - chk->send_size = sizeof(struct sctp_chunkhdr); - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->data = cookie_ack; - if (chk->asoc->last_control_chunk_from != NULL) { - chk->whoTo = chk->asoc->last_control_chunk_from; - atomic_add_int(&chk->whoTo->ref_count, 1); - } else { - chk->whoTo = NULL; - } - hdr = mtod(cookie_ack, struct sctp_chunkhdr *); - hdr->chunk_type = SCTP_COOKIE_ACK; - hdr->chunk_flags = 0; - hdr->chunk_length = htons(chk->send_size); - SCTP_BUF_LEN(cookie_ack) = chk->send_size; - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; - return; -} - -void -sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - /* formulate and queue a SHUTDOWN-ACK back to the sender */ - struct mbuf *m_shutdown_ack; - struct sctp_shutdown_ack_chunk *ack_cp; - struct sctp_tmit_chunk *chk; - - m_shutdown_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_ack_chunk), 0, M_NOWAIT, 1, MT_HEADER); - if (m_shutdown_ack == NULL) { - /* no mbuf's */ - return; - } - SCTP_BUF_RESV_UF(m_shutdown_ack, SCTP_MIN_OVERHEAD); - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(m_shutdown_ack); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_SHUTDOWN_ACK; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - chk->send_size = sizeof(struct sctp_chunkhdr); - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->data = m_shutdown_ack; - chk->whoTo = net; - if (chk->whoTo) { - atomic_add_int(&chk->whoTo->ref_count, 1); - } - ack_cp = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *); - ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK; - ack_cp->ch.chunk_flags = 0; - ack_cp->ch.chunk_length = htons(chk->send_size); - SCTP_BUF_LEN(m_shutdown_ack) = chk->send_size; - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; - return; -} - -void -sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - /* formulate and queue a SHUTDOWN to the sender */ - struct mbuf *m_shutdown; - struct sctp_shutdown_chunk *shutdown_cp; - struct sctp_tmit_chunk *chk; - - TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { - if (chk->rec.chunk_id.id == SCTP_SHUTDOWN) { - /* We already have a SHUTDOWN queued. Reuse it. */ - if (chk->whoTo) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; - } - break; - } - } - if (chk == NULL) { - m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER); - if (m_shutdown == NULL) { - /* no mbuf's */ - return; - } - SCTP_BUF_RESV_UF(m_shutdown, SCTP_MIN_OVERHEAD); - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(m_shutdown); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_SHUTDOWN; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - chk->send_size = sizeof(struct sctp_shutdown_chunk); - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->data = m_shutdown; - chk->whoTo = net; - if (chk->whoTo) { - atomic_add_int(&chk->whoTo->ref_count, 1); - } - shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *); - shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN; - shutdown_cp->ch.chunk_flags = 0; - shutdown_cp->ch.chunk_length = htons(chk->send_size); - shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn); - SCTP_BUF_LEN(m_shutdown) = chk->send_size; - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; - } else { - TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, sctp_next); - chk->whoTo = net; - if (chk->whoTo) { - atomic_add_int(&chk->whoTo->ref_count, 1); - } - shutdown_cp = mtod(chk->data, struct sctp_shutdown_chunk *); - shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn); - TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); - } - return; -} - -void -sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked) -{ - /* - * formulate and queue an ASCONF to the peer. - * ASCONF parameters should be queued on the assoc queue. - */ - struct sctp_tmit_chunk *chk; - struct mbuf *m_asconf; - int len; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if ((!TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) && - (!sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_MULTIPLE_ASCONFS))) { - /* can't send a new one if there is one in flight already */ - return; - } - - /* compose an ASCONF chunk, maximum length is PMTU */ - m_asconf = sctp_compose_asconf(stcb, &len, addr_locked); - if (m_asconf == NULL) { - return; - } - - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - sctp_m_freem(m_asconf); - return; - } - - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_ASCONF; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = CHUNK_FLAGS_FRAGMENT_OK; - chk->data = m_asconf; - chk->send_size = len; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - chk->whoTo = net; - if (chk->whoTo) { - atomic_add_int(&chk->whoTo->ref_count, 1); - } - TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; - return; -} - -void -sctp_send_asconf_ack(struct sctp_tcb *stcb) -{ - /* - * formulate and queue a asconf-ack back to sender. - * the asconf-ack must be stored in the tcb. - */ - struct sctp_tmit_chunk *chk; - struct sctp_asconf_ack *ack, *latest_ack; - struct mbuf *m_ack; - struct sctp_nets *net = NULL; - - SCTP_TCB_LOCK_ASSERT(stcb); - /* Get the latest ASCONF-ACK */ - latest_ack = TAILQ_LAST(&stcb->asoc.asconf_ack_sent, sctp_asconf_ackhead); - if (latest_ack == NULL) { - return; - } - if (latest_ack->last_sent_to != NULL && - latest_ack->last_sent_to == stcb->asoc.last_control_chunk_from) { - /* we're doing a retransmission */ - net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0); - if (net == NULL) { - /* no alternate */ - if (stcb->asoc.last_control_chunk_from == NULL) { - if (stcb->asoc.alternate) { - net = stcb->asoc.alternate; - } else { - net = stcb->asoc.primary_destination; - } - } else { - net = stcb->asoc.last_control_chunk_from; - } - } - } else { - /* normal case */ - if (stcb->asoc.last_control_chunk_from == NULL) { - if (stcb->asoc.alternate) { - net = stcb->asoc.alternate; - } else { - net = stcb->asoc.primary_destination; - } - } else { - net = stcb->asoc.last_control_chunk_from; - } - } - latest_ack->last_sent_to = net; - - TAILQ_FOREACH(ack, &stcb->asoc.asconf_ack_sent, next) { - if (ack->data == NULL) { - continue; - } - - /* copy the asconf_ack */ - m_ack = SCTP_M_COPYM(ack->data, 0, M_COPYALL, M_NOWAIT); - if (m_ack == NULL) { - /* couldn't copy it */ - return; - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(m_ack, SCTP_MBUF_ICOPY); - } -#endif - - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - if (m_ack) - sctp_m_freem(m_ack); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_ASCONF_ACK; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = CHUNK_FLAGS_FRAGMENT_OK; - chk->whoTo = net; - if (chk->whoTo) { - atomic_add_int(&chk->whoTo->ref_count, 1); - } - chk->data = m_ack; - chk->send_size = ack->len; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->asoc = &stcb->asoc; - - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; - } - return; -} - -static int -sctp_chunk_retransmission(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_association *asoc, - int *cnt_out, struct timeval *now, int *now_filled, int *fr_done, int so_locked) -{ - /*- - * send out one MTU of retransmission. If fast_retransmit is - * happening we ignore the cwnd. Otherwise we obey the cwnd and - * rwnd. For a Cookie or Asconf in the control chunk queue we - * retransmit them by themselves. - * - * For data chunks we will pick out the lowest TSN's in the sent_queue - * marked for resend and bundle them all together (up to a MTU of - * destination). The address to send to should have been - * selected/changed where the retransmission was marked (i.e. in FR - * or t3-timeout routines). - */ - struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; - struct sctp_tmit_chunk *chk, *fwd; - struct mbuf *m, *endofchain; - struct sctp_nets *net = NULL; - uint32_t tsns_sent = 0; - int no_fragmentflg, bundle_at; - unsigned int mtu; - int error, i, one_chunk, fwd_tsn, ctl_cnt, tmr_started; - struct sctp_auth_chunk *auth = NULL; - uint32_t auth_offset = 0; - uint16_t auth_keyid; - int override_ok = 1; - int data_auth_reqd = 0; - uint32_t dmtu = 0; - bool use_zero_crc; - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - SCTP_TCB_LOCK_ASSERT(stcb); - tmr_started = ctl_cnt = 0; - no_fragmentflg = 1; - fwd_tsn = 0; - *cnt_out = 0; - fwd = NULL; - endofchain = m = NULL; - auth_keyid = stcb->asoc.authinfo.active_keyid; -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xC3, 1); -#endif - if ((TAILQ_EMPTY(&asoc->sent_queue)) && - (TAILQ_EMPTY(&asoc->control_send_queue))) { - SCTPDBG(SCTP_DEBUG_OUTPUT1,"SCTP hits empty queue with cnt set to %d?\n", - asoc->sent_queue_retran_cnt); - asoc->sent_queue_cnt = 0; - asoc->sent_queue_cnt_removeable = 0; - /* send back 0/0 so we enter normal transmission */ - *cnt_out = 0; - return (0); - } - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) || - (chk->rec.chunk_id.id == SCTP_STREAM_RESET) || - (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN)) { - if (chk->sent != SCTP_DATAGRAM_RESEND) { - continue; - } - if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) { - if (chk != asoc->str_reset) { - /* - * not eligible for retran if its - * not ours - */ - continue; - } - } - ctl_cnt++; - if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { - fwd_tsn = 1; - } - /* - * Add an AUTH chunk, if chunk requires it save the - * offset into the chain for AUTH - */ - if ((auth == NULL) && - (sctp_auth_is_required_chunk(chk->rec.chunk_id.id, - stcb->asoc.peer_auth_chunks))) { - m = sctp_add_auth_chunk(m, &endofchain, - &auth, &auth_offset, - stcb, - chk->rec.chunk_id.id); - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } - m = sctp_copy_mbufchain(chk->data, m, &endofchain, 0, chk->send_size, chk->copy_by_ref); - break; - } - } - one_chunk = 0; - /* do we have control chunks to retransmit? */ - if (m != NULL) { - /* Start a timer no matter if we succeed or fail */ - switch (asoc->snd_edmid) { - case SCTP_EDMID_LOWER_LAYER_DTLS: - use_zero_crc = true; - break; - default: - use_zero_crc = false; - break; - } - if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { - sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo); - use_zero_crc = false; - } else if (chk->rec.chunk_id.id == SCTP_ASCONF) { - /* XXXMT: Can this happen? */ - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo); - use_zero_crc = false; - } - chk->snd_count++; /* update our count */ - if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo, - (struct sockaddr *)&chk->whoTo->ro._l_addr, m, - auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, 0, - inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), - chk->whoTo->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - use_zero_crc, - so_locked))) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (error == ENOBUFS) { - asoc->ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - return (error); - } else { - asoc->ifp_had_enobuf = 0; - } - endofchain = NULL; - auth = NULL; - auth_offset = 0; - /* - * We don't want to mark the net->sent time here since this - * we use this for HB and retrans cannot measure RTT - */ - /* (void)SCTP_GETTIME_TIMEVAL(&chk->whoTo->last_sent_time); */ - *cnt_out += 1; - chk->sent = SCTP_DATAGRAM_SENT; - sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt); - if (fwd_tsn == 0) { - return (0); - } else { - /* Clean up the fwd-tsn list */ - sctp_clean_up_ctl(stcb, asoc, so_locked); - return (0); - } - } - /* - * Ok, it is just data retransmission we need to do or that and a - * fwd-tsn with it all. - */ - if (TAILQ_EMPTY(&asoc->sent_queue)) { - return (SCTP_RETRAN_DONE); - } - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT)) { - /* not yet open, resend the cookie and that is it */ - return (1); - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(20, inp, stcb, NULL); -#endif - data_auth_reqd = sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks); - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - if (chk->sent != SCTP_DATAGRAM_RESEND) { - /* No, not sent to this net or not ready for rtx */ - continue; - } - if (chk->data == NULL) { - SCTP_PRINTF("TSN:%x chk->snd_count:%d chk->sent:%d can't retran - no data\n", - chk->rec.data.tsn, chk->snd_count, chk->sent); - continue; - } - if ((SCTP_BASE_SYSCTL(sctp_max_retran_chunk)) && - (chk->snd_count >= SCTP_BASE_SYSCTL(sctp_max_retran_chunk))) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - SCTP_SNPRINTF(msg, sizeof(msg), "TSN %8.8x retransmitted %d times, giving up", - chk->rec.data.tsn, chk->snd_count); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, - false, so_locked); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return (SCTP_RETRAN_EXIT); - } - /* pick up the net */ - net = chk->whoTo; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - mtu = net->mtu - SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - mtu = net->mtu - sizeof(struct sctphdr); - break; -#endif - default: - /* TSNH */ - mtu = net->mtu; - break; - } - - if ((asoc->peers_rwnd < mtu) && (asoc->total_flight > 0)) { - /* No room in peers rwnd */ - uint32_t tsn; - - tsn = asoc->last_acked_seq + 1; - if (tsn == chk->rec.data.tsn) { - /* - * we make a special exception for this - * case. The peer has no rwnd but is missing - * the lowest chunk.. which is probably what - * is holding up the rwnd. - */ - goto one_chunk_around; - } - return (1); - } - one_chunk_around: - if (asoc->peers_rwnd < mtu) { - one_chunk = 1; - if ((asoc->peers_rwnd == 0) && - (asoc->total_flight == 0)) { - chk->window_probe = 1; - chk->whoTo->window_probe = 1; - } - } -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xC3, 2); -#endif - bundle_at = 0; - m = NULL; - net->fast_retran_ip = 0; - if (chk->rec.data.doing_fast_retransmit == 0) { - /* - * if no FR in progress skip destination that have - * flight_size > cwnd. - */ - if (net->flight_size >= net->cwnd) { - continue; - } - } else { - /* - * Mark the destination net to have FR recovery - * limits put on it. - */ - *fr_done = 1; - net->fast_retran_ip = 1; - } - - /* - * if no AUTH is yet included and this chunk requires it, - * make sure to account for it. We don't apply the size - * until the AUTH chunk is actually added below in case - * there is no room for this chunk. - */ - if (data_auth_reqd && (auth == NULL)) { - dmtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - } else - dmtu = 0; - - if ((chk->send_size <= (mtu - dmtu)) || - (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { - /* ok we will add this one */ - if (data_auth_reqd) { - if (auth == NULL) { - m = sctp_add_auth_chunk(m, - &endofchain, - &auth, - &auth_offset, - stcb, - SCTP_DATA); - auth_keyid = chk->auth_keyid; - override_ok = 0; - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } else if (override_ok) { - auth_keyid = chk->auth_keyid; - override_ok = 0; - } else if (chk->auth_keyid != auth_keyid) { - /* different keyid, so done bundling */ - break; - } - } - m = sctp_copy_mbufchain(chk->data, m, &endofchain, 0, chk->send_size, chk->copy_by_ref); - if (m == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - /* Do clear IP_DF ? */ - if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { - no_fragmentflg = 0; - } - /* update our MTU size */ - if (mtu > (chk->send_size + dmtu)) - mtu -= (chk->send_size + dmtu); - else - mtu = 0; - data_list[bundle_at++] = chk; - if (one_chunk && (asoc->total_flight <= 0)) { - SCTP_STAT_INCR(sctps_windowprobed); - } - } - if (one_chunk == 0) { - /* - * now are there anymore forward from chk to pick - * up? - */ - for (fwd = TAILQ_NEXT(chk, sctp_next); fwd != NULL; fwd = TAILQ_NEXT(fwd, sctp_next)) { - if (fwd->sent != SCTP_DATAGRAM_RESEND) { - /* Nope, not for retran */ - continue; - } - if (fwd->whoTo != net) { - /* Nope, not the net in question */ - continue; - } - if (data_auth_reqd && (auth == NULL)) { - dmtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); - } else - dmtu = 0; - if (fwd->send_size <= (mtu - dmtu)) { - if (data_auth_reqd) { - if (auth == NULL) { - m = sctp_add_auth_chunk(m, - &endofchain, - &auth, - &auth_offset, - stcb, - SCTP_DATA); - auth_keyid = fwd->auth_keyid; - override_ok = 0; - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } else if (override_ok) { - auth_keyid = fwd->auth_keyid; - override_ok = 0; - } else if (fwd->auth_keyid != auth_keyid) { - /* different keyid, so done bundling */ - break; - } - } - m = sctp_copy_mbufchain(fwd->data, m, &endofchain, 0, fwd->send_size, fwd->copy_by_ref); - if (m == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - /* Do clear IP_DF ? */ - if (fwd->flags & CHUNK_FLAGS_FRAGMENT_OK) { - no_fragmentflg = 0; - } - /* update our MTU size */ - if (mtu > (fwd->send_size + dmtu)) - mtu -= (fwd->send_size + dmtu); - else - mtu = 0; - data_list[bundle_at++] = fwd; - if (bundle_at >= SCTP_MAX_DATA_BUNDLING) { - break; - } - } else { - /* can't fit so we are done */ - break; - } - } - } - /* Is there something to send for this destination? */ - if (m) { - /* - * No matter if we fail/or succeed we should start a - * timer. A failure is like a lost IP packet :-) - */ - if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - /* - * no timer running on this destination - * restart it. - */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - tmr_started = 1; - } - switch (asoc->snd_edmid) { - case SCTP_EDMID_LOWER_LAYER_DTLS: - use_zero_crc = true; - break; - default: - use_zero_crc = false; - break; - } - /* Now lets send it, if there is anything to send :> */ - if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, - (struct sockaddr *)&net->ro._l_addr, m, - auth_offset, auth, auth_keyid, - no_fragmentflg, 0, 0, - inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), - net->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - use_zero_crc, - so_locked))) { - /* error, we could not output */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (error == ENOBUFS) { - asoc->ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - return (error); - } else { - asoc->ifp_had_enobuf = 0; - } - endofchain = NULL; - auth = NULL; - auth_offset = 0; - /* For HB's */ - /* - * We don't want to mark the net->sent time here - * since this we use this for HB and retrans cannot - * measure RTT - */ - /* (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time); */ - - /* For auto-close */ - if (*now_filled == 0) { - (void)SCTP_GETTIME_TIMEVAL(&asoc->time_last_sent); - *now = asoc->time_last_sent; - *now_filled = 1; - } else { - asoc->time_last_sent = *now; - } - *cnt_out += bundle_at; -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xC4, bundle_at); -#endif - if (bundle_at) { - tsns_sent = data_list[0]->rec.data.tsn; - } - for (i = 0; i < bundle_at; i++) { - SCTP_STAT_INCR(sctps_sendretransdata); - data_list[i]->sent = SCTP_DATAGRAM_SENT; - /* - * When we have a revoked data, and we - * retransmit it, then we clear the revoked - * flag since this flag dictates if we - * subtracted from the fs - */ - if (data_list[i]->rec.data.chunk_was_revoked) { - /* Deflate the cwnd */ - data_list[i]->whoTo->cwnd -= data_list[i]->book_size; - data_list[i]->rec.data.chunk_was_revoked = 0; - } - data_list[i]->snd_count++; - sctp_ucount_decr(asoc->sent_queue_retran_cnt); - /* record the time */ - data_list[i]->sent_rcv_time = asoc->time_last_sent; - if (data_list[i]->book_size_scale) { - /* - * need to double the book size on - * this one - */ - data_list[i]->book_size_scale = 0; - /* Since we double the booksize, we must - * also double the output queue size, since this - * get shrunk when we free by this amount. - */ - atomic_add_int(&((asoc)->total_output_queue_size), data_list[i]->book_size); - data_list[i]->book_size *= 2; - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { - sctp_log_rwnd(SCTP_DECREASE_PEER_RWND, - asoc->peers_rwnd, data_list[i]->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); - } - asoc->peers_rwnd = sctp_sbspace_sub(asoc->peers_rwnd, - (uint32_t) (data_list[i]->send_size + - SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_UP_RSND, - data_list[i]->whoTo->flight_size, - data_list[i]->book_size, - (uint32_t)(uintptr_t)data_list[i]->whoTo, - data_list[i]->rec.data.tsn); - } - sctp_flight_size_increase(data_list[i]); - sctp_total_flight_increase(stcb, data_list[i]); - if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { - /* SWS sender side engages */ - asoc->peers_rwnd = 0; - } - if ((i == 0) && - (data_list[i]->rec.data.doing_fast_retransmit)) { - SCTP_STAT_INCR(sctps_sendfastretrans); - if ((data_list[i] == TAILQ_FIRST(&asoc->sent_queue)) && - (tmr_started == 0)) { - /*- - * ok we just fast-retrans'd - * the lowest TSN, i.e the - * first on the list. In - * this case we want to give - * some more time to get a - * SACK back without a - * t3-expiring. - */ - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - } - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, tsns_sent, SCTP_CWND_LOG_FROM_RESEND); - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(21, inp, stcb, NULL); -#endif - } else { - /* None will fit */ - return (1); - } - if (asoc->sent_queue_retran_cnt <= 0) { - /* all done we have no more to retran */ - asoc->sent_queue_retran_cnt = 0; - break; - } - if (one_chunk) { - /* No more room in rwnd */ - return (1); - } - /* stop the for loop here. we sent out a packet */ - break; - } - return (0); -} - -static void -sctp_timer_validation(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_association *asoc) -{ - struct sctp_nets *net; - - /* Validate that a timer is running somewhere */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - /* Here is a timer */ - return; - } - } - SCTP_TCB_LOCK_ASSERT(stcb); - /* Gak, we did not have a timer somewhere */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n"); - if (asoc->alternate) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->alternate); - } else { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination); - } - return; -} - -void -sctp_chunk_output(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - int from_where, - int so_locked) -{ - /*- - * Ok this is the generic chunk service queue. we must do the - * following: - * - See if there are retransmits pending, if so we must - * do these first. - * - Service the stream queue that is next, moving any - * message (note I must get a complete message i.e. - * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning - * TSN's - * - Check to see if the cwnd/rwnd allows any output, if so we - * go ahead and formulate and send the low level chunks. Making sure - * to combine any control in the control chunk queue also. - */ - struct sctp_association *asoc; - struct sctp_nets *net; - int error = 0, num_out, tot_out = 0, ret = 0, reason_code; - unsigned int burst_cnt = 0; - struct timeval now; - int now_filled = 0; - int nagle_on; - uint32_t frag_point = sctp_get_frag_point(stcb); - int un_sent = 0; - int fr_done; - unsigned int tot_frs = 0; - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - asoc = &stcb->asoc; -do_it_again: - /* The Nagle algorithm is only applied when handling a send call. */ - if (from_where == SCTP_OUTPUT_FROM_USR_SEND) { - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY)) { - nagle_on = 0; - } else { - nagle_on = 1; - } - } else { - nagle_on = 0; - } - SCTP_TCB_LOCK_ASSERT(stcb); - - un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight); - - if ((un_sent <= 0) && - (TAILQ_EMPTY(&asoc->control_send_queue)) && - (TAILQ_EMPTY(&asoc->asconf_send_queue)) && - (asoc->sent_queue_retran_cnt == 0) && - (asoc->trigger_reset == 0)) { - /* Nothing to do unless there is something to be sent left */ - return; - } - /* Do we have something to send, data or control AND - * a sack timer running, if so piggy-back the sack. - */ - if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { - sctp_send_sack(stcb, so_locked); - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3); - } - while (asoc->sent_queue_retran_cnt) { - /*- - * Ok, it is retransmission time only, we send out only ONE - * packet with a single call off to the retran code. - */ - if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { - /*- - * Special hook for handling cookies discarded - * by peer that carried data. Send cookie-ack only - * and then the next call with get the retran's. - */ - (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, - from_where, - &now, &now_filled, frag_point, so_locked); - return; - } else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) { - /* if its not from a HB then do it */ - fr_done = 0; - ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled, &fr_done, so_locked); - if (fr_done) { - tot_frs++; - } - } else { - /* - * its from any other place, we don't allow retran - * output (only control) - */ - ret = 1; - } - if (ret > 0) { - /* Can't send anymore */ - /*- - * now lets push out control by calling med-level - * output once. this assures that we WILL send HB's - * if queued too. - */ - (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, - from_where, - &now, &now_filled, frag_point, so_locked); -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(8, inp, stcb, NULL); -#endif - sctp_timer_validation(inp, stcb, asoc); - return; - } - if (ret < 0) { - /*- - * The count was off.. retran is not happening so do - * the normal retransmission. - */ -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(9, inp, stcb, NULL); -#endif - if (ret == SCTP_RETRAN_EXIT) { - return; - } - break; - } - if (from_where == SCTP_OUTPUT_FROM_T3) { - /* Only one transmission allowed out of a timeout */ -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(10, inp, stcb, NULL); -#endif - /* Push out any control */ - (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, from_where, - &now, &now_filled, frag_point, so_locked); - return; - } - if ((asoc->fr_max_burst > 0) && (tot_frs >= asoc->fr_max_burst)) { - /* Hit FR burst limit */ - return; - } - if ((num_out == 0) && (ret == 0)) { - /* No more retrans to send */ - break; - } - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(12, inp, stcb, NULL); -#endif - /* Check for bad destinations, if they exist move chunks around. */ - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { - /*- - * if possible move things off of this address we - * still may send below due to the dormant state but - * we try to find an alternate address to send to - * and if we have one we move all queued data on the - * out wheel to this alternate address. - */ - if (net->ref_count > 1) - sctp_move_chunks_from_net(stcb, net); - } else { - /*- - * if ((asoc->sat_network) || (net->addr_is_local)) - * { burst_limit = asoc->max_burst * - * SCTP_SAT_NETWORK_BURST_INCR; } - */ - if (asoc->max_burst > 0) { - if (SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst)) { - if ((net->flight_size + (asoc->max_burst * net->mtu)) < net->cwnd) { - /* JRS - Use the congestion control given in the congestion control module */ - asoc->cc_functions.sctp_cwnd_update_after_output(stcb, net, asoc->max_burst); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { - sctp_log_maxburst(stcb, net, 0, asoc->max_burst, SCTP_MAX_BURST_APPLIED); - } - SCTP_STAT_INCR(sctps_maxburstqueued); - } - net->fast_retran_ip = 0; - } else { - if (net->flight_size == 0) { - /* Should be decaying the cwnd here */ - ; - } - } - } - } - } - burst_cnt = 0; - do { - error = sctp_med_chunk_output(inp, stcb, asoc, &num_out, - &reason_code, 0, from_where, - &now, &now_filled, frag_point, so_locked); - if (error) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Error %d was returned from med-c-op\n", error); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { - sctp_log_maxburst(stcb, asoc->primary_destination, error, burst_cnt, SCTP_MAX_BURST_ERROR_STOP); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, NULL, error, SCTP_SEND_NOW_COMPLETES); - sctp_log_cwnd(stcb, NULL, 0xdeadbeef, SCTP_SEND_NOW_COMPLETES); - } - break; - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "m-c-o put out %d\n", num_out); - - tot_out += num_out; - burst_cnt++; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, NULL, num_out, SCTP_SEND_NOW_COMPLETES); - if (num_out == 0) { - sctp_log_cwnd(stcb, NULL, reason_code, SCTP_SEND_NOW_COMPLETES); - } - } - if (nagle_on) { - /* - * When the Nagle algorithm is used, look at how much - * is unsent, then if its smaller than an MTU and we - * have data in flight we stop, except if we are - * handling a fragmented user message. - */ - un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight; - if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) && - (stcb->asoc.total_flight > 0)) { -/* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/ - break; - } - } - if (TAILQ_EMPTY(&asoc->control_send_queue) && - TAILQ_EMPTY(&asoc->send_queue) && - sctp_is_there_unsent_data(stcb, so_locked) == 0) { - /* Nothing left to send */ - break; - } - if ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) <= 0) { - /* Nothing left to send */ - break; - } - } while (num_out && - ((asoc->max_burst == 0) || - SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) || - (burst_cnt < asoc->max_burst))); - - if (SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) == 0) { - if ((asoc->max_burst > 0) && (burst_cnt >= asoc->max_burst)) { - SCTP_STAT_INCR(sctps_maxburstqueued); - asoc->burst_limit_applied = 1; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { - sctp_log_maxburst(stcb, asoc->primary_destination, 0, burst_cnt, SCTP_MAX_BURST_APPLIED); - } - } else { - asoc->burst_limit_applied = 0; - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, NULL, tot_out, SCTP_SEND_NOW_COMPLETES); - } - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, we have put out %d chunks\n", - tot_out); - - /*- - * Now we need to clean up the control chunk chain if a ECNE is on - * it. It must be marked as UNSENT again so next call will continue - * to send it until such time that we get a CWR, to remove it. - */ - if (stcb->asoc.ecn_echo_cnt_onq) - sctp_fix_ecn_echo(asoc); - - if (stcb->asoc.trigger_reset) { - if (sctp_send_stream_reset_out_if_possible(stcb, so_locked) == 0) { - goto do_it_again; - } - } - return; -} - -int -sctp_output( - struct sctp_inpcb *inp, - struct mbuf *m, - struct sockaddr *addr, - struct mbuf *control, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p, -#elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p, -#else -#if defined(__APPLE__) && !defined(__Userspace__) - struct proc *p SCTP_UNUSED, -#else - struct proc *p, -#endif -#endif - int flags) -{ - if (inp == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } - - if (inp->sctp_socket == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } - return (sctp_sosend(inp->sctp_socket, - addr, - (struct uio *)NULL, - m, - control, -#if defined(__APPLE__) && !defined(__Userspace__) - flags -#else - flags, p -#endif - )); -} - -void -send_forward_tsn(struct sctp_tcb *stcb, - struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *chk, *at, *tp1, *last; - struct sctp_forward_tsn_chunk *fwdtsn; - struct sctp_strseq *strseq; - struct sctp_strseq_mid *strseq_m; - uint32_t advance_peer_ack_point; - unsigned int cnt_of_space, i, ovh; - unsigned int space_needed; - unsigned int cnt_of_skipped = 0; - - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { - /* mark it to unsent */ - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - /* Do we correct its output location? */ - if (chk->whoTo) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; - } - goto sctp_fill_in_rest; - } - } - /* Ok if we reach here we must build one */ - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - return; - } - asoc->fwd_tsn_cnt++; - chk->copy_by_ref = 0; - /* - * We don't do the old thing here since - * this is used not for on-wire but to - * tell if we are sending a fwd-tsn by - * the stack during output. And if its - * a IFORWARD or a FORWARD it is a fwd-tsn. - */ - chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->asoc = asoc; - chk->whoTo = NULL; - chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return; - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt++; -sctp_fill_in_rest: - /*- - * Here we go through and fill out the part that deals with - * stream/seq of the ones we skip. - */ - SCTP_BUF_LEN(chk->data) = 0; - TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { - if ((at->sent != SCTP_FORWARD_TSN_SKIP) && - (at->sent != SCTP_DATAGRAM_NR_ACKED)) { - /* no more to look at */ - break; - } - if (!asoc->idata_supported && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { - /* We don't report these */ - continue; - } - cnt_of_skipped++; - } - if (asoc->idata_supported) { - space_needed = (sizeof(struct sctp_forward_tsn_chunk) + - (cnt_of_skipped * sizeof(struct sctp_strseq_mid))); - } else { - space_needed = (sizeof(struct sctp_forward_tsn_chunk) + - (cnt_of_skipped * sizeof(struct sctp_strseq))); - } - cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data); - - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MIN_OVERHEAD; - } else { - ovh = SCTP_MIN_V4_OVERHEAD; - } - if (cnt_of_space > (asoc->smallest_mtu - ovh)) { - /* trim to a mtu size */ - cnt_of_space = asoc->smallest_mtu - ovh; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xff, 0, cnt_of_skipped, - asoc->advanced_peer_ack_point); - } - advance_peer_ack_point = asoc->advanced_peer_ack_point; - if (cnt_of_space < space_needed) { - /*- - * ok we must trim down the chunk by lowering the - * advance peer ack point. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xff, 0xff, cnt_of_space, - space_needed); - } - cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk); - if (asoc->idata_supported) { - cnt_of_skipped /= sizeof(struct sctp_strseq_mid); - } else { - cnt_of_skipped /= sizeof(struct sctp_strseq); - } - /*- - * Go through and find the TSN that will be the one - * we report. - */ - at = TAILQ_FIRST(&asoc->sent_queue); - if (at != NULL) { - for (i = 0; i < cnt_of_skipped; i++) { - tp1 = TAILQ_NEXT(at, sctp_next); - if (tp1 == NULL) { - break; - } - at = tp1; - } - } - if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xff, cnt_of_skipped, at->rec.data.tsn, - asoc->advanced_peer_ack_point); - } - last = at; - /*- - * last now points to last one I can report, update - * peer ack point - */ - if (last) { - advance_peer_ack_point = last->rec.data.tsn; - } - if (asoc->idata_supported) { - space_needed = sizeof(struct sctp_forward_tsn_chunk) + - cnt_of_skipped * sizeof(struct sctp_strseq_mid); - } else { - space_needed = sizeof(struct sctp_forward_tsn_chunk) + - cnt_of_skipped * sizeof(struct sctp_strseq); - } - } - chk->send_size = space_needed; - /* Setup the chunk */ - fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *); - fwdtsn->ch.chunk_length = htons(chk->send_size); - fwdtsn->ch.chunk_flags = 0; - if (asoc->idata_supported) { - fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN; - } else { - fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN; - } - fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point); - SCTP_BUF_LEN(chk->data) = chk->send_size; - fwdtsn++; - /*- - * Move pointer to after the fwdtsn and transfer to the - * strseq pointer. - */ - if (asoc->idata_supported) { - strseq_m = (struct sctp_strseq_mid *)fwdtsn; - strseq = NULL; - } else { - strseq = (struct sctp_strseq *)fwdtsn; - strseq_m = NULL; - } - /*- - * Now populate the strseq list. This is done blindly - * without pulling out duplicate stream info. This is - * inefficient but won't harm the process since the peer will - * look at these in sequence and will thus release anything. - * It could mean we exceed the PMTU and chop off some that - * we could have included.. but this is unlikely (aka 1432/4 - * would mean 300+ stream seq's would have to be reported in - * one FWD-TSN. With a bit of work we can later FIX this to - * optimize and pull out duplicates.. but it does add more - * overhead. So for now... not! - */ - i = 0; - TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { - if (i >= cnt_of_skipped) { - break; - } - if (!asoc->idata_supported && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { - /* We don't report these */ - continue; - } - if (at->rec.data.tsn == advance_peer_ack_point) { - at->rec.data.fwd_tsn_cnt = 0; - } - if (asoc->idata_supported) { - strseq_m->sid = htons(at->rec.data.sid); - if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { - strseq_m->flags = htons(PR_SCTP_UNORDERED_FLAG); - } else { - strseq_m->flags = 0; - } - strseq_m->mid = htonl(at->rec.data.mid); - strseq_m++; - } else { - strseq->sid = htons(at->rec.data.sid); - strseq->ssn = htons((uint16_t)at->rec.data.mid); - strseq++; - } - i++; - } - return; -} - -void -sctp_send_sack(struct sctp_tcb *stcb, int so_locked) -{ - /*- - * Queue up a SACK or NR-SACK in the control queue. - * We must first check to see if a SACK or NR-SACK is - * somehow on the control queue. - * If so, we will take and and remove the old one. - */ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk, *a_chk; - struct sctp_sack_chunk *sack; - struct sctp_nr_sack_chunk *nr_sack; - struct sctp_gap_ack_block *gap_descriptor; - const struct sack_track *selector; - int mergeable = 0; - int offset; - caddr_t limit; - uint32_t *dup; - int limit_reached = 0; - unsigned int i, siz, j; - unsigned int num_gap_blocks = 0, num_nr_gap_blocks = 0, space; - int num_dups = 0; - int space_req; - uint32_t highest_tsn; - uint8_t flags; - uint8_t type; - uint8_t tsn_map; - - if (stcb->asoc.nrsack_supported == 1) { - type = SCTP_NR_SELECTIVE_ACK; - } else { - type = SCTP_SELECTIVE_ACK; - } - a_chk = NULL; - asoc = &stcb->asoc; - SCTP_TCB_LOCK_ASSERT(stcb); - if (asoc->last_data_chunk_from == NULL) { - /* Hmm we never received anything */ - return; - } - sctp_slide_mapping_arrays(stcb); - sctp_set_rwnd(stcb, asoc); - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if (chk->rec.chunk_id.id == type) { - /* Hmm, found a sack already on queue, remove it */ - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt--; - a_chk = chk; - if (a_chk->data) { - sctp_m_freem(a_chk->data); - a_chk->data = NULL; - } - if (a_chk->whoTo) { - sctp_free_remote_addr(a_chk->whoTo); - a_chk->whoTo = NULL; - } - break; - } - } - if (a_chk == NULL) { - sctp_alloc_a_chunk(stcb, a_chk); - if (a_chk == NULL) { - /* No memory so we drop the idea, and set a timer */ - if (stcb->asoc.delayed_ack) { - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4); - sctp_timer_start(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); - } else { - stcb->asoc.send_sack = 1; - } - return; - } - a_chk->copy_by_ref = 0; - a_chk->rec.chunk_id.id = type; - a_chk->rec.chunk_id.can_take_data = 1; - } - /* Clear our pkt counts */ - asoc->data_pkts_seen = 0; - - a_chk->flags = 0; - a_chk->asoc = asoc; - a_chk->snd_count = 0; - a_chk->send_size = 0; /* fill in later */ - a_chk->sent = SCTP_DATAGRAM_UNSENT; - a_chk->whoTo = NULL; - - if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) == 0) { - /*- - * Ok, the destination for the SACK is unreachable, lets see if - * we can select an alternate to asoc->last_data_chunk_from - */ - a_chk->whoTo = sctp_find_alternate_net(stcb, asoc->last_data_chunk_from, 0); - if (a_chk->whoTo == NULL) { - /* Nope, no alternate */ - a_chk->whoTo = asoc->last_data_chunk_from; - } - } else { - a_chk->whoTo = asoc->last_data_chunk_from; - } - if (a_chk->whoTo) { - atomic_add_int(&a_chk->whoTo->ref_count, 1); - } - if (SCTP_TSN_GT(asoc->highest_tsn_inside_map, asoc->highest_tsn_inside_nr_map)) { - highest_tsn = asoc->highest_tsn_inside_map; - } else { - highest_tsn = asoc->highest_tsn_inside_nr_map; - } - if (highest_tsn == asoc->cumulative_tsn) { - /* no gaps */ - if (type == SCTP_SELECTIVE_ACK) { - space_req = sizeof(struct sctp_sack_chunk); - } else { - space_req = sizeof(struct sctp_nr_sack_chunk); - } - } else { - /* gaps get a cluster */ - space_req = MCLBYTES; - } - /* Ok now lets formulate a MBUF with our sack */ - a_chk->data = sctp_get_mbuf_for_msg(space_req, 0, M_NOWAIT, 1, MT_DATA); - if ((a_chk->data == NULL) || - (a_chk->whoTo == NULL)) { - /* rats, no mbuf memory */ - if (a_chk->data) { - /* was a problem with the destination */ - sctp_m_freem(a_chk->data); - a_chk->data = NULL; - } - sctp_free_a_chunk(stcb, a_chk, so_locked); - /* sa_ignore NO_NULL_CHK */ - if (stcb->asoc.delayed_ack) { - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5); - sctp_timer_start(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL); - } else { - stcb->asoc.send_sack = 1; - } - return; - } - /* ok, lets go through and fill it in */ - SCTP_BUF_RESV_UF(a_chk->data, SCTP_MIN_OVERHEAD); - space = (unsigned int)M_TRAILINGSPACE(a_chk->data); - if (space > (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD)) { - space = (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD); - } - limit = mtod(a_chk->data, caddr_t); - limit += space; - - flags = 0; - - if ((asoc->sctp_cmt_on_off > 0) && - SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { - /*- - * CMT DAC algorithm: If 2 (i.e., 0x10) packets have been - * received, then set high bit to 1, else 0. Reset - * pkts_rcvd. - */ - flags |= (asoc->cmt_dac_pkts_rcvd << 6); - asoc->cmt_dac_pkts_rcvd = 0; - } -#ifdef SCTP_ASOCLOG_OF_TSNS - stcb->asoc.cumack_logsnt[stcb->asoc.cumack_log_atsnt] = asoc->cumulative_tsn; - stcb->asoc.cumack_log_atsnt++; - if (stcb->asoc.cumack_log_atsnt >= SCTP_TSN_LOG_SIZE) { - stcb->asoc.cumack_log_atsnt = 0; - } -#endif - /* reset the readers interpretation */ - stcb->freed_by_sorcv_sincelast = 0; - - if (type == SCTP_SELECTIVE_ACK) { - sack = mtod(a_chk->data, struct sctp_sack_chunk *); - nr_sack = NULL; - gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk)); - if (highest_tsn > asoc->mapping_array_base_tsn) { - siz = (((highest_tsn - asoc->mapping_array_base_tsn) + 1) + 7) / 8; - } else { - siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + highest_tsn + 7) / 8; - } - } else { - sack = NULL; - nr_sack = mtod(a_chk->data, struct sctp_nr_sack_chunk *); - gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)nr_sack + sizeof(struct sctp_nr_sack_chunk)); - if (asoc->highest_tsn_inside_map > asoc->mapping_array_base_tsn) { - siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; - } else { - siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_map + 7) / 8; - } - } - - if (SCTP_TSN_GT(asoc->mapping_array_base_tsn, asoc->cumulative_tsn)) { - offset = 1; - } else { - offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; - } - if (((type == SCTP_SELECTIVE_ACK) && - SCTP_TSN_GT(highest_tsn, asoc->cumulative_tsn)) || - ((type == SCTP_NR_SELECTIVE_ACK) && - SCTP_TSN_GT(asoc->highest_tsn_inside_map, asoc->cumulative_tsn))) { - /* we have a gap .. maybe */ - for (i = 0; i < siz; i++) { - tsn_map = asoc->mapping_array[i]; - if (type == SCTP_SELECTIVE_ACK) { - tsn_map |= asoc->nr_mapping_array[i]; - } - if (i == 0) { - /* - * Clear all bits corresponding to TSNs - * smaller or equal to the cumulative TSN. - */ - tsn_map &= (~0U << (1 - offset)); - } - selector = &sack_array[tsn_map]; - if (mergeable && selector->right_edge) { - /* - * Backup, left and right edges were ok to - * merge. - */ - num_gap_blocks--; - gap_descriptor--; - } - if (selector->num_entries == 0) - mergeable = 0; - else { - for (j = 0; j < selector->num_entries; j++) { - if (mergeable && selector->right_edge) { - /* - * do a merge by NOT setting - * the left side - */ - mergeable = 0; - } else { - /* - * no merge, set the left - * side - */ - mergeable = 0; - gap_descriptor->start = htons((selector->gaps[j].start + offset)); - } - gap_descriptor->end = htons((selector->gaps[j].end + offset)); - num_gap_blocks++; - gap_descriptor++; - if (((caddr_t)gap_descriptor + sizeof(struct sctp_gap_ack_block)) > limit) { - /* no more room */ - limit_reached = 1; - break; - } - } - if (selector->left_edge) { - mergeable = 1; - } - } - if (limit_reached) { - /* Reached the limit stop */ - break; - } - offset += 8; - } - } - if ((type == SCTP_NR_SELECTIVE_ACK) && - (limit_reached == 0)) { - mergeable = 0; - - if (asoc->highest_tsn_inside_nr_map > asoc->mapping_array_base_tsn) { - siz = (((asoc->highest_tsn_inside_nr_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; - } else { - siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_nr_map + 7) / 8; - } - - if (SCTP_TSN_GT(asoc->mapping_array_base_tsn, asoc->cumulative_tsn)) { - offset = 1; - } else { - offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; - } - if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn)) { - /* we have a gap .. maybe */ - for (i = 0; i < siz; i++) { - tsn_map = asoc->nr_mapping_array[i]; - if (i == 0) { - /* - * Clear all bits corresponding to TSNs - * smaller or equal to the cumulative TSN. - */ - tsn_map &= (~0U << (1 - offset)); - } - selector = &sack_array[tsn_map]; - if (mergeable && selector->right_edge) { - /* - * Backup, left and right edges were ok to - * merge. - */ - num_nr_gap_blocks--; - gap_descriptor--; - } - if (selector->num_entries == 0) - mergeable = 0; - else { - for (j = 0; j < selector->num_entries; j++) { - if (mergeable && selector->right_edge) { - /* - * do a merge by NOT setting - * the left side - */ - mergeable = 0; - } else { - /* - * no merge, set the left - * side - */ - mergeable = 0; - gap_descriptor->start = htons((selector->gaps[j].start + offset)); - } - gap_descriptor->end = htons((selector->gaps[j].end + offset)); - num_nr_gap_blocks++; - gap_descriptor++; - if (((caddr_t)gap_descriptor + sizeof(struct sctp_gap_ack_block)) > limit) { - /* no more room */ - limit_reached = 1; - break; - } - } - if (selector->left_edge) { - mergeable = 1; - } - } - if (limit_reached) { - /* Reached the limit stop */ - break; - } - offset += 8; - } - } - } - /* now we must add any dups we are going to report. */ - if ((limit_reached == 0) && (asoc->numduptsns)) { - dup = (uint32_t *) gap_descriptor; - for (i = 0; i < asoc->numduptsns; i++) { - *dup = htonl(asoc->dup_tsns[i]); - dup++; - num_dups++; - if (((caddr_t)dup + sizeof(uint32_t)) > limit) { - /* no more room */ - break; - } - } - asoc->numduptsns = 0; - } - /* - * now that the chunk is prepared queue it to the control chunk - * queue. - */ - if (type == SCTP_SELECTIVE_ACK) { - a_chk->send_size = (uint16_t)(sizeof(struct sctp_sack_chunk) + - (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + - num_dups * sizeof(int32_t)); - SCTP_BUF_LEN(a_chk->data) = a_chk->send_size; - sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); - sack->sack.a_rwnd = htonl(asoc->my_rwnd); - sack->sack.num_gap_ack_blks = htons(num_gap_blocks); - sack->sack.num_dup_tsns = htons(num_dups); - sack->ch.chunk_type = type; - sack->ch.chunk_flags = flags; - sack->ch.chunk_length = htons(a_chk->send_size); - } else { - a_chk->send_size = (uint16_t)(sizeof(struct sctp_nr_sack_chunk) + - (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + - num_dups * sizeof(int32_t)); - SCTP_BUF_LEN(a_chk->data) = a_chk->send_size; - nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); - nr_sack->nr_sack.a_rwnd = htonl(asoc->my_rwnd); - nr_sack->nr_sack.num_gap_ack_blks = htons(num_gap_blocks); - nr_sack->nr_sack.num_nr_gap_ack_blks = htons(num_nr_gap_blocks); - nr_sack->nr_sack.num_dup_tsns = htons(num_dups); - nr_sack->nr_sack.reserved = 0; - nr_sack->ch.chunk_type = type; - nr_sack->ch.chunk_flags = flags; - nr_sack->ch.chunk_length = htons(a_chk->send_size); - } - TAILQ_INSERT_TAIL(&asoc->control_send_queue, a_chk, sctp_next); - asoc->my_last_reported_rwnd = asoc->my_rwnd; - asoc->ctrl_queue_cnt++; - asoc->send_sack = 0; - SCTP_STAT_INCR(sctps_sendsacks); - return; -} - -void -sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked) -{ - struct mbuf *m_abort, *m, *m_last; - struct mbuf *m_out, *m_end = NULL; - struct sctp_abort_chunk *abort; - struct sctp_auth_chunk *auth = NULL; - struct sctp_nets *net; - uint32_t vtag; - uint32_t auth_offset = 0; - int error; - uint16_t cause_len, chunk_len, padding_len; - bool use_zero_crc; - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } else { - sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } -#endif - SCTP_TCB_LOCK_ASSERT(stcb); - /*- - * Add an AUTH chunk, if chunk requires it and save the offset into - * the chain for AUTH - */ - if (sctp_auth_is_required_chunk(SCTP_ABORT_ASSOCIATION, - stcb->asoc.peer_auth_chunks)) { - m_out = sctp_add_auth_chunk(NULL, &m_end, &auth, &auth_offset, - stcb, SCTP_ABORT_ASSOCIATION); - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - } else { - m_out = NULL; - } - switch (stcb->asoc.snd_edmid) { - case SCTP_EDMID_LOWER_LAYER_DTLS: - use_zero_crc = true; - break; - default: - use_zero_crc = false; - break; - } - m_abort = sctp_get_mbuf_for_msg(sizeof(struct sctp_abort_chunk), 0, M_NOWAIT, 1, MT_HEADER); - if (m_abort == NULL) { - if (m_out) { - sctp_m_freem(m_out); - } - if (operr) { - sctp_m_freem(operr); - } - return; - } - /* link in any error */ - SCTP_BUF_NEXT(m_abort) = operr; - cause_len = 0; - m_last = NULL; - for (m = operr; m; m = SCTP_BUF_NEXT(m)) { - cause_len += (uint16_t)SCTP_BUF_LEN(m); - if (SCTP_BUF_NEXT(m) == NULL) { - m_last = m; - } - } - SCTP_BUF_LEN(m_abort) = sizeof(struct sctp_abort_chunk); - chunk_len = (uint16_t)sizeof(struct sctp_abort_chunk) + cause_len; - padding_len = SCTP_SIZE32(chunk_len) - chunk_len; - if (m_out == NULL) { - /* NO Auth chunk prepended, so reserve space in front */ - SCTP_BUF_RESV_UF(m_abort, SCTP_MIN_OVERHEAD); - m_out = m_abort; - } else { - /* Put AUTH chunk at the front of the chain */ - SCTP_BUF_NEXT(m_end) = m_abort; - } - if (stcb->asoc.alternate) { - net = stcb->asoc.alternate; - } else { - net = stcb->asoc.primary_destination; - } - /* Fill in the ABORT chunk header. */ - abort = mtod(m_abort, struct sctp_abort_chunk *); - abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION; - if (stcb->asoc.peer_vtag == 0) { - /* This happens iff the assoc is in COOKIE-WAIT state. */ - vtag = stcb->asoc.my_vtag; - abort->ch.chunk_flags = SCTP_HAD_NO_TCB; - } else { - vtag = stcb->asoc.peer_vtag; - abort->ch.chunk_flags = 0; - } - abort->ch.chunk_length = htons(chunk_len); - /* Add padding, if necessary. */ - if (padding_len > 0) { - if ((m_last == NULL) || - (sctp_add_pad_tombuf(m_last, padding_len) == NULL)) { - sctp_m_freem(m_out); - return; - } - } - if ((error = sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, - (struct sockaddr *)&net->ro._l_addr, - m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, 0, - stcb->sctp_ep->sctp_lport, stcb->rport, htonl(vtag), - stcb->asoc.primary_destination->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - use_zero_crc, - so_locked))) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (error == ENOBUFS) { - stcb->asoc.ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - } else { - stcb->asoc.ifp_had_enobuf = 0; - } - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); -} - -void -sctp_send_shutdown_complete(struct sctp_tcb *stcb, - struct sctp_nets *net, - int reflect_vtag) -{ - /* formulate and SEND a SHUTDOWN-COMPLETE */ - struct mbuf *m_shutdown_comp; - struct sctp_shutdown_complete_chunk *shutdown_complete; - uint32_t vtag; - int error; - uint8_t flags; - bool use_zero_crc; - - m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER); - if (m_shutdown_comp == NULL) { - /* no mbuf's */ - return; - } - if (reflect_vtag) { - flags = SCTP_HAD_NO_TCB; - vtag = stcb->asoc.my_vtag; - } else { - flags = 0; - vtag = stcb->asoc.peer_vtag; - } - switch (stcb->asoc.snd_edmid) { - case SCTP_EDMID_LOWER_LAYER_DTLS: - use_zero_crc = true; - break; - default: - use_zero_crc = false; - break; - } - shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *); - shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; - shutdown_complete->ch.chunk_flags = flags; - shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); - SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk); - if ((error = sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, - (struct sockaddr *)&net->ro._l_addr, - m_shutdown_comp, 0, NULL, 0, 1, 0, 0, - stcb->sctp_ep->sctp_lport, stcb->rport, - htonl(vtag), - net->port, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - 0, 0, -#endif - use_zero_crc, - SCTP_SO_NOT_LOCKED))) { - SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); - if (error == ENOBUFS) { - stcb->asoc.ifp_had_enobuf = 1; - SCTP_STAT_INCR(sctps_lowlevelerr); - } - } else { - stcb->asoc.ifp_had_enobuf = 0; - } - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - return; -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static void -sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, uint32_t vtag, - uint8_t type, struct mbuf *cause, - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, - uint32_t vrf_id, uint16_t port) -#else -static void -sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, uint32_t vtag, - uint8_t type, struct mbuf *cause, - uint32_t vrf_id SCTP_UNUSED, uint16_t port) -#endif -{ - struct mbuf *o_pak; - struct mbuf *mout; - struct sctphdr *shout; - struct sctp_chunkhdr *ch; -#if defined(INET) || defined(INET6) - struct udphdr *udp; -#endif - int ret, len, cause_len, padding_len; -#ifdef INET -#if defined(__APPLE__) && !defined(__Userspace__) - sctp_route_t ro; -#endif - struct sockaddr_in *src_sin, *dst_sin; - struct ip *ip; -#endif -#ifdef INET6 - struct sockaddr_in6 *src_sin6, *dst_sin6; - struct ip6_hdr *ip6; -#endif - - /* Compute the length of the cause and add final padding. */ - cause_len = 0; - if (cause != NULL) { - struct mbuf *m_at, *m_last = NULL; - - for (m_at = cause; m_at; m_at = SCTP_BUF_NEXT(m_at)) { - if (SCTP_BUF_NEXT(m_at) == NULL) - m_last = m_at; - cause_len += SCTP_BUF_LEN(m_at); - } - padding_len = cause_len % 4; - if (padding_len != 0) { - padding_len = 4 - padding_len; - } - if (padding_len != 0) { - if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) { - sctp_m_freem(cause); - return; - } - } - } else { - padding_len = 0; - } - /* Get an mbuf for the header. */ - len = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - switch (dst->sa_family) { -#ifdef INET - case AF_INET: - len += sizeof(struct ip); - break; -#endif -#ifdef INET6 - case AF_INET6: - len += sizeof(struct ip6_hdr); - break; -#endif - default: - break; - } -#if defined(INET) || defined(INET6) - if (port) { - len += sizeof(struct udphdr); - } -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_NOWAIT, 1, MT_DATA); -#else - mout = sctp_get_mbuf_for_msg(len + SCTP_MAX_LINKHDR, 1, M_NOWAIT, 1, MT_DATA); -#endif -#else - mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_NOWAIT, 1, MT_DATA); -#endif - if (mout == NULL) { - if (cause) { - sctp_m_freem(cause); - } - return; - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - SCTP_BUF_RESV_UF(mout, max_linkhdr); -#else - SCTP_BUF_RESV_UF(mout, SCTP_MAX_LINKHDR); -#endif -#else - SCTP_BUF_RESV_UF(mout, max_linkhdr); -#endif - SCTP_BUF_LEN(mout) = len; - SCTP_BUF_NEXT(mout) = cause; -#if defined(__FreeBSD__) && !defined(__Userspace__) - M_SETFIB(mout, fibnum); - mout->m_pkthdr.flowid = mflowid; - M_HASHTYPE_SET(mout, mflowtype); -#endif -#ifdef INET - ip = NULL; -#endif -#ifdef INET6 - ip6 = NULL; -#endif - switch (dst->sa_family) { -#ifdef INET - case AF_INET: - src_sin = (struct sockaddr_in *)src; - dst_sin = (struct sockaddr_in *)dst; - ip = mtod(mout, struct ip *); - ip->ip_v = IPVERSION; - ip->ip_hl = (sizeof(struct ip) >> 2); - ip->ip_tos = 0; -#if defined(__FreeBSD__) && !defined(__Userspace__) - ip->ip_off = htons(IP_DF); -#elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) - ip->ip_off = IP_DF; -#else - ip->ip_off = htons(IP_DF); -#endif -#if defined(__Userspace__) - ip->ip_id = htons(ip_id++); -#elif defined(__FreeBSD__) - ip_fillid(ip); -#elif defined(__APPLE__) -#if RANDOM_IP_ID - ip->ip_id = ip_randomid(); -#else - ip->ip_id = htons(ip_id++); -#endif -#else - ip->ip_id = ip_id++; -#endif - ip->ip_ttl = MODULE_GLOBAL(ip_defttl); - if (port) { - ip->ip_p = IPPROTO_UDP; - } else { - ip->ip_p = IPPROTO_SCTP; - } - ip->ip_src.s_addr = dst_sin->sin_addr.s_addr; - ip->ip_dst.s_addr = src_sin->sin_addr.s_addr; - ip->ip_sum = 0; - len = sizeof(struct ip); - shout = (struct sctphdr *)((caddr_t)ip + len); - break; -#endif -#ifdef INET6 - case AF_INET6: - src_sin6 = (struct sockaddr_in6 *)src; - dst_sin6 = (struct sockaddr_in6 *)dst; - ip6 = mtod(mout, struct ip6_hdr *); - ip6->ip6_flow = htonl(0x60000000); -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (V_ip6_auto_flowlabel) { - ip6->ip6_flow |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); - } -#endif -#if defined(__Userspace__) - ip6->ip6_hlim = IPv6_HOP_LIMIT; -#else - ip6->ip6_hlim = MODULE_GLOBAL(ip6_defhlim); -#endif - if (port) { - ip6->ip6_nxt = IPPROTO_UDP; - } else { - ip6->ip6_nxt = IPPROTO_SCTP; - } - ip6->ip6_src = dst_sin6->sin6_addr; - ip6->ip6_dst = src_sin6->sin6_addr; - len = sizeof(struct ip6_hdr); - shout = (struct sctphdr *)((caddr_t)ip6 + len); - break; -#endif - default: - len = 0; - shout = mtod(mout, struct sctphdr *); - break; - } -#if defined(INET) || defined(INET6) - if (port) { - if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) { - sctp_m_freem(mout); - return; - } - udp = (struct udphdr *)shout; - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_sum = 0; - udp->uh_ulen = htons((uint16_t)(sizeof(struct udphdr) + - sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr) + - cause_len + padding_len)); - len += sizeof(struct udphdr); - shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr)); - } else { - udp = NULL; - } -#endif - shout->src_port = sh->dest_port; - shout->dest_port = sh->src_port; - shout->checksum = 0; - if (vtag) { - shout->v_tag = htonl(vtag); - } else { - shout->v_tag = sh->v_tag; - } - len += sizeof(struct sctphdr); - ch = (struct sctp_chunkhdr *)((caddr_t)shout + sizeof(struct sctphdr)); - ch->chunk_type = type; - if (vtag) { - ch->chunk_flags = 0; - } else { - ch->chunk_flags = SCTP_HAD_NO_TCB; - } - ch->chunk_length = htons((uint16_t)(sizeof(struct sctp_chunkhdr) + cause_len)); - len += sizeof(struct sctp_chunkhdr); - len += cause_len + padding_len; - - if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { - sctp_m_freem(mout); - return; - } - SCTP_ATTACH_CHAIN(o_pak, mout, len); - switch (dst->sa_family) { -#ifdef INET - case AF_INET: -#if defined(__APPLE__) && !defined(__Userspace__) - /* zap the stack pointer to the route */ - memset(&ro, 0, sizeof(sctp_route_t)); -#endif - if (port) { -#if !defined(_WIN32) && !defined(__Userspace__) -#if defined(__FreeBSD__) - if (V_udp_cksum) { - udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); - } else { - udp->uh_sum = 0; - } -#else - udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); -#endif -#else - udp->uh_sum = 0; -#endif - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - ip->ip_len = htons(len); -#elif defined(__APPLE__) || defined(__Userspace__) - ip->ip_len = len; -#else - ip->ip_len = htons(len); -#endif - if (port) { - shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); -#if !defined(_WIN32) && !defined(__Userspace__) -#if defined(__FreeBSD__) - if (V_udp_cksum) { - SCTP_ENABLE_UDP_CSUM(o_pak); - } -#else - SCTP_ENABLE_UDP_CSUM(o_pak); -#endif -#endif - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - mout->m_pkthdr.csum_flags = CSUM_SCTP; - mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); - SCTP_STAT_INCR(sctps_sendhwcrc); -#else - shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip)); - SCTP_STAT_INCR(sctps_sendswcrc); -#endif - } -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { - sctp_packet_log(o_pak); - } -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id); - /* Free the route if we got one back */ - if (ro.ro_rt) { - RTFREE(ro.ro_rt); - ro.ro_rt = NULL; - } -#else -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(send, NULL, NULL, ip, NULL, shout); -#endif - SCTP_IP_OUTPUT(ret, o_pak, NULL, NULL, vrf_id); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - ip6->ip6_plen = htons((uint16_t)(len - sizeof(struct ip6_hdr))); - if (port) { - shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); -#if !defined(__Userspace__) -#if defined(_WIN32) - udp->uh_sum = 0; -#else - if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { - udp->uh_sum = 0xffff; - } -#endif -#endif - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - mout->m_pkthdr.csum_flags = CSUM_SCTP_IPV6; - mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); - SCTP_STAT_INCR(sctps_sendhwcrc); -#else - shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr)); - SCTP_STAT_INCR(sctps_sendswcrc); -#endif - } -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { - sctp_packet_log(o_pak); - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PROBE5(send, NULL, NULL, ip6, NULL, shout); -#endif - SCTP_IP6_OUTPUT(ret, o_pak, NULL, NULL, NULL, vrf_id); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - { - char *buffer; - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)src; - if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { - shout->checksum = sctp_calculate_cksum(o_pak, 0); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendhwcrc); - } -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { - sctp_packet_log(mout); - } -#endif - /* Don't alloc/free for each packet */ - if ((buffer = malloc(len)) != NULL) { - m_copydata(o_pak, 0, len, buffer); - ret = SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, len, 0, 0); - free(buffer); - } else { - ret = ENOMEM; - } - sctp_m_freem(o_pak); - break; - } -#endif - default: - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Unknown protocol (TSNH) type %d\n", - dst->sa_family); - sctp_m_freem(mout); - SCTP_LTRACE_ERR_RET_PKT(mout, NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); - return; - } - SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret); -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (port) { - UDPSTAT_INC(udps_opackets); - } -#endif - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); - if (ret) { - SCTP_STAT_INCR(sctps_senderrors); - } - return; -} - -void -sctp_send_shutdown_complete2(struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, -#endif - uint32_t vrf_id, uint16_t port) -{ - sctp_send_resp_msg(src, dst, sh, 0, SCTP_SHUTDOWN_COMPLETE, NULL, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); -} - -void -sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net,int so_locked) -{ - struct sctp_tmit_chunk *chk; - struct sctp_heartbeat_chunk *hb; - struct timeval now; - - SCTP_TCB_LOCK_ASSERT(stcb); - if (net == NULL) { - return; - } - (void)SCTP_GETTIME_TIMEVAL(&now); - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - break; -#endif -#ifdef INET6 - case AF_INET6: - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - break; -#endif - default: - return; - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n"); - return; - } - - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->send_size = sizeof(struct sctp_heartbeat_chunk); - - chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, so_locked); - return; - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - SCTP_BUF_LEN(chk->data) = chk->send_size; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - /* Now we have a mbuf that we can fill in with the details */ - hb = mtod(chk->data, struct sctp_heartbeat_chunk *); - memset(hb, 0, sizeof(struct sctp_heartbeat_chunk)); - /* fill out chunk header */ - hb->ch.chunk_type = SCTP_HEARTBEAT_REQUEST; - hb->ch.chunk_flags = 0; - hb->ch.chunk_length = htons(chk->send_size); - /* Fill out hb parameter */ - hb->heartbeat.hb_info.ph.param_type = htons(SCTP_HEARTBEAT_INFO); - hb->heartbeat.hb_info.ph.param_length = htons(sizeof(struct sctp_heartbeat_info_param)); - hb->heartbeat.hb_info.time_value_1 = (uint32_t)now.tv_sec; - hb->heartbeat.hb_info.time_value_2 = now.tv_usec; - /* Did our user request this one, put it in */ - hb->heartbeat.hb_info.addr_family = (uint8_t)net->ro._l_addr.sa.sa_family; -#ifdef HAVE_SA_LEN - hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len; -#else - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - hb->heartbeat.hb_info.addr_len = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - hb->heartbeat.hb_info.addr_len = sizeof(struct sockaddr_in6); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - hb->heartbeat.hb_info.addr_len = sizeof(struct sockaddr_conn); - break; -#endif - default: - hb->heartbeat.hb_info.addr_len = 0; - break; - } -#endif - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { - /* - * we only take from the entropy pool if the address is not - * confirmed. - */ - net->heartbeat_random1 = hb->heartbeat.hb_info.random_value1 = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); - net->heartbeat_random2 = hb->heartbeat.hb_info.random_value2 = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); - } else { - net->heartbeat_random1 = hb->heartbeat.hb_info.random_value1 = 0; - net->heartbeat_random2 = hb->heartbeat.hb_info.random_value2 = 0; - } - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - memcpy(hb->heartbeat.hb_info.address, - &net->ro._l_addr.sin.sin_addr, - sizeof(net->ro._l_addr.sin.sin_addr)); - break; -#endif -#ifdef INET6 - case AF_INET6: - memcpy(hb->heartbeat.hb_info.address, - &net->ro._l_addr.sin6.sin6_addr, - sizeof(net->ro._l_addr.sin6.sin6_addr)); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(hb->heartbeat.hb_info.address, - &net->ro._l_addr.sconn.sconn_addr, - sizeof(net->ro._l_addr.sconn.sconn_addr)); - break; -#endif - default: - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, so_locked); - return; - break; - } - net->hb_responded = 0; - TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); - stcb->asoc.ctrl_queue_cnt++; - SCTP_STAT_INCR(sctps_sendheartbeat); - return; -} - -void -sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, - uint32_t high_tsn) -{ - struct sctp_association *asoc; - struct sctp_ecne_chunk *ecne; - struct sctp_tmit_chunk *chk; - - if (net == NULL) { - return; - } - asoc = &stcb->asoc; - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if ((chk->rec.chunk_id.id == SCTP_ECN_ECHO) && (net == chk->whoTo)) { - /* found a previous ECN_ECHO update it if needed */ - uint32_t cnt, ctsn; - ecne = mtod(chk->data, struct sctp_ecne_chunk *); - ctsn = ntohl(ecne->tsn); - if (SCTP_TSN_GT(high_tsn, ctsn)) { - ecne->tsn = htonl(high_tsn); - SCTP_STAT_INCR(sctps_queue_upd_ecne); - } - cnt = ntohl(ecne->num_pkts_since_cwr); - cnt++; - ecne->num_pkts_since_cwr = htonl(cnt); - return; - } - } - /* nope could not find one to update so we must build one */ - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - return; - } - SCTP_STAT_INCR(sctps_queue_upd_ecne); - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_ECN_ECHO; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->send_size = sizeof(struct sctp_ecne_chunk); - chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return; - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - SCTP_BUF_LEN(chk->data) = chk->send_size; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - - stcb->asoc.ecn_echo_cnt_onq++; - ecne = mtod(chk->data, struct sctp_ecne_chunk *); - ecne->ch.chunk_type = SCTP_ECN_ECHO; - ecne->ch.chunk_flags = 0; - ecne->ch.chunk_length = htons(sizeof(struct sctp_ecne_chunk)); - ecne->tsn = htonl(high_tsn); - ecne->num_pkts_since_cwr = htonl(1); - TAILQ_INSERT_HEAD(&stcb->asoc.control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt++; -} - -void -sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, - struct mbuf *m, int len, int iphlen, int bad_crc) -{ - struct sctp_association *asoc; - struct sctp_pktdrop_chunk *drp; - struct sctp_tmit_chunk *chk; - uint8_t *datap; - int was_trunc = 0; - int fullsz = 0; - long spc; - int offset; - struct sctp_chunkhdr *ch, chunk_buf; - unsigned int chk_length; - - if (!stcb) { - return; - } - asoc = &stcb->asoc; - SCTP_TCB_LOCK_ASSERT(stcb); - if (asoc->pktdrop_supported == 0) { - /*- - * peer must declare support before I send one. - */ - return; - } - if (stcb->sctp_socket == NULL) { - return; - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_PACKET_DROPPED; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - len -= iphlen; - chk->send_size = len; - /* Validate that we do not have an ABORT in here. */ - offset = iphlen + sizeof(struct sctphdr); - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, - sizeof(*ch), (uint8_t *) & chunk_buf); - while (ch != NULL) { - chk_length = ntohs(ch->chunk_length); - if (chk_length < sizeof(*ch)) { - /* break to abort land */ - break; - } - switch (ch->chunk_type) { - case SCTP_PACKET_DROPPED: - case SCTP_ABORT_ASSOCIATION: - case SCTP_INITIATION_ACK: - /** - * We don't respond with an PKT-DROP to an ABORT - * or PKT-DROP. We also do not respond to an - * INIT-ACK, because we can't know if the initiation - * tag is correct or not. - */ - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return; - default: - break; - } - offset += SCTP_SIZE32(chk_length); - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, - sizeof(*ch), (uint8_t *) & chunk_buf); - } - - if ((len + SCTP_MAX_OVERHEAD + sizeof(struct sctp_pktdrop_chunk)) > - min(stcb->asoc.smallest_mtu, MCLBYTES)) { - /* only send 1 mtu worth, trim off the - * excess on the end. - */ - fullsz = len; - len = min(stcb->asoc.smallest_mtu, MCLBYTES) - SCTP_MAX_OVERHEAD; - was_trunc = 1; - } - chk->asoc = &stcb->asoc; - chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (chk->data == NULL) { -jump_out: - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return; - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - drp = mtod(chk->data, struct sctp_pktdrop_chunk *); - if (drp == NULL) { - sctp_m_freem(chk->data); - chk->data = NULL; - goto jump_out; - } - chk->book_size = SCTP_SIZE32((chk->send_size + sizeof(struct sctp_pktdrop_chunk) + - sizeof(struct sctphdr) + SCTP_MED_OVERHEAD)); - chk->book_size_scale = 0; - if (was_trunc) { - drp->ch.chunk_flags = SCTP_PACKET_TRUNCATED; - drp->trunc_len = htons(fullsz); - /* Len is already adjusted to size minus overhead above - * take out the pkt_drop chunk itself from it. - */ - chk->send_size = (uint16_t)(len - sizeof(struct sctp_pktdrop_chunk)); - len = chk->send_size; - } else { - /* no truncation needed */ - drp->ch.chunk_flags = 0; - drp->trunc_len = htons(0); - } - if (bad_crc) { - drp->ch.chunk_flags |= SCTP_BADCRC; - } - chk->send_size += sizeof(struct sctp_pktdrop_chunk); - SCTP_BUF_LEN(chk->data) = chk->send_size; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - if (net) { - /* we should hit here */ - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - } else { - chk->whoTo = NULL; - } - drp->ch.chunk_type = SCTP_PACKET_DROPPED; - drp->ch.chunk_length = htons(chk->send_size); - spc = SCTP_SB_LIMIT_RCV(stcb->sctp_socket); - if (spc < 0) { - spc = 0; - } - drp->bottle_bw = htonl(spc); - if (asoc->my_rwnd) { - drp->current_onq = htonl(asoc->size_on_reasm_queue + - asoc->size_on_all_streams + - asoc->my_rwnd_control_len + - SCTP_SBAVAIL(&stcb->sctp_socket->so_rcv)); - } else { - /*- - * If my rwnd is 0, possibly from mbuf depletion as well as - * space used, tell the peer there is NO space aka onq == bw - */ - drp->current_onq = htonl(spc); - } - drp->reserved = 0; - datap = drp->data; - m_copydata(m, iphlen, len, (caddr_t)datap); - TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt++; -} - -void -sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, uint8_t override) -{ - struct sctp_association *asoc; - struct sctp_cwr_chunk *cwr; - struct sctp_tmit_chunk *chk; - - SCTP_TCB_LOCK_ASSERT(stcb); - if (net == NULL) { - return; - } - asoc = &stcb->asoc; - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) { - /* found a previous CWR queued to same destination update it if needed */ - uint32_t ctsn; - cwr = mtod(chk->data, struct sctp_cwr_chunk *); - ctsn = ntohl(cwr->tsn); - if (SCTP_TSN_GT(high_tsn, ctsn)) { - cwr->tsn = htonl(high_tsn); - } - if (override & SCTP_CWR_REDUCE_OVERRIDE) { - /* Make sure override is carried */ - cwr->ch.chunk_flags |= SCTP_CWR_REDUCE_OVERRIDE; - } - return; - } - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_ECN_CWR; - chk->rec.chunk_id.can_take_data = 1; - chk->flags = 0; - chk->asoc = asoc; - chk->send_size = sizeof(struct sctp_cwr_chunk); - chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return; - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - SCTP_BUF_LEN(chk->data) = chk->send_size; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - cwr = mtod(chk->data, struct sctp_cwr_chunk *); - cwr->ch.chunk_type = SCTP_ECN_CWR; - cwr->ch.chunk_flags = override; - cwr->ch.chunk_length = htons(sizeof(struct sctp_cwr_chunk)); - cwr->tsn = htonl(high_tsn); - TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); - asoc->ctrl_queue_cnt++; -} - -static int -sctp_add_stream_reset_out(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, - uint32_t seq, uint32_t resp_seq, uint32_t last_sent) -{ - uint16_t len, old_len, i; - struct sctp_stream_reset_out_request *req_out; - struct sctp_chunkhdr *ch; - int at; - int number_entries=0; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - /* get to new offset for the param. */ - req_out = (struct sctp_stream_reset_out_request *)((caddr_t)ch + len); - /* now how long will this param be? */ - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) && - (stcb->asoc.strmout[i].chunks_on_queues == 0) && - TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - number_entries++; - } - } - if (number_entries == 0) { - return (0); - } - if (number_entries == stcb->asoc.streamoutcnt) { - number_entries = 0; - } - if (number_entries > SCTP_MAX_STREAMS_AT_ONCE_RESET) { - number_entries = SCTP_MAX_STREAMS_AT_ONCE_RESET; - } - len = (uint16_t)(sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries)); - req_out->ph.param_type = htons(SCTP_STR_RESET_OUT_REQUEST); - req_out->ph.param_length = htons(len); - req_out->request_seq = htonl(seq); - req_out->response_seq = htonl(resp_seq); - req_out->send_reset_at_tsn = htonl(last_sent); - at = 0; - if (number_entries) { - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) && - (stcb->asoc.strmout[i].chunks_on_queues == 0) && - TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - req_out->list_of_streams[at] = htons(i); - at++; - stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT; - if (at >= number_entries) { - break; - } - } - } - } else { - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT; - } - } - if (SCTP_SIZE32(len) > len) { - /*- - * Need to worry about the pad we may end up adding to the - * end. This is easy since the struct is either aligned to 4 - * bytes or 2 bytes off. - */ - req_out->list_of_streams[number_entries] = 0; - } - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->book_size = len + old_len; - chk->book_size_scale = 0; - chk->send_size = SCTP_SIZE32(chk->book_size); - SCTP_BUF_LEN(chk->data) = chk->send_size; - return (1); -} - -static void -sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk, - int number_entries, uint16_t *list, - uint32_t seq) -{ - uint16_t len, old_len, i; - struct sctp_stream_reset_in_request *req_in; - struct sctp_chunkhdr *ch; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - - /* get to new offset for the param. */ - req_in = (struct sctp_stream_reset_in_request *)((caddr_t)ch + len); - /* now how long will this param be? */ - len = (uint16_t)(sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries)); - req_in->ph.param_type = htons(SCTP_STR_RESET_IN_REQUEST); - req_in->ph.param_length = htons(len); - req_in->request_seq = htonl(seq); - if (number_entries) { - for (i = 0; i < number_entries; i++) { - req_in->list_of_streams[i] = htons(list[i]); - } - } - if (SCTP_SIZE32(len) > len) { - /*- - * Need to worry about the pad we may end up adding to the - * end. This is easy since the struct is either aligned to 4 - * bytes or 2 bytes off. - */ - req_in->list_of_streams[number_entries] = 0; - } - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->book_size = len + old_len; - chk->book_size_scale = 0; - chk->send_size = SCTP_SIZE32(chk->book_size); - SCTP_BUF_LEN(chk->data) = chk->send_size; - return; -} - -static void -sctp_add_stream_reset_tsn(struct sctp_tmit_chunk *chk, - uint32_t seq) -{ - uint16_t len, old_len; - struct sctp_stream_reset_tsn_request *req_tsn; - struct sctp_chunkhdr *ch; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - - /* get to new offset for the param. */ - req_tsn = (struct sctp_stream_reset_tsn_request *)((caddr_t)ch + len); - /* now how long will this param be? */ - len = sizeof(struct sctp_stream_reset_tsn_request); - req_tsn->ph.param_type = htons(SCTP_STR_RESET_TSN_REQUEST); - req_tsn->ph.param_length = htons(len); - req_tsn->request_seq = htonl(seq); - - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->send_size = len + old_len; - chk->book_size = SCTP_SIZE32(chk->send_size); - chk->book_size_scale = 0; - SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); - return; -} - -void -sctp_add_stream_reset_result(struct sctp_tmit_chunk *chk, - uint32_t resp_seq, uint32_t result) -{ - uint16_t len, old_len; - struct sctp_stream_reset_response *resp; - struct sctp_chunkhdr *ch; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - - /* get to new offset for the param. */ - resp = (struct sctp_stream_reset_response *)((caddr_t)ch + len); - /* now how long will this param be? */ - len = sizeof(struct sctp_stream_reset_response); - resp->ph.param_type = htons(SCTP_STR_RESET_RESPONSE); - resp->ph.param_length = htons(len); - resp->response_seq = htonl(resp_seq); - resp->result = ntohl(result); - - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->book_size = len + old_len; - chk->book_size_scale = 0; - chk->send_size = SCTP_SIZE32(chk->book_size); - SCTP_BUF_LEN(chk->data) = chk->send_size; - return; -} - -void -sctp_send_deferred_reset_response(struct sctp_tcb *stcb, - struct sctp_stream_reset_list *ent, - int response) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - struct sctp_chunkhdr *ch; - - asoc = &stcb->asoc; - - /* - * Reset our last reset action to the new one IP -> response - * (PERFORMED probably). This assures that if we fail to send, a - * retran from the peer will get the new response. - */ - asoc->last_reset_action[0] = response; - if (asoc->stream_reset_outstanding) { - return; - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return; - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_STREAM_RESET; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->book_size = sizeof(struct sctp_chunkhdr); - chk->send_size = SCTP_SIZE32(chk->book_size); - chk->book_size_scale = 0; - chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED); - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return; - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - /* setup chunk parameters */ - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - if (stcb->asoc.alternate) { - chk->whoTo = stcb->asoc.alternate; - } else { - chk->whoTo = stcb->asoc.primary_destination; - } - ch = mtod(chk->data, struct sctp_chunkhdr *); - ch->chunk_type = SCTP_STREAM_RESET; - ch->chunk_flags = 0; - ch->chunk_length = htons(chk->book_size); - atomic_add_int(&chk->whoTo->ref_count, 1); - SCTP_BUF_LEN(chk->data) = chk->send_size; - sctp_add_stream_reset_result(chk, ent->seq, response); - /* insert the chunk for sending */ - TAILQ_INSERT_TAIL(&asoc->control_send_queue, - chk, - sctp_next); - asoc->ctrl_queue_cnt++; -} - -void -sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk, - uint32_t resp_seq, uint32_t result, - uint32_t send_una, uint32_t recv_next) -{ - uint16_t len, old_len; - struct sctp_stream_reset_response_tsn *resp; - struct sctp_chunkhdr *ch; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - - /* get to new offset for the param. */ - resp = (struct sctp_stream_reset_response_tsn *)((caddr_t)ch + len); - /* now how long will this param be? */ - len = sizeof(struct sctp_stream_reset_response_tsn); - resp->ph.param_type = htons(SCTP_STR_RESET_RESPONSE); - resp->ph.param_length = htons(len); - resp->response_seq = htonl(resp_seq); - resp->result = htonl(result); - resp->senders_next_tsn = htonl(send_una); - resp->receivers_next_tsn = htonl(recv_next); - - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->book_size = len + old_len; - chk->send_size = SCTP_SIZE32(chk->book_size); - chk->book_size_scale = 0; - SCTP_BUF_LEN(chk->data) = chk->send_size; - return; -} - -static void -sctp_add_an_out_stream(struct sctp_tmit_chunk *chk, - uint32_t seq, - uint16_t adding) -{ - uint16_t len, old_len; - struct sctp_chunkhdr *ch; - struct sctp_stream_reset_add_strm *addstr; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - - /* get to new offset for the param. */ - addstr = (struct sctp_stream_reset_add_strm *)((caddr_t)ch + len); - /* now how long will this param be? */ - len = sizeof(struct sctp_stream_reset_add_strm); - - /* Fill it out. */ - addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_OUT_STREAMS); - addstr->ph.param_length = htons(len); - addstr->request_seq = htonl(seq); - addstr->number_of_streams = htons(adding); - addstr->reserved = 0; - - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->send_size = len + old_len; - chk->book_size = SCTP_SIZE32(chk->send_size); - chk->book_size_scale = 0; - SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); - return; -} - -static void -sctp_add_an_in_stream(struct sctp_tmit_chunk *chk, - uint32_t seq, - uint16_t adding) -{ - uint16_t len, old_len; - struct sctp_chunkhdr *ch; - struct sctp_stream_reset_add_strm *addstr; - - ch = mtod(chk->data, struct sctp_chunkhdr *); - old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); - - /* get to new offset for the param. */ - addstr = (struct sctp_stream_reset_add_strm *)((caddr_t)ch + len); - /* now how long will this param be? */ - len = sizeof(struct sctp_stream_reset_add_strm); - /* Fill it out. */ - addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_IN_STREAMS); - addstr->ph.param_length = htons(len); - addstr->request_seq = htonl(seq); - addstr->number_of_streams = htons(adding); - addstr->reserved = 0; - - /* now fix the chunk length */ - ch->chunk_length = htons(len + old_len); - chk->send_size = len + old_len; - chk->book_size = SCTP_SIZE32(chk->send_size); - chk->book_size_scale = 0; - SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); - return; -} - -int -sctp_send_stream_reset_out_if_possible(struct sctp_tcb *stcb, int so_locked) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - struct sctp_chunkhdr *ch; - uint32_t seq; - - asoc = &stcb->asoc; - asoc->trigger_reset = 0; - if (asoc->stream_reset_outstanding) { - return (EALREADY); - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_STREAM_RESET; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->book_size = sizeof(struct sctp_chunkhdr); - chk->send_size = SCTP_SIZE32(chk->book_size); - chk->book_size_scale = 0; - chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, so_locked); - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - - /* setup chunk parameters */ - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - if (stcb->asoc.alternate) { - chk->whoTo = stcb->asoc.alternate; - } else { - chk->whoTo = stcb->asoc.primary_destination; - } - ch = mtod(chk->data, struct sctp_chunkhdr *); - ch->chunk_type = SCTP_STREAM_RESET; - ch->chunk_flags = 0; - ch->chunk_length = htons(chk->book_size); - atomic_add_int(&chk->whoTo->ref_count, 1); - SCTP_BUF_LEN(chk->data) = chk->send_size; - seq = stcb->asoc.str_reset_seq_out; - if (sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1))) { - seq++; - asoc->stream_reset_outstanding++; - } else { - m_freem(chk->data); - chk->data = NULL; - sctp_free_a_chunk(stcb, chk, so_locked); - return (ENOENT); - } - asoc->str_reset = chk; - /* insert the chunk for sending */ - TAILQ_INSERT_TAIL(&asoc->control_send_queue, - chk, - sctp_next); - asoc->ctrl_queue_cnt++; - - if (stcb->asoc.send_sack) { - sctp_send_sack(stcb, so_locked); - } - sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo); - return (0); -} - -int -sctp_send_str_reset_req(struct sctp_tcb *stcb, - uint16_t number_entries, uint16_t *list, - uint8_t send_in_req, - uint8_t send_tsn_req, - uint8_t add_stream, - uint16_t adding_o, - uint16_t adding_i, uint8_t peer_asked) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - struct sctp_chunkhdr *ch; - int can_send_out_req=0; - uint32_t seq; - - SCTP_TCB_LOCK_ASSERT(stcb); - - asoc = &stcb->asoc; - if (asoc->stream_reset_outstanding) { - /*- - * Already one pending, must get ACK back to clear the flag. - */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY); - return (EBUSY); - } - if ((send_in_req == 0) && (send_tsn_req == 0) && - (add_stream == 0)) { - /* nothing to do */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } - if (send_tsn_req && send_in_req) { - /* error, can't do that */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } else if (send_in_req) { - can_send_out_req = 1; - } - if (number_entries > (MCLBYTES - - SCTP_MIN_OVERHEAD - - sizeof(struct sctp_chunkhdr) - - sizeof(struct sctp_stream_reset_out_request)) / - sizeof(uint16_t)) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - chk->copy_by_ref = 0; - chk->rec.chunk_id.id = SCTP_STREAM_RESET; - chk->rec.chunk_id.can_take_data = 0; - chk->flags = 0; - chk->asoc = &stcb->asoc; - chk->book_size = sizeof(struct sctp_chunkhdr); - chk->send_size = SCTP_SIZE32(chk->book_size); - chk->book_size_scale = 0; - chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (chk->data == NULL) { - sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED); - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - return (ENOMEM); - } - SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - - /* setup chunk parameters */ - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - if (stcb->asoc.alternate) { - chk->whoTo = stcb->asoc.alternate; - } else { - chk->whoTo = stcb->asoc.primary_destination; - } - atomic_add_int(&chk->whoTo->ref_count, 1); - ch = mtod(chk->data, struct sctp_chunkhdr *); - ch->chunk_type = SCTP_STREAM_RESET; - ch->chunk_flags = 0; - ch->chunk_length = htons(chk->book_size); - SCTP_BUF_LEN(chk->data) = chk->send_size; - - seq = stcb->asoc.str_reset_seq_out; - if (can_send_out_req) { - int ret; - - ret = sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1)); - if (ret) { - seq++; - asoc->stream_reset_outstanding++; - } - } - if ((add_stream & 1) && - ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < adding_o)) { - /* Need to allocate more */ - struct sctp_stream_out *oldstream; - struct sctp_stream_queue_pending *sp, *nsp; - int i; -#if defined(SCTP_DETAILED_STR_STATS) - int j; -#endif - - oldstream = stcb->asoc.strmout; - /* get some more */ - SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *, - (stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out), - SCTP_M_STRMO); - if (stcb->asoc.strmout == NULL) { - uint8_t x; - stcb->asoc.strmout = oldstream; - /* Turn off the bit */ - x = add_stream & 0xfe; - add_stream = x; - goto skip_stuff; - } - /* Ok now we proceed with copying the old out stuff and - * initializing the new stuff. - */ - stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, false); - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); - /* FIX ME FIX ME */ - /* This should be a SS_COPY operation FIX ME STREAM SCHEDULER EXPERT */ - stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], &oldstream[i]); - stcb->asoc.strmout[i].chunks_on_queues = oldstream[i].chunks_on_queues; -#if defined(SCTP_DETAILED_STR_STATS) - for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { - stcb->asoc.strmout[i].abandoned_sent[j] = oldstream[i].abandoned_sent[j]; - stcb->asoc.strmout[i].abandoned_unsent[j] = oldstream[i].abandoned_unsent[j]; - } -#else - stcb->asoc.strmout[i].abandoned_sent[0] = oldstream[i].abandoned_sent[0]; - stcb->asoc.strmout[i].abandoned_unsent[0] = oldstream[i].abandoned_unsent[0]; -#endif - stcb->asoc.strmout[i].next_mid_ordered = oldstream[i].next_mid_ordered; - stcb->asoc.strmout[i].next_mid_unordered = oldstream[i].next_mid_unordered; - stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete; - stcb->asoc.strmout[i].sid = i; - stcb->asoc.strmout[i].state = oldstream[i].state; - /* now anything on those queues? */ - TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) { - TAILQ_REMOVE(&oldstream[i].outqueue, sp, next); - TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next); - } - } - /* now the new streams */ - stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); - for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + adding_o); i++) { - TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); - stcb->asoc.strmout[i].chunks_on_queues = 0; -#if defined(SCTP_DETAILED_STR_STATS) - for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { - stcb->asoc.strmout[i].abandoned_sent[j] = 0; - stcb->asoc.strmout[i].abandoned_unsent[j] = 0; - } -#else - stcb->asoc.strmout[i].abandoned_sent[0] = 0; - stcb->asoc.strmout[i].abandoned_unsent[0] = 0; -#endif - stcb->asoc.strmout[i].next_mid_ordered = 0; - stcb->asoc.strmout[i].next_mid_unordered = 0; - stcb->asoc.strmout[i].sid = i; - stcb->asoc.strmout[i].last_msg_incomplete = 0; - stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); - stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED; - } - stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o; - SCTP_FREE(oldstream, SCTP_M_STRMO); - } -skip_stuff: - if ((add_stream & 1) && (adding_o > 0)) { - asoc->strm_pending_add_size = adding_o; - asoc->peer_req_out = peer_asked; - sctp_add_an_out_stream(chk, seq, adding_o); - seq++; - asoc->stream_reset_outstanding++; - } - if ((add_stream & 2) && (adding_i > 0)) { - sctp_add_an_in_stream(chk, seq, adding_i); - seq++; - asoc->stream_reset_outstanding++; - } - if (send_in_req) { - sctp_add_stream_reset_in(chk, number_entries, list, seq); - seq++; - asoc->stream_reset_outstanding++; - } - if (send_tsn_req) { - sctp_add_stream_reset_tsn(chk, seq); - asoc->stream_reset_outstanding++; - } - asoc->str_reset = chk; - /* insert the chunk for sending */ - TAILQ_INSERT_TAIL(&asoc->control_send_queue, - chk, - sctp_next); - asoc->ctrl_queue_cnt++; - if (stcb->asoc.send_sack) { - sctp_send_sack(stcb, SCTP_SO_LOCKED); - } - sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo); - return (0); -} - -void -sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, uint32_t vtag, struct mbuf *cause, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, -#endif - uint32_t vrf_id, uint16_t port) -{ - /* Don't respond to an ABORT with an ABORT. */ - if (sctp_is_there_an_abort_here(m, iphlen, &vtag)) { - if (cause) - sctp_m_freem(cause); - return; - } - sctp_send_resp_msg(src, dst, sh, vtag, SCTP_ABORT_ASSOCIATION, cause, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - return; -} - -void -sctp_send_operr_to(struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, uint32_t vtag, struct mbuf *cause, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, -#endif - uint32_t vrf_id, uint16_t port) -{ - sctp_send_resp_msg(src, dst, sh, vtag, SCTP_OPERATION_ERROR, cause, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - return; -} - -static struct mbuf * -sctp_copy_resume(struct uio *uio, - int max_send_len, -#if defined(__FreeBSD__) || defined(__Userspace__) - int user_marks_eor, -#endif - int *error, - uint32_t *sndout, - struct mbuf **new_tail) -{ -#if defined(__FreeBSD__) || defined(__Userspace__) - struct mbuf *m; - - m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0, - (M_PKTHDR | (user_marks_eor ? M_EOR : 0))); - if (m == NULL) { - /* The only possible error is EFAULT. */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); - *error = EFAULT; - } else { - *sndout = m_length(m, NULL); - *new_tail = m_last(m); - } - return (m); -#else - int left, cancpy, willcpy; - struct mbuf *m, *head; - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - left = (int)min(uio->uio_resid, max_send_len); -#else - left = (int)min(uio_resid(uio), max_send_len); -#endif -#else - left = (int)min(uio->uio_resid, max_send_len); -#endif - /* Always get a header just in case */ - head = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); - if (head == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - *error = ENOBUFS; - return (NULL); - } - cancpy = (int)M_TRAILINGSPACE(head); - willcpy = min(cancpy, left); - *error = uiomove(mtod(head, caddr_t), willcpy, uio); - if (*error != 0) { - sctp_m_freem(head); - return (NULL); - } - *sndout += willcpy; - left -= willcpy; - SCTP_BUF_LEN(head) = willcpy; - m = head; - *new_tail = head; - while (left > 0) { - /* move in user data */ - SCTP_BUF_NEXT(m) = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); - if (SCTP_BUF_NEXT(m) == NULL) { - sctp_m_freem(head); - *new_tail = NULL; - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - *error = ENOBUFS; - return (NULL); - } - m = SCTP_BUF_NEXT(m); - cancpy = (int)M_TRAILINGSPACE(m); - willcpy = min(cancpy, left); - *error = uiomove(mtod(m, caddr_t), willcpy, uio); - if (*error != 0) { - sctp_m_freem(head); - *new_tail = NULL; - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, *error); - return (NULL); - } - SCTP_BUF_LEN(m) = willcpy; - left -= willcpy; - *sndout += willcpy; - *new_tail = m; - if (left == 0) { - SCTP_BUF_NEXT(m) = NULL; - } - } - return (head); -#endif -} - -static int -sctp_copy_one(struct sctp_stream_queue_pending *sp, - struct uio *uio, - int resv_upfront) -{ -#if defined(__FreeBSD__) || defined(__Userspace__) - sp->data = m_uiotombuf(uio, M_WAITOK, sp->length, resv_upfront, 0); - if (sp->data == NULL) { - /* The only possible error is EFAULT. */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); - return (EFAULT); - } - sp->tail_mbuf = m_last(sp->data); - return (0); -#else - int left; - int cancpy, willcpy, error; - struct mbuf *m, *head; - int cpsz = 0; - - /* First one gets a header */ - left = sp->length; - head = m = sctp_get_mbuf_for_msg((left + resv_upfront), 0, M_WAITOK, 0, MT_DATA); - if (m == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - return (ENOBUFS); - } - /*- - * Add this one for m in now, that way if the alloc fails we won't - * have a bad cnt. - */ - SCTP_BUF_RESV_UF(m, resv_upfront); - cancpy = (int)M_TRAILINGSPACE(m); - willcpy = min(cancpy, left); - while (left > 0) { - /* move in user data */ - error = uiomove(mtod(m, caddr_t), willcpy, uio); - if (error) { - sctp_m_freem(head); - return (error); - } - SCTP_BUF_LEN(m) = willcpy; - left -= willcpy; - cpsz += willcpy; - if (left > 0) { - SCTP_BUF_NEXT(m) = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); - if (SCTP_BUF_NEXT(m) == NULL) { - /* - * the head goes back to caller, he can free - * the rest - */ - sctp_m_freem(head); - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - return (ENOBUFS); - } - m = SCTP_BUF_NEXT(m); - cancpy = (int)M_TRAILINGSPACE(m); - willcpy = min(cancpy, left); - } else { - sp->tail_mbuf = m; - SCTP_BUF_NEXT(m) = NULL; - } - } - sp->data = head; - sp->length = cpsz; - return (0); -#endif -} - -static struct sctp_stream_queue_pending * -sctp_copy_it_in(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_nonpad_sndrcvinfo *srcv, - struct uio *uio, - struct sctp_nets *net, - ssize_t max_send_len, - int user_marks_eor, - int *error) - -{ - /*- - * This routine must be very careful in its work. Protocol - * processing is up and running so care must be taken to spl...() - * when you need to do something that may effect the stcb/asoc. The - * sb is locked however. When data is copied the protocol processing - * should be enabled since this is a slower operation... - */ - struct sctp_stream_queue_pending *sp; - int resv_in_first; - - *error = 0; - sctp_alloc_a_strmoq(stcb, sp); - if (sp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); - *error = ENOMEM; - goto out_now; - } - sp->act_flags = 0; - sp->sender_all_done = 0; - sp->sinfo_flags = srcv->sinfo_flags; - sp->timetolive = srcv->sinfo_timetolive; - sp->ppid = srcv->sinfo_ppid; - sp->context = srcv->sinfo_context; - sp->fsn = 0; - (void)SCTP_GETTIME_TIMEVAL(&sp->ts); - sp->sid = srcv->sinfo_stream; -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - sp->length = (uint32_t)min(uio->uio_resid, max_send_len); -#else - sp->length = (uint32_t)min(uio_resid(uio), max_send_len); -#endif -#else - sp->length = (uint32_t)min(uio->uio_resid, max_send_len); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if ((sp->length == (uint32_t)uio->uio_resid) && -#else - if ((sp->length == (uint32_t)uio_resid(uio)) && -#endif -#else - if ((sp->length == (uint32_t)uio->uio_resid) && -#endif - ((user_marks_eor == 0) || - (srcv->sinfo_flags & SCTP_EOF) || - (user_marks_eor && (srcv->sinfo_flags & SCTP_EOR)))) { - sp->msg_is_complete = 1; - } else { - sp->msg_is_complete = 0; - } - sp->sender_all_done = 0; - sp->some_taken = 0; - sp->put_last_out = 0; - resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb); - sp->data = sp->tail_mbuf = NULL; - if (sp->length == 0) { - goto skip_copy; - } - if (srcv->sinfo_keynumber_valid) { - sp->auth_keyid = srcv->sinfo_keynumber; - } else { - sp->auth_keyid = stcb->asoc.authinfo.active_keyid; - } - if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { - sctp_auth_key_acquire(stcb, sp->auth_keyid); - sp->holds_key_ref = 1; - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(SCTP_INP_SO(stcb->sctp_ep), 0); -#endif - *error = sctp_copy_one(sp, uio, resv_in_first); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(SCTP_INP_SO(stcb->sctp_ep), 0); -#endif - skip_copy: - if (*error) { -#if defined(__Userspace__) - SCTP_TCB_LOCK(stcb); -#endif - sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); -#if defined(__Userspace__) - SCTP_TCB_UNLOCK(stcb); -#endif - sp = NULL; - } else { - if (sp->sinfo_flags & SCTP_ADDR_OVER) { - sp->net = net; - atomic_add_int(&sp->net->ref_count, 1); - } else { - sp->net = NULL; - } - sctp_set_prsctp_policy(sp); - } -out_now: - return (sp); -} - -int -sctp_sosend(struct socket *so, - struct sockaddr *addr, - struct uio *uio, - struct mbuf *top, - struct mbuf *control, -#if defined(__APPLE__) && !defined(__Userspace__) - int flags) -#else - int flags, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p) -#elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p) -#else -#if defined(__Userspace__) - /* - * proc is a dummy in __Userspace__ and will not be passed - * to sctp_lower_sosend - */ -#endif - struct proc *p) -#endif -#endif -{ - struct sctp_sndrcvinfo sndrcvninfo; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin; -#endif - struct sockaddr *addr_to_use; -#if defined(__APPLE__) && !defined(__Userspace__) - struct proc *p = current_proc(); -#endif - int error; - bool use_sndinfo; - - if (control != NULL) { - /* process cmsg snd/rcv info (maybe a assoc-id) */ - use_sndinfo = sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control, sizeof(sndrcvninfo)); - } else { - use_sndinfo = false; - } -#if defined(INET) && defined(INET6) - if ((addr != NULL) && (addr->sa_family == AF_INET6)) { - struct sockaddr_in6 *sin6; - -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); - } -#endif - sin6 = (struct sockaddr_in6 *)addr; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin, sin6); - addr_to_use = (struct sockaddr *)&sin; - } else { - addr_to_use = addr; - } - } else { - addr_to_use = addr; - } -#else - addr_to_use = addr; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 1); -#endif - error = sctp_lower_sosend(so, addr_to_use, uio, top, control, flags, -#if defined(__Userspace__) - use_sndinfo ? &sndrcvninfo : NULL); -#else - use_sndinfo ? &sndrcvninfo : NULL, p); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (error); -} - -int -sctp_lower_sosend(struct socket *so, - struct sockaddr *addr, - struct uio *uio, - struct mbuf *top, - struct mbuf *control, - int flags, -#if defined(__Userspace__) - struct sctp_sndrcvinfo *srcv) -#else - struct sctp_sndrcvinfo *srcv, -#if defined(__FreeBSD__) - struct thread *p) -#elif defined(_WIN32) - PKTHREAD p) -#else - struct proc *p) -#endif -#endif -{ - struct sctp_nonpad_sndrcvinfo sndrcvninfo_buf; -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct timeval now; - struct sctp_block_entry be; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb = NULL; - struct sctp_nets *net; - struct sctp_association *asoc; - struct sctp_inpcb *t_inp; - struct sctp_nonpad_sndrcvinfo *sndrcvninfo; - ssize_t sndlen = 0, max_len, local_add_more; - ssize_t local_soresv = 0; - sctp_assoc_t sinfo_assoc_id; - int user_marks_eor; - int nagle_applies = 0; - int error; - int queue_only = 0, queue_only_for_init = 0; - int un_sent; - int now_filled = 0; - unsigned int inqueue_bytes = 0; - uint16_t port; - uint16_t sinfo_flags; - uint16_t sinfo_stream; - bool create_lock_applied = false; - bool free_cnt_applied = false; - bool some_on_control; - bool got_all_of_the_send = false; - bool non_blocking = false; - - error = 0; - net = NULL; - stcb = NULL; - -#if defined(__APPLE__) && !defined(__Userspace__) - sctp_lock_assert(so); -#endif - if ((uio == NULL) && (top == NULL)) { - error = EINVAL; - goto out_unlocked; - } - if (addr != NULL) { - union sctp_sockstore *raddr = (union sctp_sockstore *)addr; - - switch (raddr->sa.sa_family) { -#ifdef INET - case AF_INET: -#ifdef HAVE_SIN_LEN - if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) { - error = EINVAL; - goto out_unlocked; - } -#endif - port = raddr->sin.sin_port; - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SIN6_LEN - if (raddr->sin6.sin6_len != sizeof(struct sockaddr_in6)) { - error = EINVAL; - goto out_unlocked; - } -#endif - port = raddr->sin6.sin6_port; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: -#ifdef HAVE_SCONN_LEN - if (raddr->sconn.sconn_len != sizeof(struct sockaddr_conn)) { - error = EINVAL; - goto out_unlocked; - } -#endif - port = raddr->sconn.sconn_port; - break; -#endif - default: - error = EAFNOSUPPORT; - goto out_unlocked; - } - } else { - port = 0; - } - if (uio != NULL) { -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if (uio->uio_resid < 0) { -#else - if (uio_resid(uio) < 0) { -#endif -#else - if (uio->uio_resid < 0) { -#endif - error = EINVAL; - goto out_unlocked; - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - sndlen = uio->uio_resid; -#else - sndlen = uio_resid(uio); -#endif -#else - sndlen = uio->uio_resid; -#endif - } else { - sndlen = SCTP_HEADER_LEN(top); - } - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n", - (void *)addr, sndlen); - - t_inp = inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - error = EINVAL; - goto out_unlocked; - } - user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); - if ((uio == NULL) && (user_marks_eor != 0)) { - /*- - * We do not support eeor mode for - * sending with mbuf chains (like sendfile). - */ - error = EINVAL; - goto out_unlocked; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - SCTP_IS_LISTENING(inp)) { - /* The listener can NOT send. */ - error = EINVAL; - goto out_unlocked; - } - atomic_add_int(&inp->total_sends, 1); - - if (srcv != NULL) { - sndrcvninfo = (struct sctp_nonpad_sndrcvinfo *)srcv; - sinfo_assoc_id = sndrcvninfo->sinfo_assoc_id; - sinfo_flags = sndrcvninfo->sinfo_flags; - if (INVALID_SINFO_FLAG(sinfo_flags) || - PR_SCTP_INVALID_POLICY(sinfo_flags)) { - error = EINVAL; - goto out_unlocked; - } - if (sinfo_flags != 0) { - SCTP_STAT_INCR(sctps_sends_with_flags); - } - } else { - sndrcvninfo = NULL; - sinfo_flags = inp->def_send.sinfo_flags; - sinfo_assoc_id = inp->def_send.sinfo_assoc_id; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (flags & MSG_EOR) { - sinfo_flags |= SCTP_EOR; - } - if (flags & MSG_EOF) { - sinfo_flags |= SCTP_EOF; - } -#endif - if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) { - error = EINVAL; - goto out_unlocked; - } - SCTP_INP_RLOCK(inp); - if ((sinfo_flags & SCTP_SENDALL) && - (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { - SCTP_INP_RUNLOCK(inp); - error = sctp_sendall(inp, uio, top, sndrcvninfo); - top = NULL; - goto out_unlocked; - } - /* Now we must find the association. */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb != NULL) { - SCTP_TCB_LOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } else if (sinfo_assoc_id > SCTP_ALL_ASSOC) { - stcb = sctp_findasoc_ep_asocid_locked(inp, sinfo_assoc_id, 1); - SCTP_INP_RUNLOCK(inp); - if (stcb != NULL) { - SCTP_TCB_LOCK_ASSERT(stcb); - } - } else if (addr != NULL) { - /*- - * Since we did not use findep we must - * increment it, and if we don't find a tcb - * decrement it. - */ - SCTP_INP_INCR_REF(inp); - SCTP_INP_RUNLOCK(inp); - stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_TCB_LOCK_ASSERT(stcb); - } - } else { - SCTP_INP_RUNLOCK(inp); - } - -#ifdef INVARIANTS - if (stcb != NULL) { - SCTP_TCB_LOCK_ASSERT(stcb); - } -#endif - - if ((stcb == NULL) && (addr != NULL)) { - /* Possible implicit send? */ - SCTP_ASOC_CREATE_LOCK(inp); - create_lock_applied = true; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - error = EINVAL; - goto out_unlocked; - } - if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && - (addr->sa_family == AF_INET6)) { - error = EINVAL; - goto out_unlocked; - } - SCTP_INP_WLOCK(inp); - SCTP_INP_INCR_REF(inp); - SCTP_INP_WUNLOCK(inp); - /* With the lock applied look again */ - stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); -#if defined(INET) || defined(INET6) - if ((stcb == NULL) && (control != NULL) && (port > 0)) { - stcb = sctp_findassociation_cmsgs(&t_inp, port, control, &net, &error); - } -#endif - if (stcb == NULL) { - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_TCB_LOCK_ASSERT(stcb); - SCTP_ASOC_CREATE_UNLOCK(inp); - create_lock_applied = false; - } - if (error != 0) { - goto out_unlocked; - } - if (t_inp != inp) { - error = ENOTCONN; - goto out_unlocked; - } - } - if (stcb == NULL) { - if (addr == NULL) { - error = ENOENT; - goto out_unlocked; - } else { - /* We must go ahead and start the INIT process */ - uint32_t vrf_id; - - if ((sinfo_flags & SCTP_ABORT) || - ((sinfo_flags & SCTP_EOF) && (sndlen == 0))) { - /*- - * User asks to abort a non-existent assoc, - * or EOF a non-existent assoc with no data - */ - error = ENOENT; - goto out_unlocked; - } - /* get an asoc/stcb struct */ - vrf_id = inp->def_vrf_id; - KASSERT(create_lock_applied, ("create_lock_applied is false")); - stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, -#if !defined(__Userspace__) - p, -#else - (struct proc *)NULL, -#endif - SCTP_INITIALIZE_AUTH_PARAMS); - if (stcb == NULL) { - /* error is setup for us in the call. */ - KASSERT(error != 0, ("error is 0 although stcb is NULL")); - goto out_unlocked; - } - SCTP_TCB_LOCK_ASSERT(stcb); - SCTP_ASOC_CREATE_UNLOCK(inp); - create_lock_applied = false; - /* Turn on queue only flag to prevent data from being sent */ - queue_only = 1; - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - if (control != NULL) { - if (sctp_process_cmsgs_for_init(stcb, control, &error)) { - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); - stcb = NULL; - KASSERT(error != 0, - ("error is 0 although sctp_process_cmsgs_for_init() indicated an error")); - goto out_unlocked; - } - } - /* out with the INIT */ - queue_only_for_init = 1; - /*- - * we may want to dig in after this call and adjust the MTU - * value. It defaulted to 1500 (constant) but the ro - * structure may now have an update and thus we may need to - * change it BEFORE we append the message. - */ - } - } - - KASSERT(!create_lock_applied, ("create_lock_applied is true")); - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - - asoc = &stcb->asoc; - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - if (asoc->state & SCTP_STATE_WAS_ABORTED) { - /* XXX: Could also be ECONNABORTED, not enough info. */ - error = ECONNRESET; - } else { - error = ENOTCONN; - } - goto out_unlocked; - } - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - queue_only = 1; - } - /* Keep the stcb from being freed under our feet. */ - atomic_add_int(&asoc->refcnt, 1); - free_cnt_applied = true; - if (sndrcvninfo == NULL) { - /* Use a local copy to have a consistent view. */ - sndrcvninfo_buf = asoc->def_send; - sndrcvninfo = &sndrcvninfo_buf; - sinfo_flags = sndrcvninfo->sinfo_flags; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (flags & MSG_EOR) { - sinfo_flags |= SCTP_EOR; - } - if (flags & MSG_EOF) { - sinfo_flags |= SCTP_EOF; - } -#endif - } - /* Are we aborting? */ - if (sinfo_flags & SCTP_ABORT) { - struct mbuf *mm; - struct sctp_paramhdr *ph; - ssize_t tot_demand, tot_out = 0, max_out; - - SCTP_STAT_INCR(sctps_sends_with_abort); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - /* It has to be up before we abort. */ - error = EINVAL; - goto out_unlocked; - } - /* How big is the user initiated abort? */ - if (top != NULL) { - struct mbuf *cntm; - - if (sndlen != 0) { - for (cntm = top; cntm; cntm = SCTP_BUF_NEXT(cntm)) { - tot_out += SCTP_BUF_LEN(cntm); - } - } - mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); - } else { - /* Must fit in a MTU */ - tot_out = sndlen; - tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); - if (tot_demand > SCTP_DEFAULT_ADD_MORE) { - error = EMSGSIZE; - goto out_unlocked; - } - mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_NOWAIT, 1, MT_DATA); - } - if (mm == NULL) { - error = ENOMEM; - goto out_unlocked; - } - max_out = asoc->smallest_mtu - sizeof(struct sctp_paramhdr); - max_out -= sizeof(struct sctp_abort_msg); - if (tot_out > max_out) { - tot_out = max_out; - } - ph = mtod(mm, struct sctp_paramhdr *); - ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); - ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out)); - ph++; - SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr)); - if (top == NULL) { - SCTP_TCB_UNLOCK(stcb); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 0); -#endif - error = uiomove((caddr_t)ph, (int)tot_out, uio); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 0); -#endif - SCTP_TCB_LOCK(stcb); - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - sctp_m_freem(mm); - if (asoc->state & SCTP_STATE_WAS_ABORTED) { - /* XXX: Could also be ECONNABORTED, not enough info. */ - error = ECONNRESET; - } else { - error = ENOTCONN; - } - goto out_unlocked; - } - if (error != 0) { - /*- - * Here if we can't get his data we - * still abort we just don't get to - * send the users note :-0 - */ - sctp_m_freem(mm); - mm = NULL; - error = 0; - } - } else { - if (sndlen != 0) { - SCTP_BUF_NEXT(mm) = top; - } - } - atomic_subtract_int(&asoc->refcnt, 1); - free_cnt_applied = false; - /* release this lock, otherwise we hang on ourselves */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_abort_an_association(stcb->sctp_ep, stcb, mm, false, SCTP_SO_LOCKED); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - stcb = NULL; - /* In this case top is already chained to mm - * avoid double free, since we free it below if - * top != NULL and driver would free it after sending - * the packet out - */ - if (sndlen != 0) { - top = NULL; - } - goto out_unlocked; - } - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - - if (sinfo_flags & SCTP_ADDR_OVER) { - if (addr != NULL) { - net = sctp_findnet(stcb, addr); - } else { - net = NULL; - } - if ((net == NULL) || - ((port != 0) && (port != stcb->rport))) { - error = EINVAL; - goto out_unlocked; - } - } else { - if (asoc->alternate != NULL) { - net = asoc->alternate; - } else { - net = asoc->primary_destination; - } - } - if (sndlen == 0) { - if (sinfo_flags & SCTP_EOF) { - got_all_of_the_send = true; - goto dataless_eof; - } else { - error = EINVAL; - goto out_unlocked; - } - } - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { - if (sndlen > (ssize_t)asoc->smallest_mtu) { - error = EMSGSIZE; - goto out_unlocked; - } - } - sinfo_stream = sndrcvninfo->sinfo_stream; - /* Is the stream no. valid? */ - if (sinfo_stream >= asoc->streamoutcnt) { - /* Invalid stream number */ - error = EINVAL; - goto out_unlocked; - } - if ((asoc->strmout[sinfo_stream].state != SCTP_STREAM_OPEN) && - (asoc->strmout[sinfo_stream].state != SCTP_STREAM_OPENING)) { - /* - * Can't queue any data while stream reset is underway. - */ - if (asoc->strmout[sinfo_stream].state > SCTP_STREAM_OPEN) { - error = EAGAIN; - } else { - error = EINVAL; - } - goto out_unlocked; - } - atomic_add_int(&stcb->total_sends, 1); -#if defined(__Userspace__) - if (inp->recv_callback != NULL) { - non_blocking = true; - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (SCTP_SO_IS_NBIO(so) || (flags & (MSG_NBIO | MSG_DONTWAIT)) != 0) { -#else - if (SCTP_SO_IS_NBIO(so)) { -#endif - non_blocking = true; - } - if (non_blocking) { - ssize_t amount; - - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - if (user_marks_eor == 0) { - amount = sndlen; - } else { - amount = 1; - } - if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + asoc->sb_send_resv)) || - (asoc->chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { - if ((sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so)) && - (user_marks_eor == 0)) { - error = EMSGSIZE; - } else { - error = EWOULDBLOCK; - } - goto out_unlocked; - } - } - atomic_add_int(&asoc->sb_send_resv, (int)sndlen); - local_soresv = sndlen; - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - - /* Ok, we will attempt a msgsnd :> */ -#if !(defined(_WIN32) || defined(__Userspace__)) - if (p != NULL) { -#if defined(__FreeBSD__) - p->td_ru.ru_msgsnd++; -#else - p->p_stats->p_ru.ru_msgsnd++; -#endif - } -#endif - /* Calculate the maximum we can send */ - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { - max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; - } else { - max_len = 0; - } - /* Unless E_EOR mode is on, we must make a send FIT in one call. */ - if ((user_marks_eor == 0) && - (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { - /* It will NEVER fit. */ - error = EMSGSIZE; - goto out_unlocked; - } - if (user_marks_eor != 0) { - local_add_more = (ssize_t)min(SCTP_SB_LIMIT_SND(so), SCTP_BASE_SYSCTL(sctp_add_more_threshold)); - } else { - /*- - * For non-eeor the whole message must fit in - * the socket send buffer. - */ - local_add_more = sndlen; - } - if (non_blocking) { - goto skip_preblock; - } - if (((max_len <= local_add_more) && ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) || - (max_len == 0) || - ((asoc->chunks_on_out_queue + asoc->stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { - /* No room right now! */ - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - SOCKBUF_LOCK(&so->so_snd); - while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) || - ((asoc->stream_queue_cnt + asoc->chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { - SCTPDBG(SCTP_DEBUG_OUTPUT1,"pre_block limit:%u <(inq:%d + %zd) || (%d+%d > %d)\n", - (unsigned int)SCTP_SB_LIMIT_SND(so), - inqueue_bytes, - local_add_more, - asoc->stream_queue_cnt, - asoc->chunks_on_out_queue, - SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, asoc, sndlen); - } - be.error = 0; -#if !(defined(_WIN32) && !defined(__Userspace__)) - stcb->block_entry = &be; -#endif - SCTP_TCB_UNLOCK(stcb); -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = sbwait(so, SO_SND); -#else - error = sbwait(&so->so_snd); -#endif - if (error == 0) { - if (so->so_error != 0) { - error = so->so_error; - } - if (be.error != 0) { - error = be.error; - } - } - SOCKBUF_UNLOCK(&so->so_snd); - SCTP_TCB_LOCK(stcb); - stcb->block_entry = NULL; - if (error != 0) { - goto out_unlocked; - } - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - if (asoc->state & SCTP_STATE_WAS_ABORTED) { - /* XXX: Could also be ECONNABORTED, not enough info. */ - error = ECONNRESET; - } else { - error = ENOTCONN; - } - goto out_unlocked; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, - asoc, asoc->total_output_queue_size); - } - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - SOCKBUF_LOCK(&so->so_snd); - } - if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { - max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; - } else { - max_len = 0; - } - SOCKBUF_UNLOCK(&so->so_snd); - } - -skip_preblock: - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - -#if defined(__APPLE__) && !defined(__Userspace__) - error = sblock(&so->so_snd, SBLOCKWAIT(flags)); - if (error != 0) { - goto out_unlocked; - } -#endif - /* sndlen covers for mbuf case - * uio_resid covers for the non-mbuf case - * NOTE: uio will be null when top/mbuf is passed - */ - if (top == NULL) { - struct sctp_stream_queue_pending *sp; - struct sctp_stream_out *strm; - uint32_t sndout; - - if ((asoc->stream_locked) && - (asoc->stream_locked_on != sinfo_stream)) { - error = EINVAL; - goto out; - } - strm = &asoc->strmout[sinfo_stream]; - if (strm->last_msg_incomplete == 0) { - do_a_copy_in: - SCTP_TCB_UNLOCK(stcb); - sp = sctp_copy_it_in(stcb, asoc, sndrcvninfo, uio, net, max_len, user_marks_eor, &error); - SCTP_TCB_LOCK(stcb); - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - if (asoc->state & SCTP_STATE_WAS_ABORTED) { - /* XXX: Could also be ECONNABORTED, not enough info. */ - error = ECONNRESET; - } else { - error = ENOTCONN; - } - goto out; - } - if (error != 0) { - goto out; - } - /* - * Reject the sending of a new user message, if the - * association is about to be shut down. - */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || - (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { - if (sp->data != 0) { - sctp_m_freem(sp->data); - sp->data = NULL; - sp->tail_mbuf = NULL; - sp->length = 0; - } - if (sp->net != NULL) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); - error = EPIPE; - goto out_unlocked; - } - /* The out streams might be reallocated. */ - strm = &asoc->strmout[sinfo_stream]; - if (sp->msg_is_complete) { - strm->last_msg_incomplete = 0; - asoc->stream_locked = 0; - } else { - /* Just got locked to this guy in - * case of an interrupt. - */ - strm->last_msg_incomplete = 1; - if (asoc->idata_supported == 0) { - asoc->stream_locked = 1; - asoc->stream_locked_on = sinfo_stream; - } - sp->sender_all_done = 0; - } - sctp_snd_sb_alloc(stcb, sp->length); - atomic_add_int(&asoc->stream_queue_cnt, 1); - if (sinfo_flags & SCTP_UNORDERED) { - SCTP_STAT_INCR(sctps_sends_with_unord); - } - sp->processing = 1; - TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); - asoc->ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp); - } else { - sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); - if (sp == NULL) { - /* ???? Huh ??? last msg is gone */ -#ifdef INVARIANTS - panic("Warning: Last msg marked incomplete, yet nothing left?"); -#else - SCTP_PRINTF("Warning: Last msg marked incomplete, yet nothing left?\n"); - strm->last_msg_incomplete = 0; -#endif - goto do_a_copy_in; - } - if (sp->processing != 0) { - error = EINVAL; - goto out; - } else { - sp->processing = 1; - } - } - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - while (uio->uio_resid > 0) { -#else - while (uio_resid(uio) > 0) { -#endif -#else - while (uio->uio_resid > 0) { -#endif - /* How much room do we have? */ - struct mbuf *new_tail, *mm; - - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { - max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; - } else { - max_len = 0; - } - if ((max_len > (ssize_t)SCTP_BASE_SYSCTL(sctp_add_more_threshold)) || - ((max_len > 0 ) && (SCTP_SB_LIMIT_SND(so) < SCTP_BASE_SYSCTL(sctp_add_more_threshold))) || -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - (uio->uio_resid <= max_len)) { -#else - (uio_resid(uio) <= max_len)) { -#endif -#else - (uio->uio_resid <= max_len)) { -#endif - SCTP_TCB_UNLOCK(stcb); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 0); -#endif - sndout = 0; - new_tail = NULL; -#if defined(__FreeBSD__) || defined(__Userspace__) - mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail); -#else - mm = sctp_copy_resume(uio, (int)max_len, &error, &sndout, &new_tail); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 0); -#endif - SCTP_TCB_LOCK(stcb); - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - /* We need to get out. - * Peer probably aborted. - */ - sctp_m_freem(mm); - if (asoc->state & SCTP_STATE_WAS_ABORTED) { - /* XXX: Could also be ECONNABORTED, not enough info. */ - error = ECONNRESET; - } else { - error = ENOTCONN; - } - goto out; - } - if ((mm == NULL) || (error != 0)) { - if (mm != NULL) { - sctp_m_freem(mm); - } - if (sp != NULL) { - sp->processing = 0; - } - goto out; - } - /* Update the mbuf and count */ - if (sp->tail_mbuf != NULL) { - /* Tack it to the end. */ - SCTP_BUF_NEXT(sp->tail_mbuf) = mm; - } else { - /* A stolen mbuf. */ - sp->data = mm; - } - sp->tail_mbuf = new_tail; - sctp_snd_sb_alloc(stcb, sndout); - atomic_add_int(&sp->length, sndout); - if (sinfo_flags & SCTP_SACK_IMMEDIATELY) { - sp->sinfo_flags |= SCTP_SACK_IMMEDIATELY; - } - - /* Did we reach EOR? */ -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if ((uio->uio_resid == 0) && -#else - if ((uio_resid(uio) == 0) && -#endif -#else - if ((uio->uio_resid == 0) && -#endif - ((user_marks_eor == 0) || - (sinfo_flags & SCTP_EOF) || - (user_marks_eor && (sinfo_flags & SCTP_EOR)))) { - sp->msg_is_complete = 1; - } else { - sp->msg_is_complete = 0; - } - } - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if (uio->uio_resid == 0) { -#else - if (uio_resid(uio) == 0) { -#endif -#else - if (uio->uio_resid == 0) { -#endif - /* got it all? */ - continue; - } - /* PR-SCTP? */ - if ((asoc->prsctp_supported) && (asoc->sent_queue_cnt_removeable > 0)) { - /* This is ugly but we must assure locking order */ - sctp_prune_prsctp(stcb, asoc, sndrcvninfo, (int)sndlen); - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) - max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; - else - max_len = 0; - if (max_len > 0) { - continue; - } - } - /* wait for space now */ - if (non_blocking) { - /* Non-blocking io in place out */ - if (sp != NULL) { - sp->processing = 0; - } - goto skip_out_eof; - } - /* What about the INIT, send it maybe */ - if (queue_only_for_init) { - if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - /* a collision took us forward? */ - queue_only = 0; - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - queue_only = 1; - } - } - if ((net->flight_size > net->cwnd) && - (asoc->sctp_cmt_on_off == 0)) { - SCTP_STAT_INCR(sctps_send_cwnd_avoid); - queue_only = 1; - } else if (asoc->ifp_had_enobuf) { - SCTP_STAT_INCR(sctps_ifnomemqueued); - if (net->flight_size > (2 * net->mtu)) { - queue_only = 1; - } - asoc->ifp_had_enobuf = 0; - } - un_sent = asoc->total_output_queue_size - asoc->total_flight; - if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && - (asoc->total_flight > 0) && - (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && - (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) { - /*- - * Ok, Nagle is set on and we have data outstanding. - * Don't send anything and let SACKs drive out the - * data unless we have a "full" segment to send. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { - sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED); - } - SCTP_STAT_INCR(sctps_naglequeued); - nagle_applies = 1; - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { - if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) - sctp_log_nagle_event(stcb, SCTP_NAGLE_SKIPPED); - } - SCTP_STAT_INCR(sctps_naglesent); - nagle_applies = 0; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only, - nagle_applies, un_sent); - sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size, - asoc->total_flight, - asoc->chunks_on_out_queue, asoc->total_flight_count); - } - if (queue_only_for_init) { - queue_only_for_init = 0; - } - if ((queue_only == 0) && (nagle_applies == 0)) { - /*- - * need to start chunk output - * before blocking.. note that if - * a lock is already applied, then - * the input via the net is happening - * and I don't need to start output :-D - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_chunk_output(inp, stcb, - SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - } - /*- - * This is a bit strange, but I think it will - * work. The total_output_queue_size is locked and - * protected by the TCB_LOCK, which we just released. - * There is a race that can occur between releasing it - * above, and me getting the socket lock, where sacks - * come in but we have not put the SB_WAIT on the - * so_snd buffer to get the wakeup. After the LOCK - * is applied the sack_processing will also need to - * LOCK the so->so_snd to do the actual sowwakeup(). So - * once we have the socket buffer lock if we recheck the - * size we KNOW we will get to sleep safely with the - * wakeup flag in place. - */ - inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - SOCKBUF_LOCK(&so->so_snd); - if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes + - min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio->uio_resid); -#else - sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio_resid(uio)); -#endif -#else - sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio->uio_resid); -#endif - } - be.error = 0; -#if !(defined(_WIN32) && !defined(__Userspace__)) - stcb->block_entry = &be; -#endif - SCTP_TCB_UNLOCK(stcb); -#if defined(__APPLE__) && !defined(__Userspace__) - sbunlock(&so->so_snd, 1); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = sbwait(so, SO_SND); -#else - error = sbwait(&so->so_snd); -#endif - if (error == 0) { - if (so->so_error != 0) - error = so->so_error; - if (be.error != 0) { - error = be.error; - } - } - SOCKBUF_UNLOCK(&so->so_snd); - SCTP_TCB_LOCK(stcb); - stcb->block_entry = NULL; - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - if (asoc->state & SCTP_STATE_WAS_ABORTED) { - /* XXX: Could also be ECONNABORTED, not enough info. */ - error = ECONNRESET; - } else { - error = ENOTCONN; - } - goto out_unlocked; - } - if (error != 0) { - if (sp != NULL) { - sp->processing = 0; - } - goto out_unlocked; - } -#if defined(__APPLE__) && !defined(__Userspace__) - error = sblock(&so->so_snd, SBLOCKWAIT(flags)); - if (error != 0) { - goto out_unlocked; - } -#endif - } else { - SOCKBUF_UNLOCK(&so->so_snd); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, - asoc, asoc->total_output_queue_size); - } - } - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - - /* The out streams might be reallocated. */ - strm = &asoc->strmout[sinfo_stream]; - if (sp != NULL) { - if (sp->msg_is_complete == 0) { - strm->last_msg_incomplete = 1; - if (asoc->idata_supported == 0) { - asoc->stream_locked = 1; - asoc->stream_locked_on = sinfo_stream; - } - } else { - sp->sender_all_done = 1; - strm->last_msg_incomplete = 0; - asoc->stream_locked = 0; - } - sp->processing = 0; - } else { - SCTP_PRINTF("Huh no sp TSNH?\n"); - strm->last_msg_incomplete = 0; - asoc->stream_locked = 0; - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if (uio->uio_resid == 0) { -#else - if (uio_resid(uio) == 0) { -#endif -#else - if (uio->uio_resid == 0) { -#endif - got_all_of_the_send = true; - } - } else { - error = sctp_msg_append(stcb, net, top, sndrcvninfo); - top = NULL; - if ((sinfo_flags & SCTP_EOF) != 0) { - got_all_of_the_send = true; - } - } - if (error != 0) { - goto out; - } - -dataless_eof: - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - - /* EOF thing ? */ - if ((sinfo_flags & SCTP_EOF) && got_all_of_the_send) { - SCTP_STAT_INCR(sctps_sends_with_eof); - error = 0; - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) { - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - goto abort_anyway; - } - /* there is nothing queued to send, so I'm done... */ - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - struct sctp_nets *netp; - - /* only send SHUTDOWN the first time through */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (asoc->alternate != NULL) { - netp = asoc->alternate; - } else { - netp = asoc->primary_destination; - } - sctp_send_shutdown(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - NULL); - } - } else { - /*- - * we still got (or just got) data to send, so set - * SHUTDOWN_PENDING - */ - /*- - * XXX sockets draft says that SCTP_EOF should be - * sent with no data. currently, we will allow user - * data to be sent first and move to - * SHUTDOWN-PENDING - */ - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - abort_anyway: - if (free_cnt_applied) { - atomic_subtract_int(&asoc->refcnt, 1); - free_cnt_applied = false; - } - SCTP_SNPRINTF(msg, sizeof(msg), - "%s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_abort_an_association(stcb->sctp_ep, stcb, - op_err, false, SCTP_SO_LOCKED); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - stcb = NULL; - error = ECONNABORTED; - goto out; - } - sctp_feature_off(inp, SCTP_PCB_FLAGS_NODELAY); - } - } - } - -skip_out_eof: - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - - some_on_control = !TAILQ_EMPTY(&asoc->control_send_queue); - if (queue_only_for_init) { - if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - /* a collision took us forward? */ - queue_only = 0; - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - queue_only = 1; - } - } - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - - if ((net->flight_size > net->cwnd) && - (asoc->sctp_cmt_on_off == 0)) { - SCTP_STAT_INCR(sctps_send_cwnd_avoid); - queue_only = 1; - } else if (asoc->ifp_had_enobuf) { - SCTP_STAT_INCR(sctps_ifnomemqueued); - if (net->flight_size > (2 * net->mtu)) { - queue_only = 1; - } - asoc->ifp_had_enobuf = 0; - } - un_sent = asoc->total_output_queue_size - asoc->total_flight; - if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && - (asoc->total_flight > 0) && - (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && - (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) { - /*- - * Ok, Nagle is set on and we have data outstanding. - * Don't send anything and let SACKs drive out the - * data unless wen have a "full" segment to send. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { - sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED); - } - SCTP_STAT_INCR(sctps_naglequeued); - nagle_applies = 1; - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { - if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) - sctp_log_nagle_event(stcb, SCTP_NAGLE_SKIPPED); - } - SCTP_STAT_INCR(sctps_naglesent); - nagle_applies = 0; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only, - nagle_applies, un_sent); - sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size, - asoc->total_flight, - asoc->chunks_on_out_queue, asoc->total_flight_count); - } - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - if ((queue_only == 0) && (nagle_applies == 0) && (asoc->peers_rwnd && un_sent)) { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } else if ((queue_only == 0) && - (asoc->peers_rwnd == 0) && - (asoc->total_flight == 0)) { - /* We get to have a probe outstanding */ - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } else if (some_on_control) { - int num_out, reason; - - /* Here we do control only */ - (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, - &reason, 1, 1, &now, &now_filled, - sctp_get_frag_point(stcb), - SCTP_SO_LOCKED); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n", - queue_only, asoc->peers_rwnd, un_sent, - asoc->total_flight, asoc->chunks_on_out_queue, - asoc->total_output_queue_size, error); - - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); - KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, - ("Association was aborted")); - -out: -#if defined(__APPLE__) && !defined(__Userspace__) - sbunlock(&so->so_snd, 1); -#endif -out_unlocked: - if (create_lock_applied) { - SCTP_ASOC_CREATE_UNLOCK(inp); - } - if (stcb != NULL) { - if (local_soresv) { - atomic_subtract_int(&asoc->sb_send_resv, (int)sndlen); - } - if (free_cnt_applied) { - atomic_subtract_int(&asoc->refcnt, 1); - } - SCTP_TCB_UNLOCK(stcb); - } - if (top != NULL) { - sctp_m_freem(top); - } - if (control != NULL) { - sctp_m_freem(control); - } - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error); - return (error); -} - -/* - * generate an AUTHentication chunk, if required - */ -struct mbuf * -sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end, - struct sctp_auth_chunk **auth_ret, uint32_t * offset, - struct sctp_tcb *stcb, uint8_t chunk) -{ - struct mbuf *m_auth; - struct sctp_auth_chunk *auth; - int chunk_len; - struct mbuf *cn; - - if ((m_end == NULL) || (auth_ret == NULL) || (offset == NULL) || - (stcb == NULL)) - return (m); - - if (stcb->asoc.auth_supported == 0) { - return (m); - } - /* does the requested chunk require auth? */ - if (!sctp_auth_is_required_chunk(chunk, stcb->asoc.peer_auth_chunks)) { - return (m); - } - m_auth = sctp_get_mbuf_for_msg(sizeof(*auth), 0, M_NOWAIT, 1, MT_HEADER); - if (m_auth == NULL) { - /* no mbuf's */ - return (m); - } - /* reserve some space if this will be the first mbuf */ - if (m == NULL) - SCTP_BUF_RESV_UF(m_auth, SCTP_MIN_OVERHEAD); - /* fill in the AUTH chunk details */ - auth = mtod(m_auth, struct sctp_auth_chunk *); - memset(auth, 0, sizeof(*auth)); - auth->ch.chunk_type = SCTP_AUTHENTICATION; - auth->ch.chunk_flags = 0; - chunk_len = sizeof(*auth) + - sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id); - auth->ch.chunk_length = htons(chunk_len); - auth->hmac_id = htons(stcb->asoc.peer_hmac_id); - /* key id and hmac digest will be computed and filled in upon send */ - - /* save the offset where the auth was inserted into the chain */ - *offset = 0; - for (cn = m; cn; cn = SCTP_BUF_NEXT(cn)) { - *offset += SCTP_BUF_LEN(cn); - } - - /* update length and return pointer to the auth chunk */ - SCTP_BUF_LEN(m_auth) = chunk_len; - m = sctp_copy_mbufchain(m_auth, m, m_end, 1, chunk_len, 0); - if (auth_ret != NULL) - *auth_ret = auth; - - return (m); -} - -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) -#ifdef INET6 -int -sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro) -{ - struct nd_prefix *pfx = NULL; - struct nd_pfxrouter *pfxrtr = NULL; - struct sockaddr_in6 gw6; - -#if defined(__FreeBSD__) - if (ro == NULL || ro->ro_nh == NULL || src6->sin6_family != AF_INET6) -#else - if (ro == NULL || ro->ro_rt == NULL || src6->sin6_family != AF_INET6) -#endif - return (0); - - /* get prefix entry of address */ -#if defined(__FreeBSD__) - ND6_RLOCK(); -#endif - LIST_FOREACH(pfx, &MODULE_GLOBAL(nd_prefix), ndpr_entry) { - if (pfx->ndpr_stateflags & NDPRF_DETACHED) - continue; - if (IN6_ARE_MASKED_ADDR_EQUAL(&pfx->ndpr_prefix.sin6_addr, - &src6->sin6_addr, &pfx->ndpr_mask)) - break; - } - /* no prefix entry in the prefix list */ - if (pfx == NULL) { -#if defined(__FreeBSD__) - ND6_RUNLOCK(); -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefix entry for "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6); - return (0); - } - - SCTPDBG(SCTP_DEBUG_OUTPUT2, "v6src_match_nexthop(), Prefix entry is "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6); - - /* search installed gateway from prefix entry */ - LIST_FOREACH(pfxrtr, &pfx->ndpr_advrtrs, pfr_entry) { - memset(&gw6, 0, sizeof(struct sockaddr_in6)); - gw6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - gw6.sin6_len = sizeof(struct sockaddr_in6); -#endif - memcpy(&gw6.sin6_addr, &pfxrtr->router->rtaddr, - sizeof(struct in6_addr)); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "prefix router is "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&gw6); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "installed router is "); -#if defined(__FreeBSD__) - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ro->ro_nh->gw_sa); -#else - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway); -#endif -#if defined(__FreeBSD__) - if (sctp_cmpaddr((struct sockaddr *)&gw6, &ro->ro_nh->gw_sa)) { - ND6_RUNLOCK(); -#else - if (sctp_cmpaddr((struct sockaddr *)&gw6, ro->ro_rt->rt_gateway)) { -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is installed\n"); - return (1); - } - } -#if defined(__FreeBSD__) - ND6_RUNLOCK(); -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is not installed\n"); - return (0); -} -#endif - -int -sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro) -{ -#ifdef INET - struct sockaddr_in *sin, *mask; - struct ifaddr *ifa; - struct in_addr srcnetaddr, gwnetaddr; - -#if defined(__FreeBSD__) - if (ro == NULL || ro->ro_nh == NULL || -#else - if (ro == NULL || ro->ro_rt == NULL || -#endif - sifa->address.sa.sa_family != AF_INET) { - return (0); - } - ifa = (struct ifaddr *)sifa->ifa; - mask = (struct sockaddr_in *)(ifa->ifa_netmask); - sin = &sifa->address.sin; - srcnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); - SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: src address is "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa); - SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", srcnetaddr.s_addr); - -#if defined(__FreeBSD__) - sin = &ro->ro_nh->gw4_sa; -#else - sin = (struct sockaddr_in *)ro->ro_rt->rt_gateway; -#endif - gwnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); - SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: nexthop is "); -#if defined(__FreeBSD__) - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ro->ro_nh->gw_sa); -#else - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway); -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", gwnetaddr.s_addr); - if (srcnetaddr.s_addr == gwnetaddr.s_addr) { - return (1); - } -#endif - return (0); -} -#elif defined(__Userspace__) -/* TODO __Userspace__ versions of sctp_vXsrc_match_nexthop(). */ -int -sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro) -{ - return (0); -} -int -sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro) -{ - return (0); -} - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.h deleted file mode 100644 index 56858d88..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_output.h +++ /dev/null @@ -1,240 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_OUTPUT_H_ -#define _NETINET_SCTP_OUTPUT_H_ - -#include - -#if defined(_KERNEL) || defined(__Userspace__) - -struct mbuf * -sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_scoping *scope, - struct mbuf *m_at, - int cnt_inits_to, - uint16_t *padding_len, uint16_t *chunk_len); - -int sctp_is_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); - -int -sctp_is_address_in_scope(struct sctp_ifa *ifa, - struct sctp_scoping *scope, - int do_update); - -int -sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa); - -struct sctp_ifa * -sctp_source_address_selection(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - sctp_route_t *ro, struct sctp_nets *net, - int non_asoc_addr_ok, uint32_t vrf_id); - -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) -int sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro); - -int sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro); -#endif - -void sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int); - -void -sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *, struct mbuf *, - int, int, - struct sockaddr *, struct sockaddr *, - struct sctphdr *, struct sctp_init_chunk *, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, -#endif - uint32_t, uint16_t); - -struct mbuf * -sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *, - struct sctp_chunkhdr *, int *, int *); -void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *); - -int -sctp_send_cookie_echo(struct mbuf *, int, int, struct sctp_tcb *, - struct sctp_nets *); - -void sctp_send_cookie_ack(struct sctp_tcb *); - -void -sctp_send_heartbeat_ack(struct sctp_tcb *, struct mbuf *, int, int, - struct sctp_nets *); - -void -sctp_remove_from_wheel(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_stream_out *strq, int holds_lock); - -void sctp_send_shutdown(struct sctp_tcb *, struct sctp_nets *); - -void sctp_send_shutdown_ack(struct sctp_tcb *, struct sctp_nets *); - -void sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *, int); - -void sctp_send_shutdown_complete2(struct sockaddr *, struct sockaddr *, - struct sctphdr *, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, uint16_t, -#endif - uint32_t, uint16_t); - -void sctp_send_asconf(struct sctp_tcb *, struct sctp_nets *, int addr_locked); - -void sctp_send_asconf_ack(struct sctp_tcb *); - -uint32_t sctp_get_frag_point(struct sctp_tcb *); - -void sctp_toss_old_cookies(struct sctp_tcb *, struct sctp_association *); - -void sctp_toss_old_asconf(struct sctp_tcb *); - -void sctp_fix_ecn_echo(struct sctp_association *); - -void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net); - -#define SCTP_DATA_CHUNK_OVERHEAD(stcb) ((stcb)->asoc.idata_supported ? \ - sizeof(struct sctp_idata_chunk) : \ - sizeof(struct sctp_data_chunk)) - -#if defined(__FreeBSD__) && !defined(__Userspace__) -int -sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *, - struct mbuf *, struct thread *, int); -#elif defined(_WIN32) && !defined(__Userspace__) -sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *, - struct mbuf *, PKTHREAD, int); -#else -#if defined(__Userspace__) -/* sctp_output is called bu sctp_sendm. Not using sctp_sendm for __Userspace__ */ -#endif -int -sctp_output(struct sctp_inpcb *, - struct mbuf *, - struct sockaddr *, - struct mbuf *, - struct proc *, int); -#endif - -void sctp_chunk_output(struct sctp_inpcb *, struct sctp_tcb *, int, int); - -void sctp_send_abort_tcb(struct sctp_tcb *, struct mbuf *, int); - -void send_forward_tsn(struct sctp_tcb *, struct sctp_association *); - -void sctp_send_sack(struct sctp_tcb *, int); - -void sctp_send_hb(struct sctp_tcb *, struct sctp_nets *, int); - -void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t); - -void -sctp_send_packet_dropped(struct sctp_tcb *, struct sctp_nets *, struct mbuf *, - int, int, int); - -void sctp_send_cwr(struct sctp_tcb *, struct sctp_nets *, uint32_t, uint8_t); - -void -sctp_add_stream_reset_result(struct sctp_tmit_chunk *, uint32_t, uint32_t); - -void -sctp_send_deferred_reset_response(struct sctp_tcb *, - struct sctp_stream_reset_list *, - int); - -void -sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *, - uint32_t, uint32_t, uint32_t, uint32_t); -int -sctp_send_stream_reset_out_if_possible(struct sctp_tcb *, int); - -int -sctp_send_str_reset_req(struct sctp_tcb *, uint16_t , uint16_t *, - uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, uint8_t); - -void -sctp_send_abort(struct mbuf *, int, struct sockaddr *, struct sockaddr *, - struct sctphdr *, uint32_t, struct mbuf *, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, uint16_t, -#endif - uint32_t, uint16_t); - -void -sctp_send_operr_to(struct sockaddr *, struct sockaddr *, - struct sctphdr *, uint32_t, struct mbuf *, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, uint16_t, -#endif - uint32_t, uint16_t); - -#endif /* _KERNEL || __Userspace__ */ - -#if defined(_KERNEL) || defined(__Userspace__) -int -sctp_sosend(struct socket *so, - struct sockaddr *addr, - struct uio *uio, - struct mbuf *top, - struct mbuf *control, -#if defined(__APPLE__) && !defined(__Userspace__) - int flags -#else - int flags, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p -#elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p -#else -#if defined(__Userspace__) - /* proc is a dummy in __Userspace__ and will not be passed to sctp_lower_sosend */ -#endif - struct proc *p -#endif -#endif -); - -#endif -#endif - diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.c deleted file mode 100644 index 225090a0..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.c +++ /dev/null @@ -1,8136 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(INET) || defined(INET6) -#if !defined(_WIN32) -#include -#endif -#endif -#ifdef INET6 -#if defined(__Userspace__) -#include "user_ip6_var.h" -#else -#include -#endif -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#include -#include -#endif -#if defined(__Userspace__) -#include -#include -#if !defined(_WIN32) -#include -#endif -#endif - -#if !defined(__FreeBSD__) || defined(__Userspace__) -struct sctp_base_info system_base_info; - -#endif -/* FIX: we don't handle multiple link local scopes */ -/* "scopeless" replacement IN6_ARE_ADDR_EQUAL */ -#ifdef INET6 -int -SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b) -{ -#ifdef SCTP_EMBEDDED_V6_SCOPE -#if defined(__APPLE__) && !defined(__Userspace__) - struct in6_addr tmp_a, tmp_b; - - tmp_a = a->sin6_addr; -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - if (in6_embedscope(&tmp_a, a, NULL, NULL) != 0) { -#else - if (in6_embedscope(&tmp_a, a, NULL, NULL, NULL) != 0) { -#endif - return (0); - } - tmp_b = b->sin6_addr; -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - if (in6_embedscope(&tmp_b, b, NULL, NULL) != 0) { -#else - if (in6_embedscope(&tmp_b, b, NULL, NULL, NULL) != 0) { -#endif - return (0); - } - return (IN6_ARE_ADDR_EQUAL(&tmp_a, &tmp_b)); -#elif defined(SCTP_KAME) - struct sockaddr_in6 tmp_a, tmp_b; - - memcpy(&tmp_a, a, sizeof(struct sockaddr_in6)); - if (sa6_embedscope(&tmp_a, MODULE_GLOBAL(ip6_use_defzone)) != 0) { - return (0); - } - memcpy(&tmp_b, b, sizeof(struct sockaddr_in6)); - if (sa6_embedscope(&tmp_b, MODULE_GLOBAL(ip6_use_defzone)) != 0) { - return (0); - } - return (IN6_ARE_ADDR_EQUAL(&tmp_a.sin6_addr, &tmp_b.sin6_addr)); -#else - struct in6_addr tmp_a, tmp_b; - - tmp_a = a->sin6_addr; - if (in6_embedscope(&tmp_a, a) != 0) { - return (0); - } - tmp_b = b->sin6_addr; - if (in6_embedscope(&tmp_b, b) != 0) { - return (0); - } - return (IN6_ARE_ADDR_EQUAL(&tmp_a, &tmp_b)); -#endif -#else - return (IN6_ARE_ADDR_EQUAL(&(a->sin6_addr), &(b->sin6_addr))); -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -} -#endif - -void -sctp_fill_pcbinfo(struct sctp_pcbinfo *spcb) -{ - /* - * We really don't need to lock this, but I will just because it - * does not hurt. - */ - SCTP_INP_INFO_RLOCK(); - spcb->ep_count = SCTP_BASE_INFO(ipi_count_ep); - spcb->asoc_count = SCTP_BASE_INFO(ipi_count_asoc); - spcb->laddr_count = SCTP_BASE_INFO(ipi_count_laddr); - spcb->raddr_count = SCTP_BASE_INFO(ipi_count_raddr); - spcb->chk_count = SCTP_BASE_INFO(ipi_count_chunk); - spcb->readq_count = SCTP_BASE_INFO(ipi_count_readq); - spcb->stream_oque = SCTP_BASE_INFO(ipi_count_strmoq); - spcb->free_chunks = SCTP_BASE_INFO(ipi_free_chunks); - SCTP_INP_INFO_RUNLOCK(); -} - -/*- - * Addresses are added to VRF's (Virtual Router's). For BSD we - * have only the default VRF 0. We maintain a hash list of - * VRF's. Each VRF has its own list of sctp_ifn's. Each of - * these has a list of addresses. When we add a new address - * to a VRF we lookup the ifn/ifn_index, if the ifn does - * not exist we create it and add it to the list of IFN's - * within the VRF. Once we have the sctp_ifn, we add the - * address to the list. So we look something like: - * - * hash-vrf-table - * vrf-> ifn-> ifn -> ifn - * vrf | - * ... +--ifa-> ifa -> ifa - * vrf - * - * We keep these separate lists since the SCTP subsystem will - * point to these from its source address selection nets structure. - * When an address is deleted it does not happen right away on - * the SCTP side, it gets scheduled. What we do when a - * delete happens is immediately remove the address from - * the master list and decrement the refcount. As our - * addip iterator works through and frees the src address - * selection pointing to the sctp_ifa, eventually the refcount - * will reach 0 and we will delete it. Note that it is assumed - * that any locking on system level ifn/ifa is done at the - * caller of these functions and these routines will only - * lock the SCTP structures as they add or delete things. - * - * Other notes on VRF concepts. - * - An endpoint can be in multiple VRF's - * - An association lives within a VRF and only one VRF. - * - Any incoming packet we can deduce the VRF for by - * looking at the mbuf/pak inbound (for BSD its VRF=0 :D) - * - Any downward send call or connect call must supply the - * VRF via ancillary data or via some sort of set default - * VRF socket option call (again for BSD no brainer since - * the VRF is always 0). - * - An endpoint may add multiple VRF's to it. - * - Listening sockets can accept associations in any - * of the VRF's they are in but the assoc will end up - * in only one VRF (gotten from the packet or connect/send). - * - */ - -struct sctp_vrf * -sctp_allocate_vrf(int vrf_id) -{ - struct sctp_vrf *vrf = NULL; - struct sctp_vrflist *bucket; - - /* First allocate the VRF structure */ - vrf = sctp_find_vrf(vrf_id); - if (vrf) { - /* Already allocated */ - return (vrf); - } - SCTP_MALLOC(vrf, struct sctp_vrf *, sizeof(struct sctp_vrf), - SCTP_M_VRF); - if (vrf == NULL) { - /* No memory */ -#ifdef INVARIANTS - panic("No memory for VRF:%d", vrf_id); -#endif - return (NULL); - } - /* setup the VRF */ - memset(vrf, 0, sizeof(struct sctp_vrf)); - vrf->vrf_id = vrf_id; - LIST_INIT(&vrf->ifnlist); - vrf->total_ifa_count = 0; - vrf->refcount = 0; - /* now also setup table ids */ - SCTP_INIT_VRF_TABLEID(vrf); - /* Init the HASH of addresses */ - vrf->vrf_addr_hash = SCTP_HASH_INIT(SCTP_VRF_ADDR_HASH_SIZE, - &vrf->vrf_addr_hashmark); - if (vrf->vrf_addr_hash == NULL) { - /* No memory */ -#ifdef INVARIANTS - panic("No memory for VRF:%d", vrf_id); -#endif - SCTP_FREE(vrf, SCTP_M_VRF); - return (NULL); - } - - /* Add it to the hash table */ - bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(vrf_id & SCTP_BASE_INFO(hashvrfmark))]; - LIST_INSERT_HEAD(bucket, vrf, next_vrf); - atomic_add_int(&SCTP_BASE_INFO(ipi_count_vrfs), 1); - return (vrf); -} - -struct sctp_ifn * -sctp_find_ifn(void *ifn, uint32_t ifn_index) -{ - struct sctp_ifn *sctp_ifnp; - struct sctp_ifnlist *hash_ifn_head; - - /* We assume the lock is held for the addresses - * if that's wrong problems could occur :-) - */ - SCTP_IPI_ADDR_LOCK_ASSERT(); - hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))]; - LIST_FOREACH(sctp_ifnp, hash_ifn_head, next_bucket) { - if (sctp_ifnp->ifn_index == ifn_index) { - return (sctp_ifnp); - } - if (sctp_ifnp->ifn_p && ifn && (sctp_ifnp->ifn_p == ifn)) { - return (sctp_ifnp); - } - } - return (NULL); -} - -struct sctp_vrf * -sctp_find_vrf(uint32_t vrf_id) -{ - struct sctp_vrflist *bucket; - struct sctp_vrf *liste; - - bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(vrf_id & SCTP_BASE_INFO(hashvrfmark))]; - LIST_FOREACH(liste, bucket, next_vrf) { - if (vrf_id == liste->vrf_id) { - return (liste); - } - } - return (NULL); -} - -void -sctp_free_vrf(struct sctp_vrf *vrf) -{ - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&vrf->refcount)) { - if (vrf->vrf_addr_hash) { - SCTP_HASH_FREE(vrf->vrf_addr_hash, vrf->vrf_addr_hashmark); - vrf->vrf_addr_hash = NULL; - } - /* We zero'd the count */ - LIST_REMOVE(vrf, next_vrf); - SCTP_FREE(vrf, SCTP_M_VRF); - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_vrfs), 1); - } -} - -void -sctp_free_ifn(struct sctp_ifn *sctp_ifnp) -{ - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&sctp_ifnp->refcount)) { - /* We zero'd the count */ - if (sctp_ifnp->vrf) { - sctp_free_vrf(sctp_ifnp->vrf); - } - SCTP_FREE(sctp_ifnp, SCTP_M_IFN); - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_ifns), 1); - } -} - -void -sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu) -{ - struct sctp_ifn *sctp_ifnp; - - sctp_ifnp = sctp_find_ifn((void *)NULL, ifn_index); - if (sctp_ifnp != NULL) { - sctp_ifnp->ifn_mtu = mtu; - } -} - -void -sctp_free_ifa(struct sctp_ifa *sctp_ifap) -{ - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&sctp_ifap->refcount)) { - /* We zero'd the count */ - if (sctp_ifap->ifn_p) { - sctp_free_ifn(sctp_ifap->ifn_p); - } - SCTP_FREE(sctp_ifap, SCTP_M_IFA); - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_ifas), 1); - } -} - -static void -sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock) -{ - struct sctp_ifn *found; - - found = sctp_find_ifn(sctp_ifnp->ifn_p, sctp_ifnp->ifn_index); - if (found == NULL) { - /* Not in the list.. sorry */ - return; - } - if (hold_addr_lock == 0) { - SCTP_IPI_ADDR_WLOCK(); - } else { - SCTP_IPI_ADDR_WLOCK_ASSERT(); - } - LIST_REMOVE(sctp_ifnp, next_bucket); - LIST_REMOVE(sctp_ifnp, next_ifn); - if (hold_addr_lock == 0) { - SCTP_IPI_ADDR_WUNLOCK(); - } - /* Take away the reference, and possibly free it */ - sctp_free_ifn(sctp_ifnp); -} - -void -sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, - const char *if_name, uint32_t ifn_index) -{ - struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap; - - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find vrf_id 0x%x\n", vrf_id); - goto out; - } - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); - if (sctp_ifap == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find sctp_ifap for address\n"); - goto out; - } - if (sctp_ifap->ifn_p == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n"); - goto out; - } - if (if_name) { - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) != 0) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFN %s of IFA not the same as %s\n", - sctp_ifap->ifn_p->ifn_name, if_name); - goto out; - } - } else { - if (sctp_ifap->ifn_p->ifn_index != ifn_index) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n", - sctp_ifap->ifn_p->ifn_index, ifn_index); - goto out; - } - } - - sctp_ifap->localifa_flags &= (~SCTP_ADDR_VALID); - sctp_ifap->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; - out: - SCTP_IPI_ADDR_RUNLOCK(); -} - -void -sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, - const char *if_name, uint32_t ifn_index) -{ - struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap; - - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find vrf_id 0x%x\n", vrf_id); - goto out; - } - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); - if (sctp_ifap == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find sctp_ifap for address\n"); - goto out; - } - if (sctp_ifap->ifn_p == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n"); - goto out; - } - if (if_name) { - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) != 0) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFN %s of IFA not the same as %s\n", - sctp_ifap->ifn_p->ifn_name, if_name); - goto out; - } - } else { - if (sctp_ifap->ifn_p->ifn_index != ifn_index) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n", - sctp_ifap->ifn_p->ifn_index, ifn_index); - goto out; - } - } - - sctp_ifap->localifa_flags &= (~SCTP_ADDR_IFA_UNUSEABLE); - sctp_ifap->localifa_flags |= SCTP_ADDR_VALID; - out: - SCTP_IPI_ADDR_RUNLOCK(); -} - -/*- - * Add an ifa to an ifn. - * Register the interface as necessary. - * NOTE: ADDR write lock MUST be held. - */ -static void -sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap) -{ - int ifa_af; - - LIST_INSERT_HEAD(&sctp_ifnp->ifalist, sctp_ifap, next_ifa); - sctp_ifap->ifn_p = sctp_ifnp; - atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); - /* update address counts */ - sctp_ifnp->ifa_count++; - ifa_af = sctp_ifap->address.sa.sa_family; - switch (ifa_af) { -#ifdef INET - case AF_INET: - sctp_ifnp->num_v4++; - break; -#endif -#ifdef INET6 - case AF_INET6: - sctp_ifnp->num_v6++; - break; -#endif - default: - break; - } - if (sctp_ifnp->ifa_count == 1) { - /* register the new interface */ - sctp_ifnp->registered_af = ifa_af; - } -} - -/*- - * Remove an ifa from its ifn. - * If no more addresses exist, remove the ifn too. Otherwise, re-register - * the interface based on the remaining address families left. - * NOTE: ADDR write lock MUST be held. - */ -static void -sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap) -{ - LIST_REMOVE(sctp_ifap, next_ifa); - if (sctp_ifap->ifn_p) { - /* update address counts */ - sctp_ifap->ifn_p->ifa_count--; - switch (sctp_ifap->address.sa.sa_family) { -#ifdef INET - case AF_INET: - sctp_ifap->ifn_p->num_v4--; - break; -#endif -#ifdef INET6 - case AF_INET6: - sctp_ifap->ifn_p->num_v6--; - break; -#endif - default: - break; - } - - if (LIST_EMPTY(&sctp_ifap->ifn_p->ifalist)) { - /* remove the ifn, possibly freeing it */ - sctp_delete_ifn(sctp_ifap->ifn_p, SCTP_ADDR_LOCKED); - } else { - /* re-register address family type, if needed */ - if ((sctp_ifap->ifn_p->num_v6 == 0) && - (sctp_ifap->ifn_p->registered_af == AF_INET6)) { - sctp_ifap->ifn_p->registered_af = AF_INET; - } else if ((sctp_ifap->ifn_p->num_v4 == 0) && - (sctp_ifap->ifn_p->registered_af == AF_INET)) { - sctp_ifap->ifn_p->registered_af = AF_INET6; - } - /* free the ifn refcount */ - sctp_free_ifn(sctp_ifap->ifn_p); - } - sctp_ifap->ifn_p = NULL; - } -} - -struct sctp_ifa * -sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, - uint32_t ifn_type, const char *if_name, void *ifa, - struct sockaddr *addr, uint32_t ifa_flags, - int dynamic_add) -{ - struct sctp_vrf *vrf; - struct sctp_ifn *sctp_ifnp, *new_sctp_ifnp; - struct sctp_ifa *sctp_ifap, *new_sctp_ifap; - struct sctp_ifalist *hash_addr_head; - struct sctp_ifnlist *hash_ifn_head; - uint32_t hash_of_addr; - int new_ifn_af = 0; - -#ifdef SCTP_DEBUG - SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: adding address: ", vrf_id); - SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr); -#endif - SCTP_MALLOC(new_sctp_ifnp, struct sctp_ifn *, - sizeof(struct sctp_ifn), SCTP_M_IFN); - if (new_sctp_ifnp == NULL) { -#ifdef INVARIANTS - panic("No memory for IFN"); -#endif - return (NULL); - } - SCTP_MALLOC(new_sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA); - if (new_sctp_ifap == NULL) { -#ifdef INVARIANTS - panic("No memory for IFA"); -#endif - SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); - return (NULL); - } - - SCTP_IPI_ADDR_WLOCK(); - sctp_ifnp = sctp_find_ifn(ifn, ifn_index); - if (sctp_ifnp) { - vrf = sctp_ifnp->vrf; - } else { - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - vrf = sctp_allocate_vrf(vrf_id); - if (vrf == NULL) { - SCTP_IPI_ADDR_WUNLOCK(); - SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); - SCTP_FREE(new_sctp_ifap, SCTP_M_IFA); - return (NULL); - } - } - } - if (sctp_ifnp == NULL) { - /* build one and add it, can't hold lock - * until after malloc done though. - */ - sctp_ifnp = new_sctp_ifnp; - new_sctp_ifnp = NULL; - memset(sctp_ifnp, 0, sizeof(struct sctp_ifn)); - sctp_ifnp->ifn_index = ifn_index; - sctp_ifnp->ifn_p = ifn; - sctp_ifnp->ifn_type = ifn_type; - sctp_ifnp->refcount = 0; - sctp_ifnp->vrf = vrf; - atomic_add_int(&vrf->refcount, 1); - sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index); - if (if_name != NULL) { - SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", if_name); - } else { - SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", "unknown"); - } - hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))]; - LIST_INIT(&sctp_ifnp->ifalist); - LIST_INSERT_HEAD(hash_ifn_head, sctp_ifnp, next_bucket); - LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn); - atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifns), 1); - new_ifn_af = 1; - } - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); - if (sctp_ifap) { - /* Hmm, it already exists? */ - if ((sctp_ifap->ifn_p) && - (sctp_ifap->ifn_p->ifn_index == ifn_index)) { - SCTPDBG(SCTP_DEBUG_PCB4, "Using existing ifn %s (0x%x) for ifa %p\n", - sctp_ifap->ifn_p->ifn_name, ifn_index, - (void *)sctp_ifap); - if (new_ifn_af) { - /* Remove the created one that we don't want */ - sctp_delete_ifn(sctp_ifnp, SCTP_ADDR_LOCKED); - } - if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) { - /* easy to solve, just switch back to active */ - SCTPDBG(SCTP_DEBUG_PCB4, "Clearing deleted ifa flag\n"); - sctp_ifap->localifa_flags = SCTP_ADDR_VALID; - sctp_ifap->ifn_p = sctp_ifnp; - atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); - } - exit_stage_left: - SCTP_IPI_ADDR_WUNLOCK(); - if (new_sctp_ifnp != NULL) { - SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); - } - SCTP_FREE(new_sctp_ifap, SCTP_M_IFA); - return (sctp_ifap); - } else { - if (sctp_ifap->ifn_p) { - /* - * The last IFN gets the address, remove the - * old one - */ - SCTPDBG(SCTP_DEBUG_PCB4, "Moving ifa %p from %s (0x%x) to %s (0x%x)\n", - (void *)sctp_ifap, sctp_ifap->ifn_p->ifn_name, - sctp_ifap->ifn_p->ifn_index, if_name, - ifn_index); - /* remove the address from the old ifn */ - sctp_remove_ifa_from_ifn(sctp_ifap); - /* move the address over to the new ifn */ - sctp_add_ifa_to_ifn(sctp_ifnp, sctp_ifap); - goto exit_stage_left; - } else { - /* repair ifnp which was NULL ? */ - sctp_ifap->localifa_flags = SCTP_ADDR_VALID; - SCTPDBG(SCTP_DEBUG_PCB4, "Repairing ifn %p for ifa %p\n", - (void *)sctp_ifnp, (void *)sctp_ifap); - sctp_add_ifa_to_ifn(sctp_ifnp, sctp_ifap); - } - goto exit_stage_left; - } - } - sctp_ifap = new_sctp_ifap; - memset(sctp_ifap, 0, sizeof(struct sctp_ifa)); - sctp_ifap->ifn_p = sctp_ifnp; - atomic_add_int(&sctp_ifnp->refcount, 1); - sctp_ifap->vrf_id = vrf_id; - sctp_ifap->ifa = ifa; -#ifdef HAVE_SA_LEN - memcpy(&sctp_ifap->address, addr, addr->sa_len); -#else - switch (addr->sa_family) { -#ifdef INET - case AF_INET: - memcpy(&sctp_ifap->address, addr, sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: - memcpy(&sctp_ifap->address, addr, sizeof(struct sockaddr_in6)); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(&sctp_ifap->address, addr, sizeof(struct sockaddr_conn)); - break; -#endif - default: - /* TSNH */ - break; - } -#endif - sctp_ifap->localifa_flags = SCTP_ADDR_VALID | SCTP_ADDR_DEFER_USE; - sctp_ifap->flags = ifa_flags; - /* Set scope */ - switch (sctp_ifap->address.sa.sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = &sctp_ifap->address.sin; - if (SCTP_IFN_IS_IFT_LOOP(sctp_ifap->ifn_p) || - (IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr))) { - sctp_ifap->src_is_loop = 1; - } - if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { - sctp_ifap->src_is_priv = 1; - } - sctp_ifnp->num_v4++; - if (new_ifn_af) - new_ifn_af = AF_INET; - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - /* ok to use deprecated addresses? */ - struct sockaddr_in6 *sin6; - - sin6 = &sctp_ifap->address.sin6; - if (SCTP_IFN_IS_IFT_LOOP(sctp_ifap->ifn_p) || - (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))) { - sctp_ifap->src_is_loop = 1; - } - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - sctp_ifap->src_is_priv = 1; - } - sctp_ifnp->num_v6++; - if (new_ifn_af) - new_ifn_af = AF_INET6; - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - if (new_ifn_af) - new_ifn_af = AF_CONN; - break; -#endif - default: - new_ifn_af = 0; - break; - } - hash_of_addr = sctp_get_ifa_hash_val(&sctp_ifap->address.sa); - - if ((sctp_ifap->src_is_priv == 0) && - (sctp_ifap->src_is_loop == 0)) { - sctp_ifap->src_is_glob = 1; - } - hash_addr_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; - LIST_INSERT_HEAD(hash_addr_head, sctp_ifap, next_bucket); - sctp_ifap->refcount = 1; - LIST_INSERT_HEAD(&sctp_ifnp->ifalist, sctp_ifap, next_ifa); - sctp_ifnp->ifa_count++; - vrf->total_ifa_count++; - atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifas), 1); - if (new_ifn_af) { - sctp_ifnp->registered_af = new_ifn_af; - } - SCTP_IPI_ADDR_WUNLOCK(); - if (new_sctp_ifnp != NULL) { - SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); - } - - if (dynamic_add) { - /* Bump up the refcount so that when the timer - * completes it will drop back down. - */ - struct sctp_laddr *wi; - - atomic_add_int(&sctp_ifap->refcount, 1); - wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (wi == NULL) { - /* - * Gak, what can we do? We have lost an address - * change can you say HOSED? - */ - SCTPDBG(SCTP_DEBUG_PCB4, "Lost an address change?\n"); - /* Opps, must decrement the count */ - sctp_del_addr_from_vrf(vrf_id, addr, ifn_index, - if_name); - return (NULL); - } - SCTP_INCR_LADDR_COUNT(); - memset(wi, 0, sizeof(*wi)); - (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); - wi->ifa = sctp_ifap; - wi->action = SCTP_ADD_IP_ADDRESS; - - SCTP_WQ_ADDR_LOCK(); - LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, - (struct sctp_inpcb *)NULL, - (struct sctp_tcb *)NULL, - (struct sctp_nets *)NULL); - SCTP_WQ_ADDR_UNLOCK(); - } else { - /* it's ready for use */ - sctp_ifap->localifa_flags &= ~SCTP_ADDR_DEFER_USE; - } - return (sctp_ifap); -} - -void -sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, - uint32_t ifn_index, const char *if_name) -{ - struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap = NULL; - - SCTP_IPI_ADDR_WLOCK(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "Can't find vrf_id 0x%x\n", vrf_id); - goto out_now; - } - -#ifdef SCTP_DEBUG - SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: deleting address:", vrf_id); - SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr); -#endif - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); - if (sctp_ifap) { - /* Validate the delete */ - if (sctp_ifap->ifn_p) { - int valid = 0; - /*- - * The name has priority over the ifn_index - * if its given. - */ - if (if_name) { - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) == 0) { - /* They match its a correct delete */ - valid = 1; - } - } - if (!valid) { - /* last ditch check ifn_index */ - if (ifn_index == sctp_ifap->ifn_p->ifn_index) { - valid = 1; - } - } - if (!valid) { - SCTPDBG(SCTP_DEBUG_PCB4, "ifn:%d ifname:%s does not match addresses\n", - ifn_index, ((if_name == NULL) ? "NULL" : if_name)); - SCTPDBG(SCTP_DEBUG_PCB4, "ifn:%d ifname:%s - ignoring delete\n", - sctp_ifap->ifn_p->ifn_index, sctp_ifap->ifn_p->ifn_name); - SCTP_IPI_ADDR_WUNLOCK(); - return; - } - } - SCTPDBG(SCTP_DEBUG_PCB4, "Deleting ifa %p\n", (void *)sctp_ifap); - sctp_ifap->localifa_flags &= SCTP_ADDR_VALID; - /* - * We don't set the flag. This means that the structure will - * hang around in EP's that have bound specific to it until - * they close. This gives us TCP like behavior if someone - * removes an address (or for that matter adds it right back). - */ - /* sctp_ifap->localifa_flags |= SCTP_BEING_DELETED; */ - vrf->total_ifa_count--; - LIST_REMOVE(sctp_ifap, next_bucket); - sctp_remove_ifa_from_ifn(sctp_ifap); - } -#ifdef SCTP_DEBUG - else { - SCTPDBG(SCTP_DEBUG_PCB4, "Del Addr-ifn:%d Could not find address:", - ifn_index); - SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr); - } -#endif - - out_now: - SCTP_IPI_ADDR_WUNLOCK(); - if (sctp_ifap) { - struct sctp_laddr *wi; - - wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (wi == NULL) { - /* - * Gak, what can we do? We have lost an address - * change can you say HOSED? - */ - SCTPDBG(SCTP_DEBUG_PCB4, "Lost an address change?\n"); - - /* Oops, must decrement the count */ - sctp_free_ifa(sctp_ifap); - return; - } - SCTP_INCR_LADDR_COUNT(); - memset(wi, 0, sizeof(*wi)); - (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); - wi->ifa = sctp_ifap; - wi->action = SCTP_DEL_IP_ADDRESS; - SCTP_WQ_ADDR_LOCK(); - /* - * Should this really be a tailq? As it is we will process the - * newest first :-0 - */ - LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, - (struct sctp_inpcb *)NULL, - (struct sctp_tcb *)NULL, - (struct sctp_nets *)NULL); - SCTP_WQ_ADDR_UNLOCK(); - } - return; -} - -static int -sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) -{ - int loopback_scope; -#if defined(INET) - int ipv4_local_scope, ipv4_addr_legal; -#endif -#if defined(INET6) - int local_scope, site_scope, ipv6_addr_legal; -#endif -#if defined(__Userspace__) - int conn_addr_legal; -#endif - struct sctp_vrf *vrf; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - - loopback_scope = stcb->asoc.scope.loopback_scope; -#if defined(INET) - ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; - ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; -#endif -#if defined(INET6) - local_scope = stcb->asoc.scope.local_scope; - site_scope = stcb->asoc.scope.site_scope; - ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; -#endif -#if defined(__Userspace__) - conn_addr_legal = stcb->asoc.scope.conn_addr_legal; -#endif - - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(stcb->asoc.vrf_id); - if (vrf == NULL) { - /* no vrf, no addresses */ - SCTP_IPI_ADDR_RUNLOCK(); - return (0); - } - - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if ((loopback_scope == 0) && - SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (sctp_is_addr_restricted(stcb, sctp_ifa) && - (!sctp_is_addr_pending(stcb, sctp_ifa))) { - /* We allow pending addresses, where we - * have sent an asconf-add to be considered - * valid. - */ - continue; - } - if (sctp_ifa->address.sa.sa_family != to->sa_family) { - continue; - } - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (ipv4_addr_legal) { - struct sockaddr_in *sin, *rsin; - - sin = &sctp_ifa->address.sin; - rsin = (struct sockaddr_in *)to; - if ((ipv4_local_scope == 0) && - IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (ipv6_addr_legal) { - struct sockaddr_in6 *sin6, *rsin6; -#if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME) - struct sockaddr_in6 lsa6; -#endif - sin6 = &sctp_ifa->address.sin6; - rsin6 = (struct sockaddr_in6 *)to; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (local_scope == 0) - continue; -#if defined(SCTP_EMBEDDED_V6_SCOPE) - if (sin6->sin6_scope_id == 0) { -#ifdef SCTP_KAME - if (sa6_recoverscope(sin6) != 0) - continue; -#else - lsa6 = *sin6; - if (in6_recoverscope(&lsa6, - &lsa6.sin6_addr, - NULL)) - continue; - sin6 = &lsa6; -#endif /* SCTP_KAME */ - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - } - if ((site_scope == 0) && - (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - continue; - } - if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (conn_addr_legal) { - struct sockaddr_conn *sconn, *rsconn; - - sconn = &sctp_ifa->address.sconn; - rsconn = (struct sockaddr_conn *)to; - if (sconn->sconn_addr == rsconn->sconn_addr) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - } - break; -#endif - default: - /* TSNH */ - break; - } - } - } - } else { - struct sctp_laddr *laddr; - - LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { - SCTPDBG(SCTP_DEBUG_PCB1, "ifa being deleted\n"); - continue; - } - if (sctp_is_addr_restricted(stcb, laddr->ifa) && - (!sctp_is_addr_pending(stcb, laddr->ifa))) { - /* We allow pending addresses, where we - * have sent an asconf-add to be considered - * valid. - */ - continue; - } - if (laddr->ifa->address.sa.sa_family != to->sa_family) { - continue; - } - switch (to->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin, *rsin; - - sin = &laddr->ifa->address.sin; - rsin = (struct sockaddr_in *)to; - if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6, *rsin6; - - sin6 = &laddr->ifa->address.sin6; - rsin6 = (struct sockaddr_in6 *)to; - if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - break; - } - -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn, *rsconn; - - sconn = &laddr->ifa->address.sconn; - rsconn = (struct sockaddr_conn *)to; - if (sconn->sconn_addr == rsconn->sconn_addr) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - break; - } -#endif - default: - /* TSNH */ - break; - } - } - } - SCTP_IPI_ADDR_RUNLOCK(); - return (0); -} - -static struct sctp_tcb * -sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, - struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id) -{ - /**** ASSUMES THE CALLER holds the INP_INFO_RLOCK */ - /* - * If we support the TCP model, then we must now dig through to see - * if we can find our endpoint in the list of tcp ep's. - */ - uint16_t lport, rport; - struct sctppcbhead *ephead; - struct sctp_inpcb *inp; - struct sctp_laddr *laddr; - struct sctp_tcb *stcb; - struct sctp_nets *net; -#ifdef SCTP_MVRF - int fnd, i; -#endif - - if ((to == NULL) || (from == NULL)) { - return (NULL); - } - - switch (to->sa_family) { -#ifdef INET - case AF_INET: - if (from->sa_family == AF_INET) { - lport = ((struct sockaddr_in *)to)->sin_port; - rport = ((struct sockaddr_in *)from)->sin_port; - } else { - return (NULL); - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (from->sa_family == AF_INET6) { - lport = ((struct sockaddr_in6 *)to)->sin6_port; - rport = ((struct sockaddr_in6 *)from)->sin6_port; - } else { - return (NULL); - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (from->sa_family == AF_CONN) { - lport = ((struct sockaddr_conn *)to)->sconn_port; - rport = ((struct sockaddr_conn *)from)->sconn_port; - } else { - return (NULL); - } - break; -#endif - default: - return (NULL); - } - ephead = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR((lport | rport), SCTP_BASE_INFO(hashtcpmark))]; - /* - * Ok now for each of the guys in this bucket we must look and see: - * - Does the remote port match. - Does there single association's - * addresses match this address (to). If so we update p_ep to point - * to this ep and return the tcb from it. - */ - LIST_FOREACH(inp, ephead, sctp_hash) { - SCTP_INP_RLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - SCTP_INP_RUNLOCK(inp); - continue; - } - if (lport != inp->sctp_lport) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - switch (to->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)to; - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - SCTP_INP_RUNLOCK(inp); - continue; - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)to; - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - SCTP_INP_RUNLOCK(inp); - continue; - } - break; - } -#endif - default: - SCTP_INP_RUNLOCK(inp); - continue; - } -#endif -#ifdef SCTP_MVRF - fnd = 0; - for (i = 0; i < inp->num_vrfs; i++) { - if (inp->m_vrf_ids[i] == vrf_id) { - fnd = 1; - break; - } - } - if (fnd == 0) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#else - if (inp->def_vrf_id != vrf_id) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#endif - /* check to see if the ep has one of the addresses */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { - /* We are NOT bound all, so look further */ - int match = 0; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n", __func__); - continue; - } - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { - SCTPDBG(SCTP_DEBUG_PCB1, "ifa being deleted\n"); - continue; - } - if (laddr->ifa->address.sa.sa_family == - to->sa_family) { - /* see if it matches */ -#ifdef INET - if (from->sa_family == AF_INET) { - struct sockaddr_in *intf_addr, *sin; - - intf_addr = &laddr->ifa->address.sin; - sin = (struct sockaddr_in *)to; - if (sin->sin_addr.s_addr == - intf_addr->sin_addr.s_addr) { - match = 1; - break; - } - } -#endif -#ifdef INET6 - if (from->sa_family == AF_INET6) { - struct sockaddr_in6 *intf_addr6; - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *) - to; - intf_addr6 = &laddr->ifa->address.sin6; - - if (SCTP6_ARE_ADDR_EQUAL(sin6, - intf_addr6)) { - match = 1; - break; - } - } -#endif -#if defined(__Userspace__) - if (from->sa_family == AF_CONN) { - struct sockaddr_conn *intf_addr, *sconn; - - intf_addr = &laddr->ifa->address.sconn; - sconn = (struct sockaddr_conn *)to; - if (sconn->sconn_addr == - intf_addr->sconn_addr) { - match = 1; - break; - } - } -#endif - } - } - if (match == 0) { - /* This endpoint does not have this address */ - SCTP_INP_RUNLOCK(inp); - continue; - } - } - /* - * Ok if we hit here the ep has the address, does it hold - * the tcb? - */ - /* XXX: Why don't we TAILQ_FOREACH through sctp_asoc_list? */ - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); - continue; - } - SCTP_TCB_LOCK(stcb); - if (!sctp_does_stcb_own_this_addr(stcb, to)) { - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - continue; - } - if (stcb->rport != rport) { - /* remote port does not match. */ - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - continue; - } - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - continue; - } - if (!sctp_does_stcb_own_this_addr(stcb, to)) { - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - continue; - } - /* Does this TCB have a matching address? */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->ro._l_addr.sa.sa_family != from->sa_family) { - /* not the same family, can't be a match */ - continue; - } - switch (from->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin, *rsin; - - sin = (struct sockaddr_in *)&net->ro._l_addr; - rsin = (struct sockaddr_in *)from; - if (sin->sin_addr.s_addr == - rsin->sin_addr.s_addr) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - /* Update the endpoint pointer */ - *inp_p = inp; - SCTP_INP_RUNLOCK(inp); - return (stcb); - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6, *rsin6; - - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; - rsin6 = (struct sockaddr_in6 *)from; - if (SCTP6_ARE_ADDR_EQUAL(sin6, - rsin6)) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - /* Update the endpoint pointer */ - *inp_p = inp; - SCTP_INP_RUNLOCK(inp); - return (stcb); - } - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn, *rsconn; - - sconn = (struct sockaddr_conn *)&net->ro._l_addr; - rsconn = (struct sockaddr_conn *)from; - if (sconn->sconn_addr == rsconn->sconn_addr) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - /* Update the endpoint pointer */ - *inp_p = inp; - SCTP_INP_RUNLOCK(inp); - return (stcb); - } - break; - } -#endif - default: - /* TSNH */ - break; - } - } - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - } - return (NULL); -} - -/* - * rules for use - * - * 1) If I return a NULL you must decrement any INP ref cnt. 2) If I find an - * stcb, both will be locked (locked_tcb and stcb) but decrement will be done - * (if locked == NULL). 3) Decrement happens on return ONLY if locked == - * NULL. - */ - -struct sctp_tcb * -sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, - struct sctp_nets **netp, struct sockaddr *local, struct sctp_tcb *locked_tcb) -{ - struct sctpasochead *head; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb = NULL; - struct sctp_nets *net; - uint16_t rport; - - inp = *inp_p; - switch (remote->sa_family) { -#ifdef INET - case AF_INET: - rport = (((struct sockaddr_in *)remote)->sin_port); - break; -#endif -#ifdef INET6 - case AF_INET6: - rport = (((struct sockaddr_in6 *)remote)->sin6_port); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - rport = (((struct sockaddr_conn *)remote)->sconn_port); - break; -#endif - default: - return (NULL); - } - if (locked_tcb) { - /* - * UN-lock so we can do proper locking here this occurs when - * called from load_addresses_from_init. - */ - atomic_add_int(&locked_tcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(locked_tcb); - } - SCTP_INP_INFO_RLOCK(); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /*- - * Now either this guy is our listener or it's the - * connector. If it is the one that issued the connect, then - * it's only chance is to be the first TCB in the list. If - * it is the acceptor, then do the special_lookup to hash - * and find the real inp. - */ - if ((inp->sctp_socket) && SCTP_IS_LISTENING(inp)) { - /* to is peer addr, from is my addr */ -#ifndef SCTP_MVRF - stcb = sctp_tcb_special_locate(inp_p, remote, local, - netp, inp->def_vrf_id); - if ((stcb != NULL) && (locked_tcb == NULL)) { - /* we have a locked tcb, lower refcount */ - SCTP_INP_DECR_REF(inp); - } - if ((locked_tcb != NULL) && (locked_tcb != stcb)) { - SCTP_INP_RLOCK(locked_tcb->sctp_ep); - SCTP_TCB_LOCK(locked_tcb); - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - SCTP_INP_RUNLOCK(locked_tcb->sctp_ep); - } -#else - /*- - * MVRF is tricky, we must look in every VRF - * the endpoint has. - */ - int i; - - for (i = 0; i < inp->num_vrfs; i++) { - stcb = sctp_tcb_special_locate(inp_p, remote, local, - netp, inp->m_vrf_ids[i]); - if ((stcb != NULL) && (locked_tcb == NULL)) { - /* we have a locked tcb, lower refcount */ - SCTP_INP_DECR_REF(inp); - break; - } - if ((locked_tcb != NULL) && (locked_tcb != stcb)) { - SCTP_INP_RLOCK(locked_tcb->sctp_ep); - SCTP_TCB_LOCK(locked_tcb); - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - SCTP_INP_RUNLOCK(locked_tcb->sctp_ep); - break; - } - } -#endif - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } else { - SCTP_INP_WLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - goto null_return; - } - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - goto null_return; - } - SCTP_TCB_LOCK(stcb); - - if (stcb->rport != rport) { - /* remote port does not match. */ - SCTP_TCB_UNLOCK(stcb); - goto null_return; - } - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_TCB_UNLOCK(stcb); - goto null_return; - } - if (local && !sctp_does_stcb_own_this_addr(stcb, local)) { - SCTP_TCB_UNLOCK(stcb); - goto null_return; - } - /* now look at the list of remote addresses */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { -#ifdef INVARIANTS - if (net == (TAILQ_NEXT(net, sctp_next))) { - panic("Corrupt net list"); - } -#endif - if (net->ro._l_addr.sa.sa_family != - remote->sa_family) { - /* not the same family */ - continue; - } - switch (remote->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin, *rsin; - - sin = (struct sockaddr_in *) - &net->ro._l_addr; - rsin = (struct sockaddr_in *)remote; - if (sin->sin_addr.s_addr == - rsin->sin_addr.s_addr) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - if (locked_tcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else if (locked_tcb != stcb) { - SCTP_TCB_LOCK(locked_tcb); - } - if (locked_tcb) { - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6, *rsin6; - - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; - rsin6 = (struct sockaddr_in6 *)remote; - if (SCTP6_ARE_ADDR_EQUAL(sin6, - rsin6)) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - if (locked_tcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else if (locked_tcb != stcb) { - SCTP_TCB_LOCK(locked_tcb); - } - if (locked_tcb) { - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn, *rsconn; - - sconn = (struct sockaddr_conn *)&net->ro._l_addr; - rsconn = (struct sockaddr_conn *)remote; - if (sconn->sconn_addr == rsconn->sconn_addr) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - if (locked_tcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else if (locked_tcb != stcb) { - SCTP_TCB_LOCK(locked_tcb); - } - if (locked_tcb) { - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - break; - } -#endif - default: - /* TSNH */ - break; - } - } - SCTP_TCB_UNLOCK(stcb); - } - } else { - SCTP_INP_WLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - goto null_return; - } - head = &inp->sctp_tcbhash[SCTP_PCBHASH_ALLADDR(rport, - inp->sctp_hashmark)]; - LIST_FOREACH(stcb, head, sctp_tcbhash) { - if (stcb->rport != rport) { - /* remote port does not match */ - continue; - } - SCTP_TCB_LOCK(stcb); - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_TCB_UNLOCK(stcb); - continue; - } - if (local && !sctp_does_stcb_own_this_addr(stcb, local)) { - SCTP_TCB_UNLOCK(stcb); - continue; - } - /* now look at the list of remote addresses */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { -#ifdef INVARIANTS - if (net == (TAILQ_NEXT(net, sctp_next))) { - panic("Corrupt net list"); - } -#endif - if (net->ro._l_addr.sa.sa_family != - remote->sa_family) { - /* not the same family */ - continue; - } - switch (remote->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin, *rsin; - - sin = (struct sockaddr_in *) - &net->ro._l_addr; - rsin = (struct sockaddr_in *)remote; - if (sin->sin_addr.s_addr == - rsin->sin_addr.s_addr) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - if (locked_tcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else if (locked_tcb != stcb) { - SCTP_TCB_LOCK(locked_tcb); - } - if (locked_tcb) { - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6, *rsin6; - - sin6 = (struct sockaddr_in6 *) - &net->ro._l_addr; - rsin6 = (struct sockaddr_in6 *)remote; - if (SCTP6_ARE_ADDR_EQUAL(sin6, - rsin6)) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - if (locked_tcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else if (locked_tcb != stcb) { - SCTP_TCB_LOCK(locked_tcb); - } - if (locked_tcb) { - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn, *rsconn; - - sconn = (struct sockaddr_conn *)&net->ro._l_addr; - rsconn = (struct sockaddr_conn *)remote; - if (sconn->sconn_addr == rsconn->sconn_addr) { - /* found it */ - if (netp != NULL) { - *netp = net; - } - if (locked_tcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else if (locked_tcb != stcb) { - SCTP_TCB_LOCK(locked_tcb); - } - if (locked_tcb) { - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - break; - } -#endif - default: - /* TSNH */ - break; - } - } - SCTP_TCB_UNLOCK(stcb); - } - } -null_return: - /* clean up for returning null */ - if (locked_tcb) { - SCTP_TCB_LOCK(locked_tcb); - atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); - } - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - /* not found */ - return (NULL); -} - -/* - * Find an association for a specific endpoint using the association id given - * out in the COMM_UP notification - */ -struct sctp_tcb * -sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock) -{ - /* - * Use my the assoc_id to find a endpoint - */ - struct sctpasochead *head; - struct sctp_tcb *stcb; - uint32_t id; - - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - SCTP_PRINTF("TSNH ep_associd0\n"); - return (NULL); - } - id = (uint32_t)asoc_id; - head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)]; - if (head == NULL) { - /* invalid id TSNH */ - SCTP_PRINTF("TSNH ep_associd1\n"); - return (NULL); - } - LIST_FOREACH(stcb, head, sctp_tcbasocidhash) { - if (stcb->asoc.assoc_id == id) { - if (inp != stcb->sctp_ep) { - /* - * some other guy has the same id active (id - * collision ??). - */ - SCTP_PRINTF("TSNH ep_associd2\n"); - continue; - } - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - continue; - } - if (want_lock) { - SCTP_TCB_LOCK(stcb); - } - return (stcb); - } - } - return (NULL); -} - -struct sctp_tcb * -sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock) -{ - struct sctp_tcb *stcb; - - SCTP_INP_RLOCK(inp); - stcb = sctp_findasoc_ep_asocid_locked(inp, asoc_id, want_lock); - SCTP_INP_RUNLOCK(inp); - return (stcb); -} - -/* - * Endpoint probe expects that the INP_INFO is locked. - */ -static struct sctp_inpcb * -sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head, - uint16_t lport, uint32_t vrf_id) -{ - struct sctp_inpcb *inp; - struct sctp_laddr *laddr; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; - struct sockaddr_in6 *intf_addr6; -#endif -#if defined(__Userspace__) - struct sockaddr_conn *sconn; -#endif -#ifdef SCTP_MVRF - int i; -#endif - int fnd; - -#ifdef INET - sin = NULL; -#endif -#ifdef INET6 - sin6 = NULL; -#endif -#if defined(__Userspace__) - sconn = NULL; -#endif - switch (nam->sa_family) { -#ifdef INET - case AF_INET: - sin = (struct sockaddr_in *)nam; - break; -#endif -#ifdef INET6 - case AF_INET6: - sin6 = (struct sockaddr_in6 *)nam; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - sconn = (struct sockaddr_conn *)nam; - break; -#endif - default: - /* unsupported family */ - return (NULL); - } - - if (head == NULL) - return (NULL); - - LIST_FOREACH(inp, head, sctp_hash) { - SCTP_INP_RLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - SCTP_INP_RUNLOCK(inp); - continue; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) && - (inp->sctp_lport == lport)) { - /* got it */ - switch (nam->sa_family) { -#ifdef INET - case AF_INET: - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - /* IPv4 on a IPv6 socket with ONLY IPv6 set */ - SCTP_INP_RUNLOCK(inp); - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - /* A V6 address and the endpoint is NOT bound V6 */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#endif - break; -#endif - default: - break; - } - /* does a VRF id match? */ - fnd = 0; -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (inp->m_vrf_ids[i] == vrf_id) { - fnd = 1; - break; - } - } -#else - if (inp->def_vrf_id == vrf_id) - fnd = 1; -#endif - - SCTP_INP_RUNLOCK(inp); - if (!fnd) - continue; - return (inp); - } - SCTP_INP_RUNLOCK(inp); - } - switch (nam->sa_family) { -#ifdef INET - case AF_INET: - if (sin->sin_addr.s_addr == INADDR_ANY) { - /* Can't hunt for one that has no address specified */ - return (NULL); - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* Can't hunt for one that has no address specified */ - return (NULL); - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (sconn->sconn_addr == NULL) { - return (NULL); - } - break; -#endif - default: - break; - } - /* - * ok, not bound to all so see if we can find a EP bound to this - * address. - */ - LIST_FOREACH(inp, head, sctp_hash) { - SCTP_INP_RLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - SCTP_INP_RUNLOCK(inp); - continue; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)) { - SCTP_INP_RUNLOCK(inp); - continue; - } - /* - * Ok this could be a likely candidate, look at all of its - * addresses - */ - if (inp->sctp_lport != lport) { - SCTP_INP_RUNLOCK(inp); - continue; - } - /* does a VRF id match? */ - fnd = 0; -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (inp->m_vrf_ids[i] == vrf_id) { - fnd = 1; - break; - } - } -#else - if (inp->def_vrf_id == vrf_id) - fnd = 1; - -#endif - if (!fnd) { - SCTP_INP_RUNLOCK(inp); - continue; - } - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n", - __func__); - continue; - } - SCTPDBG(SCTP_DEBUG_PCB1, "Ok laddr->ifa:%p is possible, ", - (void *)laddr->ifa); - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { - SCTPDBG(SCTP_DEBUG_PCB1, "Huh IFA being deleted\n"); - continue; - } - if (laddr->ifa->address.sa.sa_family == nam->sa_family) { - /* possible, see if it matches */ - switch (nam->sa_family) { -#ifdef INET - case AF_INET: -#if defined(__APPLE__) && !defined(__Userspace__) - if (sin == NULL) { - /* TSNH */ - break; - } -#endif - if (sin->sin_addr.s_addr == - laddr->ifa->address.sin.sin_addr.s_addr) { - SCTP_INP_RUNLOCK(inp); - return (inp); - } - break; -#endif -#ifdef INET6 - case AF_INET6: - intf_addr6 = &laddr->ifa->address.sin6; - if (SCTP6_ARE_ADDR_EQUAL(sin6, - intf_addr6)) { - SCTP_INP_RUNLOCK(inp); - return (inp); - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (sconn->sconn_addr == laddr->ifa->address.sconn.sconn_addr) { - SCTP_INP_RUNLOCK(inp); - return (inp); - } - break; -#endif - } - } - } - SCTP_INP_RUNLOCK(inp); - } - return (NULL); -} - -static struct sctp_inpcb * -sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id) -{ - struct sctppcbhead *head; - struct sctp_inpcb *t_inp; -#ifdef SCTP_MVRF - int i; -#endif - int fnd; - - head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(lport, - SCTP_BASE_INFO(hashmark))]; - LIST_FOREACH(t_inp, head, sctp_hash) { - if (t_inp->sctp_lport != lport) { - continue; - } - /* is it in the VRF in question */ - fnd = 0; -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (t_inp->m_vrf_ids[i] == vrf_id) { - fnd = 1; - break; - } - } -#else - if (t_inp->def_vrf_id == vrf_id) - fnd = 1; -#endif - if (!fnd) - continue; - - /* This one is in use. */ - /* check the v6/v4 binding issue */ - if ((t_inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(t_inp)) { - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - /* collision in V6 space */ - return (t_inp); - } else { - /* inp is BOUND_V4 no conflict */ - continue; - } - } else if (t_inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - /* t_inp is bound v4 and v6, conflict always */ - return (t_inp); - } else { - /* t_inp is bound only V4 */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - /* no conflict */ - continue; - } - /* else fall through to conflict */ - } - return (t_inp); - } - return (NULL); -} - -int -sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp) -{ - /* For 1-2-1 with port reuse */ - struct sctppcbhead *head; - struct sctp_inpcb *tinp, *ninp; - - SCTP_INP_INFO_WLOCK_ASSERT(); - SCTP_INP_WLOCK_ASSERT(inp); - - if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) { - /* only works with port reuse on */ - return (-1); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) { - return (0); - } - SCTP_INP_WUNLOCK(inp); - head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(inp->sctp_lport, - SCTP_BASE_INFO(hashmark))]; - /* Kick out all non-listeners to the TCP hash */ - LIST_FOREACH_SAFE(tinp, head, sctp_hash, ninp) { - if (tinp->sctp_lport != inp->sctp_lport) { - continue; - } - if (tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - continue; - } - if (tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - continue; - } - if (SCTP_IS_LISTENING(tinp)) { - continue; - } - SCTP_INP_WLOCK(tinp); - LIST_REMOVE(tinp, sctp_hash); - head = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR(tinp->sctp_lport, SCTP_BASE_INFO(hashtcpmark))]; - tinp->sctp_flags |= SCTP_PCB_FLAGS_IN_TCPPOOL; - LIST_INSERT_HEAD(head, tinp, sctp_hash); - SCTP_INP_WUNLOCK(tinp); - } - SCTP_INP_WLOCK(inp); - /* Pull from where he was */ - LIST_REMOVE(inp, sctp_hash); - inp->sctp_flags &= ~SCTP_PCB_FLAGS_IN_TCPPOOL; - head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(inp->sctp_lport, SCTP_BASE_INFO(hashmark))]; - LIST_INSERT_HEAD(head, inp, sctp_hash); - return (0); -} - -struct sctp_inpcb * -sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock, - uint32_t vrf_id) -{ - /* - * First we check the hash table to see if someone has this port - * bound with just the port. - */ - struct sctp_inpcb *inp; - struct sctppcbhead *head; - int lport; - unsigned int i; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif -#if defined(__Userspace__) - struct sockaddr_conn *sconn; -#endif - - switch (nam->sa_family) { -#ifdef INET - case AF_INET: - sin = (struct sockaddr_in *)nam; - lport = sin->sin_port; - break; -#endif -#ifdef INET6 - case AF_INET6: - sin6 = (struct sockaddr_in6 *)nam; - lport = sin6->sin6_port; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - sconn = (struct sockaddr_conn *)nam; - lport = sconn->sconn_port; - break; -#endif - default: - return (NULL); - } - /* - * I could cheat here and just cast to one of the types but we will - * do it right. It also provides the check against an Unsupported - * type too. - */ - /* Find the head of the ALLADDR chain */ - if (have_lock == 0) { - SCTP_INP_INFO_RLOCK(); - } - head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(lport, - SCTP_BASE_INFO(hashmark))]; - inp = sctp_endpoint_probe(nam, head, lport, vrf_id); - - /* - * If the TCP model exists it could be that the main listening - * endpoint is gone but there still exists a connected socket for this - * guy. If so we can return the first one that we find. This may NOT - * be the correct one so the caller should be wary on the returned INP. - * Currently the only caller that sets find_tcp_pool is in bindx where - * we are verifying that a user CAN bind the address. He either - * has bound it already, or someone else has, or its open to bind, - * so this is good enough. - */ - if (inp == NULL && find_tcp_pool) { - for (i = 0; i < SCTP_BASE_INFO(hashtcpmark) + 1; i++) { - head = &SCTP_BASE_INFO(sctp_tcpephash)[i]; - inp = sctp_endpoint_probe(nam, head, lport, vrf_id); - if (inp) { - break; - } - } - } - if (inp) { - SCTP_INP_INCR_REF(inp); - } - if (have_lock == 0) { - SCTP_INP_INFO_RUNLOCK(); - } - return (inp); -} - -/* - * Find an association for an endpoint with the pointer to whom you want to - * send to and the endpoint pointer. The address can be IPv4 or IPv6. We may - * need to change the *to to some other struct like a mbuf... - */ -struct sctp_tcb * -sctp_findassociation_addr_sa(struct sockaddr *from, struct sockaddr *to, - struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool, - uint32_t vrf_id) -{ - struct sctp_inpcb *inp = NULL; - struct sctp_tcb *stcb; - - SCTP_INP_INFO_RLOCK(); - if (find_tcp_pool) { - if (inp_p != NULL) { - stcb = sctp_tcb_special_locate(inp_p, from, to, netp, - vrf_id); - } else { - stcb = sctp_tcb_special_locate(&inp, from, to, netp, - vrf_id); - } - if (stcb != NULL) { - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - } - inp = sctp_pcb_findep(to, 0, 1, vrf_id); - if (inp_p != NULL) { - *inp_p = inp; - } - SCTP_INP_INFO_RUNLOCK(); - if (inp == NULL) { - return (NULL); - } - /* - * ok, we have an endpoint, now lets find the assoc for it (if any) - * we now place the source address or from in the to of the find - * endpoint call. Since in reality this chain is used from the - * inbound packet side. - */ - if (inp_p != NULL) { - stcb = sctp_findassociation_ep_addr(inp_p, from, netp, to, - NULL); - } else { - stcb = sctp_findassociation_ep_addr(&inp, from, netp, to, - NULL); - } - return (stcb); -} - -/* - * This routine will grub through the mbuf that is a INIT or INIT-ACK and - * find all addresses that the sender has specified in any address list. Each - * address will be used to lookup the TCB and see if one exits. - */ -static struct sctp_tcb * -sctp_findassociation_special_addr(struct mbuf *m, int offset, - struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp, - struct sockaddr *dst) -{ - struct sctp_paramhdr *phdr, param_buf; -#if defined(INET) || defined(INET6) - struct sctp_tcb *stcb; - uint16_t ptype; -#endif - uint16_t plen; -#ifdef INET - struct sockaddr_in sin4; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - -#ifdef INET - memset(&sin4, 0, sizeof(sin4)); -#ifdef HAVE_SIN_LEN - sin4.sin_len = sizeof(sin4); -#endif - sin4.sin_family = AF_INET; - sin4.sin_port = sh->src_port; -#endif -#ifdef INET6 - memset(&sin6, 0, sizeof(sin6)); -#ifdef HAVE_SIN6_LEN - sin6.sin6_len = sizeof(sin6); -#endif - sin6.sin6_family = AF_INET6; - sin6.sin6_port = sh->src_port; -#endif - - offset += sizeof(struct sctp_init_chunk); - - phdr = sctp_get_next_param(m, offset, ¶m_buf, sizeof(param_buf)); - while (phdr != NULL) { - /* now we must see if we want the parameter */ -#if defined(INET) || defined(INET6) - ptype = ntohs(phdr->param_type); -#endif - plen = ntohs(phdr->param_length); - if (plen == 0) { - break; - } -#ifdef INET - if (ptype == SCTP_IPV4_ADDRESS && - plen == sizeof(struct sctp_ipv4addr_param)) { - /* Get the rest of the address */ - struct sctp_ipv4addr_param ip4_param, *p4; - - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&ip4_param, sizeof(ip4_param)); - if (phdr == NULL) { - return (NULL); - } - p4 = (struct sctp_ipv4addr_param *)phdr; - memcpy(&sin4.sin_addr, &p4->addr, sizeof(p4->addr)); - /* look it up */ - stcb = sctp_findassociation_ep_addr(inp_p, - (struct sockaddr *)&sin4, netp, dst, NULL); - if (stcb != NULL) { - return (stcb); - } - } -#endif -#ifdef INET6 - if (ptype == SCTP_IPV6_ADDRESS && - plen == sizeof(struct sctp_ipv6addr_param)) { - /* Get the rest of the address */ - struct sctp_ipv6addr_param ip6_param, *p6; - - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&ip6_param, sizeof(ip6_param)); - if (phdr == NULL) { - return (NULL); - } - p6 = (struct sctp_ipv6addr_param *)phdr; - memcpy(&sin6.sin6_addr, &p6->addr, sizeof(p6->addr)); - /* look it up */ - stcb = sctp_findassociation_ep_addr(inp_p, - (struct sockaddr *)&sin6, netp, dst, NULL); - if (stcb != NULL) { - return (stcb); - } - } -#endif - offset += SCTP_SIZE32(plen); - phdr = sctp_get_next_param(m, offset, ¶m_buf, - sizeof(param_buf)); - } - return (NULL); -} - -static struct sctp_tcb * -sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag, - struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint16_t rport, - uint16_t lport, int skip_src_check, uint32_t vrf_id, uint32_t remote_tag) -{ - /* - * Use my vtag to hash. If we find it we then verify the source addr - * is in the assoc. If all goes well we save a bit on rec of a - * packet. - */ - struct sctpasochead *head; - struct sctp_nets *net; - struct sctp_tcb *stcb; -#ifdef SCTP_MVRF - unsigned int i; -#endif - - SCTP_INP_INFO_RLOCK(); - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(vtag, - SCTP_BASE_INFO(hashasocmark))]; - LIST_FOREACH(stcb, head, sctp_asocs) { - SCTP_INP_RLOCK(stcb->sctp_ep); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - SCTP_INP_RUNLOCK(stcb->sctp_ep); - continue; - } -#ifdef SCTP_MVRF - for (i = 0; i < stcb->sctp_ep->num_vrfs; i++) { - if (stcb->sctp_ep->m_vrf_ids[i] == vrf_id) { - break; - } - } - if (i == stcb->sctp_ep->num_vrfs) { - SCTP_INP_RUNLOCK(inp); - continue; - } -#else - if (stcb->sctp_ep->def_vrf_id != vrf_id) { - SCTP_INP_RUNLOCK(stcb->sctp_ep); - continue; - } -#endif - SCTP_TCB_LOCK(stcb); - SCTP_INP_RUNLOCK(stcb->sctp_ep); - if (stcb->asoc.my_vtag == vtag) { - /* candidate */ - if (stcb->rport != rport) { - SCTP_TCB_UNLOCK(stcb); - continue; - } - if (stcb->sctp_ep->sctp_lport != lport) { - SCTP_TCB_UNLOCK(stcb); - continue; - } - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_TCB_UNLOCK(stcb); - continue; - } - /* RRS:Need toaddr check here */ - if (sctp_does_stcb_own_this_addr(stcb, to) == 0) { - /* Endpoint does not own this address */ - SCTP_TCB_UNLOCK(stcb); - continue; - } - if (remote_tag) { - /* If we have both vtags that's all we match on */ - if (stcb->asoc.peer_vtag == remote_tag) { - /* If both tags match we consider it conclusive - * and check NO source/destination addresses - */ - goto conclusive; - } - } - if (skip_src_check) { - conclusive: - if (from) { - *netp = sctp_findnet(stcb, from); - } else { - *netp = NULL; /* unknown */ - } - if (inp_p) - *inp_p = stcb->sctp_ep; - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } - net = sctp_findnet(stcb, from); - if (net) { - /* yep its him. */ - *netp = net; - SCTP_STAT_INCR(sctps_vtagexpress); - *inp_p = stcb->sctp_ep; - SCTP_INP_INFO_RUNLOCK(); - return (stcb); - } else { - /* - * not him, this should only happen in rare - * cases so I peg it. - */ - SCTP_STAT_INCR(sctps_vtagbogus); - } - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_INFO_RUNLOCK(); - return (NULL); -} - -/* - * Find an association with the pointer to the inbound IP packet. This can be - * a IPv4 or IPv6 packet. - */ -struct sctp_tcb * -sctp_findassociation_addr(struct mbuf *m, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_chunkhdr *ch, - struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id) -{ - struct sctp_tcb *stcb; - struct sctp_inpcb *inp; - - if (sh->v_tag) { - /* we only go down this path if vtag is non-zero */ - stcb = sctp_findassoc_by_vtag(src, dst, ntohl(sh->v_tag), - inp_p, netp, sh->src_port, sh->dest_port, 0, vrf_id, 0); - if (stcb) { - return (stcb); - } - } - - if (inp_p) { - stcb = sctp_findassociation_addr_sa(src, dst, inp_p, netp, - 1, vrf_id); - inp = *inp_p; - } else { - stcb = sctp_findassociation_addr_sa(src, dst, &inp, netp, - 1, vrf_id); - } - SCTPDBG(SCTP_DEBUG_PCB1, "stcb:%p inp:%p\n", (void *)stcb, (void *)inp); - if (stcb == NULL && inp) { - /* Found a EP but not this address */ - if ((ch->chunk_type == SCTP_INITIATION) || - (ch->chunk_type == SCTP_INITIATION_ACK)) { - /*- - * special hook, we do NOT return linp or an - * association that is linked to an existing - * association that is under the TCP pool (i.e. no - * listener exists). The endpoint finding routine - * will always find a listener before examining the - * TCP pool. - */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { - if (inp_p) { - *inp_p = NULL; - } - return (NULL); - } - stcb = sctp_findassociation_special_addr(m, - offset, sh, &inp, netp, dst); - if (inp_p != NULL) { - *inp_p = inp; - } - } - } - SCTPDBG(SCTP_DEBUG_PCB1, "stcb is %p\n", (void *)stcb); - return (stcb); -} - -/* - * lookup an association by an ASCONF lookup address. - * if the lookup address is 0.0.0.0 or ::0, use the vtag to do the lookup - */ -struct sctp_tcb * -sctp_findassociation_ep_asconf(struct mbuf *m, int offset, - struct sockaddr *dst, struct sctphdr *sh, - struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id) -{ - struct sctp_tcb *stcb; - union sctp_sockstore remote_store; - struct sctp_paramhdr param_buf, *phdr; - int ptype; - int zero_address = 0; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - - memset(&remote_store, 0, sizeof(remote_store)); - phdr = sctp_get_next_param(m, offset + sizeof(struct sctp_asconf_chunk), - ¶m_buf, sizeof(struct sctp_paramhdr)); - if (phdr == NULL) { - SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf lookup addr\n", - __func__); - return NULL; - } - ptype = (int)((uint32_t) ntohs(phdr->param_type)); - /* get the correlation address */ - switch (ptype) { -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - { - /* ipv6 address param */ - struct sctp_ipv6addr_param *p6, p6_buf; - - if (ntohs(phdr->param_length) != sizeof(struct sctp_ipv6addr_param)) { - return NULL; - } - p6 = (struct sctp_ipv6addr_param *)sctp_get_next_param(m, - offset + sizeof(struct sctp_asconf_chunk), - &p6_buf.ph, sizeof(p6_buf)); - if (p6 == NULL) { - SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf v6 lookup addr\n", - __func__); - return (NULL); - } - sin6 = &remote_store.sin6; - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(*sin6); -#endif - sin6->sin6_port = sh->src_port; - memcpy(&sin6->sin6_addr, &p6->addr, sizeof(struct in6_addr)); - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) - zero_address = 1; - break; - } -#endif -#ifdef INET - case SCTP_IPV4_ADDRESS: - { - /* ipv4 address param */ - struct sctp_ipv4addr_param *p4, p4_buf; - - if (ntohs(phdr->param_length) != sizeof(struct sctp_ipv4addr_param)) { - return NULL; - } - p4 = (struct sctp_ipv4addr_param *)sctp_get_next_param(m, - offset + sizeof(struct sctp_asconf_chunk), - &p4_buf.ph, sizeof(p4_buf)); - if (p4 == NULL) { - SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf v4 lookup addr\n", - __func__); - return (NULL); - } - sin = &remote_store.sin; - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(*sin); -#endif - sin->sin_port = sh->src_port; - memcpy(&sin->sin_addr, &p4->addr, sizeof(struct in_addr)); - if (sin->sin_addr.s_addr == INADDR_ANY) - zero_address = 1; - break; - } -#endif - default: - /* invalid address param type */ - return NULL; - } - - if (zero_address) { - stcb = sctp_findassoc_by_vtag(NULL, dst, ntohl(sh->v_tag), inp_p, - netp, sh->src_port, sh->dest_port, 1, vrf_id, 0); - if (stcb != NULL) { - SCTP_INP_DECR_REF(*inp_p); - } - } else { - stcb = sctp_findassociation_ep_addr(inp_p, - &remote_store.sa, netp, - dst, NULL); - } - return (stcb); -} - -/* - * allocate a sctp_inpcb and setup a temporary binding to a port/all - * addresses. This way if we don't get a bind we by default pick a ephemeral - * port with all addresses bound. - */ -int -sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) -{ - /* - * we get called when a new endpoint starts up. We need to allocate - * the sctp_inpcb structure from the zone and init it. Mark it as - * unbound and find a port that we can use as an ephemeral with - * INADDR_ANY. If the user binds later no problem we can then add in - * the specific addresses. And setup the default parameters for the - * EP. - */ - int i, error; - struct sctp_inpcb *inp; - struct sctp_pcb *m; - struct timeval time; - sctp_sharedkey_t *null_key; - - error = 0; - - SCTP_INP_INFO_WLOCK(); - inp = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_ep), struct sctp_inpcb); - if (inp == NULL) { - SCTP_PRINTF("Out of SCTP-INPCB structures - no resources\n"); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); - return (ENOBUFS); - } - /* zap it */ - memset(inp, 0, sizeof(*inp)); - - /* bump generations */ -#if defined(__APPLE__) && !defined(__Userspace__) - inp->ip_inp.inp.inp_state = INPCB_STATE_INUSE; -#endif - /* setup socket pointers */ - inp->sctp_socket = so; - inp->ip_inp.inp.inp_socket = so; -#if defined(__FreeBSD__) && !defined(__Userspace__) - inp->ip_inp.inp.inp_cred = crhold(so->so_cred); -#endif -#ifdef INET6 -#if !defined(__Userspace__) && !defined(_WIN32) - if (INP_SOCKAF(so) == AF_INET6) { - if (MODULE_GLOBAL(ip6_auto_flowlabel)) { - inp->ip_inp.inp.inp_flags |= IN6P_AUTOFLOWLABEL; - } - if (MODULE_GLOBAL(ip6_v6only)) { - inp->ip_inp.inp.inp_flags |= IN6P_IPV6_V6ONLY; - } - } -#endif -#endif - inp->sctp_associd_counter = 1; - inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; - inp->sctp_frag_point = 0; - inp->max_cwnd = 0; - inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); - inp->ecn_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_ecn_enable); - inp->prsctp_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_pr_enable); - inp->auth_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_auth_enable); - inp->asconf_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_asconf_enable); - inp->reconfig_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_reconfig_enable); - inp->nrsack_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_nrsack_enable); - inp->pktdrop_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_pktdrop_enable); - inp->idata_supported = 0; - inp->rcv_edmid = SCTP_EDMID_NONE; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - inp->fibnum = so->so_fibnum; -#else - inp->fibnum = 0; -#endif -#if defined(__Userspace__) - inp->ulp_info = NULL; - inp->recv_callback = NULL; - inp->send_callback = NULL; - inp->send_sb_threshold = 0; -#endif - /* init the small hash table we use to track asocid <-> tcb */ - inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark); - if (inp->sctp_asocidhash == NULL) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - crfree(inp->ip_inp.inp.inp_cred); -#endif - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); - SCTP_INP_INFO_WUNLOCK(); - return (ENOBUFS); - } - SCTP_INCR_EP_COUNT(); - inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl); - SCTP_INP_INFO_WUNLOCK(); - - so->so_pcb = (caddr_t)inp; - - if (SCTP_SO_TYPE(so) == SOCK_SEQPACKET) { - /* UDP style socket */ - inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | - SCTP_PCB_FLAGS_UNBOUND); - /* Be sure it is NON-BLOCKING IO for UDP */ - /* SCTP_SET_SO_NBIO(so); */ - } else if (SCTP_SO_TYPE(so) == SOCK_STREAM) { - /* TCP style socket */ - inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE | - SCTP_PCB_FLAGS_UNBOUND); - /* Be sure we have blocking IO by default */ - SOCK_LOCK(so); - SCTP_CLEAR_SO_NBIO(so); - SOCK_UNLOCK(so); - } else { - /* - * unsupported socket type (RAW, etc)- in case we missed it - * in protosw - */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP); - so->so_pcb = NULL; -#if defined(__FreeBSD__) && !defined(__Userspace__) - crfree(inp->ip_inp.inp.inp_cred); -#endif - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); - return (EOPNOTSUPP); - } - if (SCTP_BASE_SYSCTL(sctp_default_frag_interleave) == SCTP_FRAG_LEVEL_1) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); - } else if (SCTP_BASE_SYSCTL(sctp_default_frag_interleave) == SCTP_FRAG_LEVEL_2) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); - } else if (SCTP_BASE_SYSCTL(sctp_default_frag_interleave) == SCTP_FRAG_LEVEL_0) { - sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); - } - inp->sctp_tcbhash = SCTP_HASH_INIT(SCTP_BASE_SYSCTL(sctp_pcbtblsize), - &inp->sctp_hashmark); - if (inp->sctp_tcbhash == NULL) { - SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n"); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); - so->so_pcb = NULL; -#if defined(__FreeBSD__) && !defined(__Userspace__) - crfree(inp->ip_inp.inp.inp_cred); -#endif - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); - return (ENOBUFS); - } -#ifdef SCTP_MVRF - inp->vrf_size = SCTP_DEFAULT_VRF_SIZE; - SCTP_MALLOC(inp->m_vrf_ids, uint32_t *, - (sizeof(uint32_t) * inp->vrf_size), SCTP_M_MVRF); - if (inp->m_vrf_ids == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); - so->so_pcb = NULL; - SCTP_HASH_FREE(inp->sctp_tcbhash, inp->sctp_hashmark); -#if defined(__FreeBSD__) && !defined(__Userspace__) - crfree(inp->ip_inp.inp.inp_cred); -#endif - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); - return (ENOBUFS); - } - inp->m_vrf_ids[0] = vrf_id; - inp->num_vrfs = 1; -#endif - inp->def_vrf_id = vrf_id; - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - inp->ip_inp.inp.inpcb_mtx = lck_mtx_alloc_init(SCTP_BASE_INFO(sctbinfo).mtx_grp, SCTP_BASE_INFO(sctbinfo).mtx_attr); - if (inp->ip_inp.inp.inpcb_mtx == NULL) { - SCTP_PRINTF("in_pcballoc: can't alloc mutex! so=%p\n", (void *)so); -#ifdef SCTP_MVRF - SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF); -#endif - SCTP_HASH_FREE(inp->sctp_tcbhash, inp->sctp_hashmark); - so->so_pcb = NULL; - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); - SCTP_UNLOCK_EXC(SCTP_BASE_INFO(sctbinfo).ipi_lock); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM); - return (ENOMEM); - } -#elif defined(APPLE_LION) || defined(APPLE_MOUNTAINLION) - lck_mtx_init(&inp->ip_inp.inp.inpcb_mtx, SCTP_BASE_INFO(sctbinfo).mtx_grp, SCTP_BASE_INFO(sctbinfo).mtx_attr); -#else - lck_mtx_init(&inp->ip_inp.inp.inpcb_mtx, SCTP_BASE_INFO(sctbinfo).ipi_lock_grp, SCTP_BASE_INFO(sctbinfo).ipi_lock_attr); -#endif -#endif - SCTP_INP_INFO_WLOCK(); - SCTP_INP_LOCK_INIT(inp); -#if defined(__FreeBSD__) && !defined(__Userspace__) - rw_init_flags(&inp->ip_inp.inp.inp_lock, "sctpinp", - RW_RECURSE | RW_DUPOK); -#endif - SCTP_INP_READ_LOCK_INIT(inp); - SCTP_ASOC_CREATE_LOCK_INIT(inp); - /* lock the new ep */ - SCTP_INP_WLOCK(inp); - - /* add it to the info area */ - LIST_INSERT_HEAD(&SCTP_BASE_INFO(listhead), inp, sctp_list); -#if defined(__APPLE__) && !defined(__Userspace__) - inp->ip_inp.inp.inp_pcbinfo = &SCTP_BASE_INFO(sctbinfo); -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION) - LIST_INSERT_HEAD(SCTP_BASE_INFO(sctbinfo).listhead, &inp->ip_inp.inp, inp_list); -#else - LIST_INSERT_HEAD(SCTP_BASE_INFO(sctbinfo).ipi_listhead, &inp->ip_inp.inp, inp_list); -#endif -#endif - SCTP_INP_INFO_WUNLOCK(); - - TAILQ_INIT(&inp->read_queue); - LIST_INIT(&inp->sctp_addr_list); - - LIST_INIT(&inp->sctp_asoc_list); - -#ifdef SCTP_TRACK_FREED_ASOCS - /* TEMP CODE */ - LIST_INIT(&inp->sctp_asoc_free_list); -#endif - /* Init the timer structure for signature change */ - SCTP_OS_TIMER_INIT(&inp->sctp_ep.signature_change.timer); - inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NEWCOOKIE; - - /* now init the actual endpoint default data */ - m = &inp->sctp_ep; - - /* setup the base timeout information */ - m->sctp_timeoutticks[SCTP_TIMER_SEND] = sctp_secs_to_ticks(SCTP_SEND_SEC); /* needed ? */ - m->sctp_timeoutticks[SCTP_TIMER_INIT] = sctp_secs_to_ticks(SCTP_INIT_SEC); /* needed ? */ - m->sctp_timeoutticks[SCTP_TIMER_RECV] = sctp_msecs_to_ticks(SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default)); - m->sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default)); - m->sctp_timeoutticks[SCTP_TIMER_PMTU] = sctp_secs_to_ticks(SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default)); - m->sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] = sctp_secs_to_ticks(SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default)); - m->sctp_timeoutticks[SCTP_TIMER_SIGNATURE] = sctp_secs_to_ticks(SCTP_BASE_SYSCTL(sctp_secret_lifetime_default)); - /* all max/min max are in ms */ - m->sctp_maxrto = SCTP_BASE_SYSCTL(sctp_rto_max_default); - m->sctp_minrto = SCTP_BASE_SYSCTL(sctp_rto_min_default); - m->initial_rto = SCTP_BASE_SYSCTL(sctp_rto_initial_default); - m->initial_init_rto_max = SCTP_BASE_SYSCTL(sctp_init_rto_max_default); - m->sctp_sack_freq = SCTP_BASE_SYSCTL(sctp_sack_freq_default); - m->max_init_times = SCTP_BASE_SYSCTL(sctp_init_rtx_max_default); - m->max_send_times = SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default); - m->def_net_failure = SCTP_BASE_SYSCTL(sctp_path_rtx_max_default); - m->def_net_pf_threshold = SCTP_BASE_SYSCTL(sctp_path_pf_threshold); - m->sctp_sws_sender = SCTP_SWS_SENDER_DEF; - m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF; - m->max_burst = SCTP_BASE_SYSCTL(sctp_max_burst_default); - m->fr_max_burst = SCTP_BASE_SYSCTL(sctp_fr_max_burst_default); - - m->sctp_default_cc_module = SCTP_BASE_SYSCTL(sctp_default_cc_module); - m->sctp_default_ss_module = SCTP_BASE_SYSCTL(sctp_default_ss_module); - m->max_open_streams_intome = SCTP_BASE_SYSCTL(sctp_nr_incoming_streams_default); - /* number of streams to pre-open on a association */ - m->pre_open_stream_count = SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default); - - m->default_mtu = 0; - /* Add adaptation cookie */ - m->adaptation_layer_indicator = 0; - m->adaptation_layer_indicator_provided = 0; - - /* seed random number generator */ - m->random_counter = 1; - m->store_at = SCTP_SIGNATURE_SIZE; - SCTP_READ_RANDOM(m->random_numbers, sizeof(m->random_numbers)); - sctp_fill_random_store(m); - - /* Minimum cookie size */ - m->size_of_a_cookie = (sizeof(struct sctp_init_msg) * 2) + - sizeof(struct sctp_state_cookie); - m->size_of_a_cookie += SCTP_SIGNATURE_SIZE; - - /* Setup the initial secret */ - (void)SCTP_GETTIME_TIMEVAL(&time); - m->time_of_secret_change = (unsigned int)time.tv_sec; - - for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) { - m->secret_key[0][i] = sctp_select_initial_TSN(m); - } - sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL); - - /* How long is a cookie good for ? */ - m->def_cookie_life = sctp_msecs_to_ticks(SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default)); - /* - * Initialize authentication parameters - */ - m->local_hmacs = sctp_default_supported_hmaclist(); - m->local_auth_chunks = sctp_alloc_chunklist(); - if (inp->asconf_supported) { - sctp_auth_add_chunk(SCTP_ASCONF, m->local_auth_chunks); - sctp_auth_add_chunk(SCTP_ASCONF_ACK, m->local_auth_chunks); - } - m->default_dscp = 0; -#ifdef INET6 - m->default_flowlabel = 0; -#endif - m->port = 0; /* encapsulation disabled by default */ - LIST_INIT(&m->shared_keys); - /* add default NULL key as key id 0 */ - null_key = sctp_alloc_sharedkey(); - sctp_insert_sharedkey(&m->shared_keys, null_key); - SCTP_INP_WUNLOCK(inp); -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 12); -#endif - return (error); -} - -void -sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, - struct sctp_tcb *stcb) -{ - struct sctp_nets *net; - uint16_t lport, rport; - struct sctppcbhead *head; - struct sctp_laddr *laddr, *oladdr; - - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(old_inp); - SCTP_INP_WLOCK(new_inp); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET6 - if (old_inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - new_inp->ip_inp.inp.inp_flags |= old_inp->ip_inp.inp.inp_flags & INP_CONTROLOPTS; - if (old_inp->ip_inp.inp.in6p_outputopts) { - new_inp->ip_inp.inp.in6p_outputopts = ip6_copypktopts(old_inp->ip_inp.inp.in6p_outputopts, M_NOWAIT); - } - } -#endif -#if defined(INET) && defined(INET6) - else -#endif -#ifdef INET - { - new_inp->ip_inp.inp.inp_ip_tos = old_inp->ip_inp.inp.inp_ip_tos; - new_inp->ip_inp.inp.inp_ip_ttl = old_inp->ip_inp.inp.inp_ip_ttl; - } -#endif -#endif - new_inp->sctp_ep.time_of_secret_change = - old_inp->sctp_ep.time_of_secret_change; - memcpy(new_inp->sctp_ep.secret_key, old_inp->sctp_ep.secret_key, - sizeof(old_inp->sctp_ep.secret_key)); - new_inp->sctp_ep.current_secret_number = - old_inp->sctp_ep.current_secret_number; - new_inp->sctp_ep.last_secret_number = - old_inp->sctp_ep.last_secret_number; - new_inp->sctp_ep.size_of_a_cookie = old_inp->sctp_ep.size_of_a_cookie; - - /* make it so new data pours into the new socket */ - stcb->sctp_socket = new_inp->sctp_socket; - stcb->sctp_ep = new_inp; - - /* Copy the port across */ - lport = new_inp->sctp_lport = old_inp->sctp_lport; - rport = stcb->rport; - /* Pull the tcb from the old association */ - LIST_REMOVE(stcb, sctp_tcbhash); - LIST_REMOVE(stcb, sctp_tcblist); - if (stcb->asoc.in_asocid_hash) { - LIST_REMOVE(stcb, sctp_tcbasocidhash); - } - /* Now insert the new_inp into the TCP connected hash */ - head = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR((lport | rport), SCTP_BASE_INFO(hashtcpmark))]; - - LIST_INSERT_HEAD(head, new_inp, sctp_hash); - /* Its safe to access */ - new_inp->sctp_flags &= ~SCTP_PCB_FLAGS_UNBOUND; - - /* Now move the tcb into the endpoint list */ - LIST_INSERT_HEAD(&new_inp->sctp_asoc_list, stcb, sctp_tcblist); - /* - * Question, do we even need to worry about the ep-hash since we - * only have one connection? Probably not :> so lets get rid of it - * and not suck up any kernel memory in that. - */ - if (stcb->asoc.in_asocid_hash) { - struct sctpasochead *lhd; - lhd = &new_inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(stcb->asoc.assoc_id, - new_inp->hashasocidmark)]; - LIST_INSERT_HEAD(lhd, stcb, sctp_tcbasocidhash); - } - /* Ok. Let's restart timer. */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, new_inp, - stcb, net); - } - - SCTP_INP_INFO_WUNLOCK(); - if (new_inp->sctp_tcbhash != NULL) { - SCTP_HASH_FREE(new_inp->sctp_tcbhash, new_inp->sctp_hashmark); - new_inp->sctp_tcbhash = NULL; - } - if ((new_inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { - /* Subset bound, so copy in the laddr list from the old_inp */ - LIST_FOREACH(oladdr, &old_inp->sctp_addr_list, sctp_nxt_addr) { - laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (laddr == NULL) { - /* - * Gak, what can we do? This assoc is really - * HOSED. We probably should send an abort - * here. - */ - SCTPDBG(SCTP_DEBUG_PCB1, "Association hosed in TCP model, out of laddr memory\n"); - continue; - } - SCTP_INCR_LADDR_COUNT(); - memset(laddr, 0, sizeof(*laddr)); - (void)SCTP_GETTIME_TIMEVAL(&laddr->start_time); - laddr->ifa = oladdr->ifa; - atomic_add_int(&laddr->ifa->refcount, 1); - LIST_INSERT_HEAD(&new_inp->sctp_addr_list, laddr, - sctp_nxt_addr); - new_inp->laddr_count++; - if (oladdr == stcb->asoc.last_used_address) { - stcb->asoc.last_used_address = laddr; - } - } - } - /* Now any running timers need to be adjusted. */ - if (stcb->asoc.dack_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - stcb->asoc.dack_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (stcb->asoc.asconf_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - stcb->asoc.asconf_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (stcb->asoc.strreset_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - stcb->asoc.strreset_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (stcb->asoc.shut_guard_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - stcb->asoc.shut_guard_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (stcb->asoc.autoclose_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - stcb->asoc.autoclose_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (stcb->asoc.delete_prim_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - stcb->asoc.delete_prim_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - /* now what about the nets? */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->pmtu_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - net->pmtu_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (net->hb_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - net->hb_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - if (net->rxt_timer.ep == old_inp) { - SCTP_INP_DECR_REF(old_inp); - net->rxt_timer.ep = new_inp; - SCTP_INP_INCR_REF(new_inp); - } - } - SCTP_INP_WUNLOCK(new_inp); - SCTP_INP_WUNLOCK(old_inp); -} - -/* - * insert an laddr entry with the given ifa for the desired list - */ -static int -sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act) -{ - struct sctp_laddr *laddr; - - laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (laddr == NULL) { - /* out of memory? */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); - } - SCTP_INCR_LADDR_COUNT(); - memset(laddr, 0, sizeof(*laddr)); - (void)SCTP_GETTIME_TIMEVAL(&laddr->start_time); - laddr->ifa = ifa; - laddr->action = act; - atomic_add_int(&ifa->refcount, 1); - /* insert it */ - LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr); - - return (0); -} - -/* - * Remove an laddr entry from the local address list (on an assoc) - */ -static void -sctp_remove_laddr(struct sctp_laddr *laddr) -{ - - /* remove from the list */ - LIST_REMOVE(laddr, sctp_nxt_addr); - sctp_free_ifa(laddr->ifa); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr); - SCTP_DECR_LADDR_COUNT(); -} -#if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)) - -/* - * Don't know why, but without this there is an unknown reference when - * compiling NetBSD... hmm - */ -extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *sin6); -#endif - -/* - * Bind the socket, with the PCB and global info locks held. Note, if a - * socket address is specified, the PCB lock may be dropped and re-acquired. - * - * sctp_ifap is used to bypass normal local address validation checks. - */ -int -#if defined(__FreeBSD__) && !defined(__Userspace__) -sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, struct thread *td) -#elif defined(_WIN32) && !defined(__Userspace__) -sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, PKTHREAD p) -#else -sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, struct proc *p) -#endif -{ - /* bind a ep to a socket address */ - struct sctppcbhead *head; - struct sctp_inpcb *inp_tmp; -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) - struct inpcb *ip_inp; -#endif - int port_reuse_active = 0; - int bindall; -#ifdef SCTP_MVRF - int i; -#endif - uint16_t lport; - int error; - uint32_t vrf_id; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - KASSERT(td != NULL, ("%s: null thread", __func__)); - -#endif - error = 0; - lport = 0; - bindall = 1; -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) - ip_inp = &inp->ip_inp.inp; -#endif - - SCTP_INP_INFO_WLOCK_ASSERT(); - SCTP_INP_WLOCK_ASSERT(inp); - -#ifdef SCTP_DEBUG - if (addr) { - SCTPDBG(SCTP_DEBUG_PCB1, "Bind called port: %d\n", - ntohs(((struct sockaddr_in *)addr)->sin_port)); - SCTPDBG(SCTP_DEBUG_PCB1, "Addr: "); - SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr); - } -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { - error = EINVAL; - /* already did a bind, subsequent binds NOT allowed ! */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - if (addr != NULL) { - switch (addr->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - /* IPV6_V6ONLY socket? */ - if (SCTP_IPV6_V6ONLY(inp)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(*sin)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#endif - - sin = (struct sockaddr_in *)addr; - lport = sin->sin_port; -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* - * For LOOPBACK the prison_local_ip4() call will transmute the ip address - * to the proper value. - */ - if ((error = prison_local_ip4(td->td_ucred, &sin->sin_addr)) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#endif - if (sin->sin_addr.s_addr != INADDR_ANY) { - bindall = 0; - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - /* Only for pure IPv6 Address. (No IPv4 Mapped!) */ - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(*sin6)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#endif - lport = sin6->sin6_port; -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* - * For LOOPBACK the prison_local_ip6() call will transmute the ipv6 address - * to the proper value. - */ - if ((error = prison_local_ip6(td->td_ucred, &sin6->sin6_addr, - (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#endif - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - bindall = 0; -#ifdef SCTP_EMBEDDED_V6_SCOPE - /* KAME hack: embed scopeid */ -#if defined(SCTP_KAME) - if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#elif defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - if (in6_embedscope(&sin6->sin6_addr, sin6, ip_inp, NULL) != 0) { -#else - if (in6_embedscope(&sin6->sin6_addr, sin6, ip_inp, NULL, NULL) != 0) { -#endif - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#elif defined(__FreeBSD__) && !defined(__Userspace__) - error = scope6_check_id(sin6, MODULE_GLOBAL(ip6_use_defzone)); - if (error != 0) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#else - if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#endif -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - } -#ifndef SCOPEDROUTING - /* this must be cleared for ifa_ifwithaddr() */ - sin6->sin6_scope_id = 0; -#endif /* SCOPEDROUTING */ - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn; - -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_conn)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#endif - sconn = (struct sockaddr_conn *)addr; - lport = sconn->sconn_port; - if (sconn->sconn_addr != NULL) { - bindall = 0; - } - break; - } -#endif - default: - error = EAFNOSUPPORT; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - } - /* Setup a vrf_id to be the default for the non-bind-all case. */ - vrf_id = inp->def_vrf_id; - - if (lport) { - /* - * Did the caller specify a port? if so we must see if an ep - * already has this one bound. - */ - /* got to be root to get at low ports */ -#if !(defined(_WIN32) && !defined(__Userspace__)) - if (ntohs(lport) < IPPORT_RESERVED && -#if defined(__FreeBSD__) && !defined(__Userspace__) - (error = priv_check(td, PRIV_NETINET_RESERVEDPORT)) != 0) { -#elif defined(__APPLE__) && !defined(__Userspace__) - (error = suser(p->p_ucred, &p->p_acflag)) != 0) { -#elif defined(__Userspace__) - /* TODO ensure uid is 0, etc... */ - 0) { -#else - (error = suser(p, 0)) != 0) { -#endif - goto out; - } -#endif - SCTP_INP_INCR_REF(inp); - SCTP_INP_WUNLOCK(inp); - if (bindall) { -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - vrf_id = inp->m_vrf_ids[i]; -#else - vrf_id = inp->def_vrf_id; -#endif - inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id); - if (inp_tmp != NULL) { - /* - * lock guy returned and lower count - * note that we are not bound so - * inp_tmp should NEVER be inp. And - * it is this inp (inp_tmp) that gets - * the reference bump, so we must - * lower it. - */ - SCTP_INP_DECR_REF(inp_tmp); - /* unlock info */ - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && - (sctp_is_feature_on(inp_tmp, SCTP_PCB_FLAGS_PORTREUSE))) { - /* Ok, must be one-2-one and allowing port re-use */ - port_reuse_active = 1; - goto continue_anyway; - } - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - error = EADDRINUSE; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#ifdef SCTP_MVRF - } -#endif - } else { - inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id); - if (inp_tmp != NULL) { - /* - * lock guy returned and lower count note - * that we are not bound so inp_tmp should - * NEVER be inp. And it is this inp (inp_tmp) - * that gets the reference bump, so we must - * lower it. - */ - SCTP_INP_DECR_REF(inp_tmp); - /* unlock info */ - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && - (sctp_is_feature_on(inp_tmp, SCTP_PCB_FLAGS_PORTREUSE))) { - /* Ok, must be one-2-one and allowing port re-use */ - port_reuse_active = 1; - goto continue_anyway; - } - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - error = EADDRINUSE; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - } - continue_anyway: - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - if (bindall) { - /* verify that no lport is not used by a singleton */ - if ((port_reuse_active == 0) && - (inp_tmp = sctp_isport_inuse(inp, lport, vrf_id))) { - /* Sorry someone already has this one bound */ - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && - (sctp_is_feature_on(inp_tmp, SCTP_PCB_FLAGS_PORTREUSE))) { - port_reuse_active = 1; - } else { - error = EADDRINUSE; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - } - } - } else { - uint16_t first, last, candidate; - uint16_t count; - -#if defined(__Userspace__) - first = MODULE_GLOBAL(ipport_firstauto); - last = MODULE_GLOBAL(ipport_lastauto); -#elif defined(_WIN32) - first = 1; - last = 0xffff; -#elif defined(__FreeBSD__) || defined(__APPLE__) - if (ip_inp->inp_flags & INP_HIGHPORT) { - first = MODULE_GLOBAL(ipport_hifirstauto); - last = MODULE_GLOBAL(ipport_hilastauto); - } else if (ip_inp->inp_flags & INP_LOWPORT) { -#if defined(__FreeBSD__) - if ((error = priv_check(td, PRIV_NETINET_RESERVEDPORT)) != 0) { -#else - if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) { -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - first = MODULE_GLOBAL(ipport_lowfirstauto); - last = MODULE_GLOBAL(ipport_lowlastauto); - } else { - first = MODULE_GLOBAL(ipport_firstauto); - last = MODULE_GLOBAL(ipport_lastauto); - } -#endif - if (first > last) { - uint16_t temp; - - temp = first; - first = last; - last = temp; - } - count = last - first + 1; /* number of candidates */ - candidate = first + sctp_select_initial_TSN(&inp->sctp_ep) % (count); - - for (;;) { -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (sctp_isport_inuse(inp, htons(candidate), inp->m_vrf_ids[i]) != NULL) { - break; - } - } - if (i == inp->num_vrfs) { - lport = htons(candidate); - break; - } -#else - if (sctp_isport_inuse(inp, htons(candidate), inp->def_vrf_id) == NULL) { - lport = htons(candidate); - break; - } -#endif - if (--count == 0) { - error = EADDRINUSE; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - if (candidate == last) - candidate = first; - else - candidate = candidate + 1; - } - } - if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | - SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - /* - * this really should not happen. The guy did a non-blocking - * bind and then did a close at the same time. - */ - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - /* ok we look clear to give out this port, so lets setup the binding */ - if (bindall) { - /* binding to all addresses, so just set in the proper flags */ - inp->sctp_flags |= SCTP_PCB_FLAGS_BOUNDALL; - /* set the automatic addr changes from kernel flag */ - if (SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) { - sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF); - sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); - } else { - sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF); - sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); - } - if (SCTP_BASE_SYSCTL(sctp_multiple_asconfs) == 0) { - sctp_feature_off(inp, SCTP_PCB_FLAGS_MULTIPLE_ASCONFS); - } else { - sctp_feature_on(inp, SCTP_PCB_FLAGS_MULTIPLE_ASCONFS); - } - /* set the automatic mobility_base from kernel - flag (by micchie) - */ - if (SCTP_BASE_SYSCTL(sctp_mobility_base) == 0) { - sctp_mobility_feature_off(inp, SCTP_MOBILITY_BASE); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); - } else { - sctp_mobility_feature_on(inp, SCTP_MOBILITY_BASE); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); - } - /* set the automatic mobility_fasthandoff from kernel - flag (by micchie) - */ - if (SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff) == 0) { - sctp_mobility_feature_off(inp, SCTP_MOBILITY_FASTHANDOFF); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); - } else { - sctp_mobility_feature_on(inp, SCTP_MOBILITY_FASTHANDOFF); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); - } - } else { - /* - * bind specific, make sure flags is off and add a new - * address structure to the sctp_addr_list inside the ep - * structure. - * - * We will need to allocate one and insert it at the head. The - * socketopt call can just insert new addresses in there as - * well. It will also have to do the embed scope kame hack - * too (before adding). - */ - struct sctp_ifa *ifa; - union sctp_sockstore store; - - memset(&store, 0, sizeof(store)); - switch (addr->sa_family) { -#ifdef INET - case AF_INET: - memcpy(&store.sin, addr, sizeof(struct sockaddr_in)); - store.sin.sin_port = 0; - break; -#endif -#ifdef INET6 - case AF_INET6: - memcpy(&store.sin6, addr, sizeof(struct sockaddr_in6)); - store.sin6.sin6_port = 0; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(&store.sconn, addr, sizeof(struct sockaddr_conn)); - store.sconn.sconn_port = 0; - break; -#endif - default: - break; - } - /* - * first find the interface with the bound address need to - * zero out the port to find the address! yuck! can't do - * this earlier since need port for sctp_pcb_findep() - */ - if (sctp_ifap != NULL) { - ifa = sctp_ifap; - } else { - /* Note for BSD we hit here always other - * O/S's will pass things in via the - * sctp_ifap argument. - */ - ifa = sctp_find_ifa_by_addr(&store.sa, - vrf_id, SCTP_ADDR_NOT_LOCKED); - } - if (ifa == NULL) { - error = EADDRNOTAVAIL; - /* Can't find an interface with that address */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - /* GAK, more FIXME IFA lock? */ - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - /* Can't bind a non-existent addr. */ - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - goto out; - } - } -#endif - /* we're not bound all */ - inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUNDALL; - /* allow bindx() to send ASCONF's for binding changes */ - sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF); - /* clear automatic addr changes from kernel flag */ - sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); - - /* add this address to the endpoint list */ - error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, 0); - if (error != 0) - goto out; - inp->laddr_count++; - } - /* find the bucket */ - if (port_reuse_active) { - /* Put it into tcp 1-2-1 hash */ - head = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR(lport, SCTP_BASE_INFO(hashtcpmark))]; - inp->sctp_flags |= SCTP_PCB_FLAGS_IN_TCPPOOL; - } else { - head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(lport, SCTP_BASE_INFO(hashmark))]; - } - /* put it in the bucket */ - LIST_INSERT_HEAD(head, inp, sctp_hash); - SCTPDBG(SCTP_DEBUG_PCB1, "Main hash to bind at head:%p, bound port:%d - in tcp_pool=%d\n", - (void *)head, ntohs(lport), port_reuse_active); - /* set in the port */ - inp->sctp_lport = lport; - - /* turn off just the unbound flag */ - KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) != 0, - ("%s: inp %p is already bound", __func__, inp)); - inp->sctp_flags &= ~SCTP_PCB_FLAGS_UNBOUND; -out: - return (error); -} - -int -#if defined(__FreeBSD__) && !defined(__Userspace__) -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, struct thread *td) -#elif defined(_WIN32) && !defined(__Userspace__) -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, PKTHREAD p) -#else -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, - struct sctp_ifa *sctp_ifap, struct proc *p) -#endif -{ - struct sctp_inpcb *inp; - int error; - - inp = so->so_pcb; - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = sctp_inpcb_bind_locked(inp, addr, sctp_ifap, td); -#else - error = sctp_inpcb_bind_locked(inp, addr, sctp_ifap, p); -#endif - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return (error); -} - -static void -sctp_iterator_inp_being_freed(struct sctp_inpcb *inp) -{ - struct sctp_iterator *it, *nit; - - /* - * We enter with the only the ITERATOR_LOCK in place and a write - * lock on the inp_info stuff. - */ - it = sctp_it_ctl.cur_it; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (it && (it->vn != curvnet)) { - /* Its not looking at our VNET */ - return; - } -#endif - if (it && (it->inp == inp)) { - /* - * This is tricky and we hold the iterator lock, - * but when it returns and gets the lock (when we - * release it) the iterator will try to operate on - * inp. We need to stop that from happening. But - * of course the iterator has a reference on the - * stcb and inp. We can mark it and it will stop. - * - * If its a single iterator situation, we - * set the end iterator flag. Otherwise - * we set the iterator to go to the next inp. - * - */ - if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { - sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_STOP_CUR_IT; - } else { - sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_STOP_CUR_INP; - } - } - /* Now go through and remove any single reference to - * our inp that may be still pending on the list - */ - SCTP_IPI_ITERATOR_WQ_LOCK(); - TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (it->vn != curvnet) { - continue; - } -#endif - if (it->inp == inp) { - /* This one points to me is it inp specific? */ - if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { - /* Remove and free this one */ - TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, - it, sctp_nxt_itr); - if (it->function_atend != NULL) { - (*it->function_atend) (it->pointer, it->val); - } - SCTP_FREE(it, SCTP_M_ITER); - } else { - it->inp = LIST_NEXT(it->inp, sctp_list); - if (it->inp) { - SCTP_INP_INCR_REF(it->inp); - } - } - /* When its put in the refcnt is incremented so decr it */ - SCTP_INP_DECR_REF(inp); - } - } - SCTP_IPI_ITERATOR_WQ_UNLOCK(); -} - -/* release sctp_inpcb unbind the port */ -void -sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) -{ - /* - * Here we free a endpoint. We must find it (if it is in the Hash - * table) and remove it from there. Then we must also find it in the - * overall list and remove it from there. After all removals are - * complete then any timer has to be stopped. Then start the actual - * freeing. a) Any local lists. b) Any associations. c) The hash of - * all associations. d) finally the ep itself. - */ - struct sctp_tcb *stcb, *nstcb; - struct sctp_laddr *laddr, *nladdr; - struct inpcb *ip_pcb; - struct socket *so; - int being_refed = 0; - struct sctp_queued_to_read *sq, *nsq; -#if !defined(__Userspace__) -#if !defined(__FreeBSD__) - sctp_rtentry_t *rt; -#endif -#endif - int cnt; - sctp_sharedkey_t *shared_key, *nshared_key; - -#if defined(__APPLE__) && !defined(__Userspace__) - sctp_lock_assert(SCTP_INP_SO(inp)); -#endif -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 0); -#endif - SCTP_ITERATOR_LOCK(); - /* mark any iterators on the list or being processed */ - sctp_iterator_inp_being_freed(inp); - SCTP_ITERATOR_UNLOCK(); - - SCTP_ASOC_CREATE_LOCK(inp); - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); - so = inp->sctp_socket; - KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) != 0, - ("%s: inp %p still has socket", __func__, inp)); - KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0, - ("%s: double free of inp %p", __func__, inp)); - if (from == SCTP_CALLED_AFTER_CMPSET_OFCLOSE) { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP; - /* socket is gone, so no more wakeups allowed */ - inp->sctp_flags |= SCTP_PCB_FLAGS_DONT_WAKE; - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; - } - /* First time through we have the socket lock, after that no more. */ - sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL, - SCTP_FROM_SCTP_PCB + SCTP_LOC_1); - - if (inp->control) { - sctp_m_freem(inp->control); - inp->control = NULL; - } - if (inp->pkt) { - sctp_m_freem(inp->pkt); - inp->pkt = NULL; - } - ip_pcb = &inp->ip_inp.inp; /* we could just cast the main pointer - * here but I will be nice :> (i.e. - * ip_pcb = ep;) */ - if (immediate == SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE) { - int cnt_in_sd; - - cnt_in_sd = 0; - LIST_FOREACH_SAFE(stcb, &inp->sctp_asoc_list, sctp_tcblist, nstcb) { - SCTP_TCB_LOCK(stcb); - /* Disconnect the socket please. */ - stcb->sctp_socket = NULL; - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_CLOSED_SOCKET); - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - /* Skip guys being freed */ - cnt_in_sd++; - if (stcb->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { - /* - * Special case - we did not start a kill - * timer on the asoc due to it was not - * closed. So go ahead and start it now. - */ - SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); - } - SCTP_TCB_UNLOCK(stcb); - continue; - } - if (((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) && - (stcb->asoc.total_output_queue_size == 0)) { - /* If we have data in queue, we don't want to just - * free since the app may have done, send()/close - * or connect/send/close. And it wants the data - * to get across first. - */ - /* Just abandon things in the front states */ - if (sctp_free_assoc(inp, stcb, SCTP_PCBFREE_NOFORCE, - SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) { - cnt_in_sd++; - } - continue; - } - if ((stcb->asoc.size_on_reasm_queue > 0) || - (stcb->asoc.control_pdapi) || - (stcb->asoc.size_on_all_streams > 0) || - ((so != NULL) && (SCTP_SBAVAIL(&so->so_rcv) > 0))) { - /* Left with Data unread */ - struct mbuf *op_err; - - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3; - sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - if (sctp_free_assoc(inp, stcb, - SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_4) == 0) { - cnt_in_sd++; - } - continue; - } else if (TAILQ_EMPTY(&stcb->asoc.send_queue) && - TAILQ_EMPTY(&stcb->asoc.sent_queue) && - (stcb->asoc.stream_queue_cnt == 0)) { - if ((*stcb->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, &stcb->asoc)) { - goto abort_anyway; - } - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - struct sctp_nets *netp; - - /* - * there is nothing queued to send, - * so I send shutdown - */ - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (stcb->asoc.alternate) { - netp = stcb->asoc.alternate; - } else { - netp = stcb->asoc.primary_destination; - } - sctp_send_shutdown(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED); - } - } else { - /* mark into shutdown pending */ - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); - if ((*stcb->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, &stcb->asoc)) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - if (TAILQ_EMPTY(&stcb->asoc.send_queue) && - TAILQ_EMPTY(&stcb->asoc.sent_queue) && - (stcb->asoc.state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - abort_anyway: - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5; - sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - if (sctp_free_assoc(inp, stcb, - SCTP_PCBFREE_NOFORCE, - SCTP_FROM_SCTP_PCB + SCTP_LOC_6) == 0) { - cnt_in_sd++; - } - continue; - } else { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); - } - } - cnt_in_sd++; - SCTP_TCB_UNLOCK(stcb); - } - /* now is there some left in our SHUTDOWN state? */ - if (cnt_in_sd) { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 2); -#endif - inp->sctp_socket = NULL; - SCTP_INP_WUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return; - } - } - inp->sctp_socket = NULL; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { - /* - * ok, this guy has been bound. It's port is - * somewhere in the SCTP_BASE_INFO(hash table). Remove - * it! - */ - LIST_REMOVE(inp, sctp_hash); - inp->sctp_flags |= SCTP_PCB_FLAGS_UNBOUND; - } - - /* If there is a timer running to kill us, - * forget it, since it may have a contest - * on the INP lock.. which would cause us - * to die ... - */ - cnt = 0; - LIST_FOREACH_SAFE(stcb, &inp->sctp_asoc_list, sctp_tcblist, nstcb) { - SCTP_TCB_LOCK(stcb); - if (immediate != SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE) { - /* Disconnect the socket please */ - stcb->sctp_socket = NULL; - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_CLOSED_SOCKET); - } - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - if (stcb->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { - SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); - } - cnt++; - SCTP_TCB_UNLOCK(stcb); - continue; - } - /* Free associations that are NOT killing us */ - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) && - ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) { - struct mbuf *op_err; - - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_7; - sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - } else if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - cnt++; - SCTP_TCB_UNLOCK(stcb); - continue; - } - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - if (sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, - SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) { - cnt++; - } - } - if (cnt) { - /* Ok we have someone out there that will kill us */ -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 3); -#endif - SCTP_INP_WUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return; - } - if (SCTP_INP_LOCK_CONTENDED(inp)) - being_refed++; - if (SCTP_INP_READ_CONTENDED(inp)) - being_refed++; - if (SCTP_ASOC_CREATE_LOCK_CONTENDED(inp)) - being_refed++; - /* NOTE: 0 refcount also means no timers are referencing us. */ - if ((inp->refcount) || - (being_refed) || - (inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP)) { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 4); -#endif - sctp_timer_start(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL); - SCTP_INP_WUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return; - } - inp->sctp_ep.signature_change.type = 0; - inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_ALLGONE; - /* Remove it from the list .. last thing we need a - * lock for. - */ - LIST_REMOVE(inp, sctp_list); - SCTP_INP_WUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 5); -#endif -#if !(defined(_WIN32) || defined(__Userspace__)) -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - rt = ip_pcb->inp_route.ro_rt; -#endif -#endif - if ((inp->sctp_asocidhash) != NULL) { - SCTP_HASH_FREE(inp->sctp_asocidhash, inp->hashasocidmark); - inp->sctp_asocidhash = NULL; - } - /*sa_ignore FREED_MEMORY*/ - TAILQ_FOREACH_SAFE(sq, &inp->read_queue, next, nsq) { - /* Its only abandoned if it had data left */ - if (sq->length) - SCTP_STAT_INCR(sctps_left_abandon); - - TAILQ_REMOVE(&inp->read_queue, sq, next); - sctp_free_remote_addr(sq->whoFrom); - if (so) - SCTP_SB_DECR(&so->so_rcv, sq->length); - if (sq->data) { - sctp_m_freem(sq->data); - sq->data = NULL; - } - /* - * no need to free the net count, since at this point all - * assoc's are gone. - */ - sctp_free_a_readq(NULL, sq); - } - /* Now the sctp_pcb things */ - /* - * free each asoc if it is not already closed/free. we can't use the - * macro here since le_next will get freed as part of the - * sctp_free_assoc() call. - */ - if (ip_pcb->inp_options) { - (void)sctp_m_free(ip_pcb->inp_options); - ip_pcb->inp_options = 0; - } -#if !(defined(_WIN32) || defined(__Userspace__)) -#if !defined(__FreeBSD__) - if (rt) { - RTFREE(rt); - ip_pcb->inp_route.ro_rt = 0; - } -#endif -#endif -#ifdef INET6 -#if !(defined(_WIN32) || defined(__Userspace__)) -#if (defined(__FreeBSD__) || defined(__APPLE__) && !defined(__Userspace__)) - if (ip_pcb->inp_vflag & INP_IPV6) { -#else - if (inp->inp_vflag & INP_IPV6) { -#endif - ip6_freepcbopts(ip_pcb->in6p_outputopts); - } -#endif -#endif /* INET6 */ - ip_pcb->inp_vflag = 0; - /* free up authentication fields */ - if (inp->sctp_ep.local_auth_chunks != NULL) - sctp_free_chunklist(inp->sctp_ep.local_auth_chunks); - if (inp->sctp_ep.local_hmacs != NULL) - sctp_free_hmaclist(inp->sctp_ep.local_hmacs); - - LIST_FOREACH_SAFE(shared_key, &inp->sctp_ep.shared_keys, next, nshared_key) { - LIST_REMOVE(shared_key, next); - sctp_free_sharedkey(shared_key); - /*sa_ignore FREED_MEMORY*/ - } - -#if defined(__APPLE__) && !defined(__Userspace__) - inp->ip_inp.inp.inp_state = INPCB_STATE_DEAD; - if (in_pcb_checkstate(&inp->ip_inp.inp, WNT_STOPUSING, 1) != WNT_STOPUSING) { -#ifdef INVARIANTS - panic("sctp_inpcb_free inp = %p couldn't set to STOPUSING", (void *)inp); -#else - SCTP_PRINTF("sctp_inpcb_free inp = %p couldn't set to STOPUSING\n", (void *)inp); -#endif - } - inp->ip_inp.inp.inp_socket->so_flags |= SOF_PCBCLEARING; -#endif - /* - * if we have an address list the following will free the list of - * ifaddr's that are set into this ep. Again macro limitations here, - * since the LIST_FOREACH could be a bad idea. - */ - LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { - sctp_remove_laddr(laddr); - } - -#ifdef SCTP_TRACK_FREED_ASOCS - /* TEMP CODE */ - LIST_FOREACH_SAFE(stcb, &inp->sctp_asoc_free_list, sctp_tcblist, nstcb) { - LIST_REMOVE(stcb, sctp_tcblist); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_DECR_ASOC_COUNT(); - } - /* *** END TEMP CODE ****/ -#endif -#ifdef SCTP_MVRF - SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF); -#endif - /* Now lets see about freeing the EP hash table. */ - if (inp->sctp_tcbhash != NULL) { - SCTP_HASH_FREE(inp->sctp_tcbhash, inp->sctp_hashmark); - inp->sctp_tcbhash = NULL; - } - /* Now we must put the ep memory back into the zone pool */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - crfree(inp->ip_inp.inp.inp_cred); - INP_LOCK_DESTROY(&inp->ip_inp.inp); -#endif - SCTP_INP_LOCK_DESTROY(inp); - SCTP_INP_READ_LOCK_DESTROY(inp); - SCTP_ASOC_CREATE_LOCK_DESTROY(inp); -#if !(defined(__APPLE__) && !defined(__Userspace__)) - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); - SCTP_DECR_EP_COUNT(); -#else - /* For Tiger, we will do this later... */ -#endif -} - -struct sctp_nets * -sctp_findnet(struct sctp_tcb *stcb, struct sockaddr *addr) -{ - struct sctp_nets *net; - /* locate the address */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (sctp_cmpaddr(addr, (struct sockaddr *)&net->ro._l_addr)) - return (net); - } - return (NULL); -} - -int -sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id) -{ - struct sctp_ifa *sctp_ifa; - sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, SCTP_ADDR_NOT_LOCKED); - if (sctp_ifa) { - return (1); - } else { - return (0); - } -} - -/* - * add's a remote endpoint address, done with the INIT/INIT-ACK as well as - * when a ASCONF arrives that adds it. It will also initialize all the cwnd - * stats of stuff. - */ -int -sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, - struct sctp_nets **netp, uint16_t port, int set_scope, int from) -{ - /* - * The following is redundant to the same lines in the - * sctp_aloc_assoc() but is needed since others call the add - * address function - */ - struct sctp_nets *net, *netfirst; - int addr_inscope; - - SCTPDBG(SCTP_DEBUG_PCB1, "Adding an address (from:%d) to the peer: ", - from); - SCTPDBG_ADDR(SCTP_DEBUG_PCB1, newaddr); - - netfirst = sctp_findnet(stcb, newaddr); - if (netfirst) { - /* - * Lie and return ok, we don't want to make the association - * go away for this behavior. It will happen in the TCP - * model in a connected socket. It does not reach the hash - * table until after the association is built so it can't be - * found. Mark as reachable, since the initial creation will - * have been cleared and the NOT_IN_ASSOC flag will have - * been added... and we don't want to end up removing it - * back out. - */ - if (netfirst->dest_state & SCTP_ADDR_UNCONFIRMED) { - netfirst->dest_state = (SCTP_ADDR_REACHABLE | - SCTP_ADDR_UNCONFIRMED); - } else { - netfirst->dest_state = SCTP_ADDR_REACHABLE; - } - - return (0); - } - addr_inscope = 1; - switch (newaddr->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)newaddr; - if (sin->sin_addr.s_addr == 0) { - /* Invalid address */ - return (-1); - } - /* zero out the zero area */ - memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); - - /* assure len is set */ -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - if (set_scope) { - if (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { - stcb->asoc.scope.ipv4_local_scope = 1; - } - } else { - /* Validate the address is in scope */ - if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) && - (stcb->asoc.scope.ipv4_local_scope == 0)) { - addr_inscope = 0; - } - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)newaddr; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* Invalid address */ - return (-1); - } - /* assure len is set */ -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(struct sockaddr_in6); -#endif - if (set_scope) { - if (sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id)) { - stcb->asoc.scope.loopback_scope = 1; - stcb->asoc.scope.local_scope = 0; - stcb->asoc.scope.ipv4_local_scope = 1; - stcb->asoc.scope.site_scope = 1; - } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - /* - * If the new destination is a LINK_LOCAL we - * must have common site scope. Don't set - * the local scope since we may not share - * all links, only loopback can do this. - * Links on the local network would also be - * on our private network for v4 too. - */ - stcb->asoc.scope.ipv4_local_scope = 1; - stcb->asoc.scope.site_scope = 1; - } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - /* - * If the new destination is SITE_LOCAL then - * we must have site scope in common. - */ - stcb->asoc.scope.site_scope = 1; - } - } else { - /* Validate the address is in scope */ - if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && - (stcb->asoc.scope.loopback_scope == 0)) { - addr_inscope = 0; - } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && - (stcb->asoc.scope.local_scope == 0)) { - addr_inscope = 0; - } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && - (stcb->asoc.scope.site_scope == 0)) { - addr_inscope = 0; - } - } - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)newaddr; - if (sconn->sconn_addr == NULL) { - /* Invalid address */ - return (-1); - } -#ifdef HAVE_SCONN_LEN - sconn->sconn_len = sizeof(struct sockaddr_conn); -#endif - break; - } -#endif - default: - /* not supported family type */ - return (-1); - } - net = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_net), struct sctp_nets); - if (net == NULL) { - return (-1); - } - SCTP_INCR_RADDR_COUNT(); - memset(net, 0, sizeof(struct sctp_nets)); - (void)SCTP_GETTIME_TIMEVAL(&net->start_time); -#ifdef HAVE_SA_LEN - memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len); -#endif - switch (newaddr->sa_family) { -#ifdef INET - case AF_INET: -#ifndef HAVE_SA_LEN - memcpy(&net->ro._l_addr, newaddr, sizeof(struct sockaddr_in)); -#endif - ((struct sockaddr_in *)&net->ro._l_addr)->sin_port = stcb->rport; - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifndef HAVE_SA_LEN - memcpy(&net->ro._l_addr, newaddr, sizeof(struct sockaddr_in6)); -#endif - ((struct sockaddr_in6 *)&net->ro._l_addr)->sin6_port = stcb->rport; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: -#ifndef HAVE_SA_LEN - memcpy(&net->ro._l_addr, newaddr, sizeof(struct sockaddr_conn)); -#endif - ((struct sockaddr_conn *)&net->ro._l_addr)->sconn_port = stcb->rport; - break; -#endif - default: - break; - } - net->addr_is_local = sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id); - if (net->addr_is_local && ((set_scope || (from == SCTP_ADDR_IS_CONFIRMED)))) { - stcb->asoc.scope.loopback_scope = 1; - stcb->asoc.scope.ipv4_local_scope = 1; - stcb->asoc.scope.local_scope = 0; - stcb->asoc.scope.site_scope = 1; - addr_inscope = 1; - } - net->failure_threshold = stcb->asoc.def_net_failure; - net->pf_threshold = stcb->asoc.def_net_pf_threshold; - if (addr_inscope == 0) { - net->dest_state = (SCTP_ADDR_REACHABLE | - SCTP_ADDR_OUT_OF_SCOPE); - } else { - if (from == SCTP_ADDR_IS_CONFIRMED) - /* SCTP_ADDR_IS_CONFIRMED is passed by connect_x */ - net->dest_state = SCTP_ADDR_REACHABLE; - else - net->dest_state = SCTP_ADDR_REACHABLE | - SCTP_ADDR_UNCONFIRMED; - } - /* We set this to 0, the timer code knows that - * this means its an initial value - */ - net->rto_needed = 1; - net->RTO = 0; - net->RTO_measured = 0; - stcb->asoc.numnets++; - net->ref_count = 1; - net->cwr_window_tsn = net->last_cwr_tsn = stcb->asoc.sending_seq - 1; - net->port = port; - net->dscp = stcb->asoc.default_dscp; -#ifdef INET6 - net->flowlabel = stcb->asoc.default_flowlabel; -#endif - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { - net->dest_state |= SCTP_ADDR_NOHB; - } else { - net->dest_state &= ~SCTP_ADDR_NOHB; - } - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { - net->dest_state |= SCTP_ADDR_NO_PMTUD; - } else { - net->dest_state &= ~SCTP_ADDR_NO_PMTUD; - } - net->heart_beat_delay = stcb->asoc.heart_beat_delay; - /* Init the timer structure */ - SCTP_OS_TIMER_INIT(&net->rxt_timer.timer); - SCTP_OS_TIMER_INIT(&net->pmtu_timer.timer); - SCTP_OS_TIMER_INIT(&net->hb_timer.timer); - - /* Now generate a route for this guy */ -#ifdef INET6 -#ifdef SCTP_EMBEDDED_V6_SCOPE - /* KAME hack: embed scopeid */ - if (newaddr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - (void)in6_embedscope(&sin6->sin6_addr, sin6, &stcb->sctp_ep->ip_inp.inp, NULL); -#else - (void)in6_embedscope(&sin6->sin6_addr, sin6, &stcb->sctp_ep->ip_inp.inp, NULL, NULL); -#endif -#elif defined(SCTP_KAME) - (void)sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)); -#else - (void)in6_embedscope(&sin6->sin6_addr, sin6); -#endif -#ifndef SCOPEDROUTING - sin6->sin6_scope_id = 0; -#endif - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#endif - SCTP_RTALLOC((sctp_route_t *)&net->ro, - stcb->asoc.vrf_id, - stcb->sctp_ep->fibnum); - - net->src_addr_selected = 0; -#if !defined(__Userspace__) - if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro)) { - /* Get source address */ - net->ro._s_addr = sctp_source_address_selection(stcb->sctp_ep, - stcb, - (sctp_route_t *)&net->ro, - net, - 0, - stcb->asoc.vrf_id); - if (stcb->asoc.default_mtu > 0) { - net->mtu = stcb->asoc.default_mtu; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - net->mtu += SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - net->mtu += SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - net->mtu += sizeof(struct sctphdr); - break; -#endif - default: - break; - } -#if defined(INET) || defined(INET6) - if (net->port) { - net->mtu += (uint32_t)sizeof(struct udphdr); - } -#endif - } else if (net->ro._s_addr != NULL) { - uint32_t imtu, rmtu, hcmtu; - - net->src_addr_selected = 1; - /* Now get the interface MTU */ - if (net->ro._s_addr->ifn_p != NULL) { - /* - * XXX: Should we here just use - * net->ro._s_addr->ifn_p->ifn_mtu - */ - imtu = SCTP_GATHER_MTU_FROM_IFN_INFO(net->ro._s_addr->ifn_p->ifn_p, - net->ro._s_addr->ifn_p->ifn_index); - } else { - imtu = 0; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_nh); - hcmtu = sctp_hc_get_mtu(&net->ro._l_addr, stcb->sctp_ep->fibnum); -#else - rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt); - hcmtu = 0; -#endif - net->mtu = sctp_min_mtu(hcmtu, rmtu, imtu); -#if defined(__FreeBSD__) && !defined(__Userspace__) -#else - if (rmtu == 0) { - /* Start things off to match mtu of interface please. */ - SCTP_SET_MTU_OF_ROUTE(&net->ro._l_addr.sa, - net->ro.ro_rt, net->mtu); - } -#endif - } - } -#endif - if (net->mtu == 0) { - if (stcb->asoc.default_mtu > 0) { - net->mtu = stcb->asoc.default_mtu; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - net->mtu += SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - net->mtu += SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - net->mtu += sizeof(struct sctphdr); - break; -#endif - default: - break; - } -#if defined(INET) || defined(INET6) - if (net->port) { - net->mtu += (uint32_t)sizeof(struct udphdr); - } -#endif - } else { - switch (newaddr->sa_family) { -#ifdef INET - case AF_INET: - net->mtu = SCTP_DEFAULT_MTU; - break; -#endif -#ifdef INET6 - case AF_INET6: - net->mtu = 1280; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - net->mtu = 1280; - break; -#endif - default: - break; - } - } - } -#if defined(INET) || defined(INET6) - if (net->port) { - net->mtu -= (uint32_t)sizeof(struct udphdr); - } -#endif - if (from == SCTP_ALLOC_ASOC) { - stcb->asoc.smallest_mtu = net->mtu; - } - if (stcb->asoc.smallest_mtu > net->mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu, true); - } -#ifdef INET6 -#ifdef SCTP_EMBEDDED_V6_SCOPE - if (newaddr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; -#ifdef SCTP_KAME - (void)sa6_recoverscope(sin6); -#else - (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); -#endif /* SCTP_KAME */ - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#endif - - /* JRS - Use the congestion control given in the CC module */ - if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) - (*stcb->asoc.cc_functions.sctp_set_initial_cc_param)(stcb, net); - - /* - * CMT: CUC algo - set find_pseudo_cumack to TRUE (1) at beginning - * of assoc (2005/06/27, iyengar@cis.udel.edu) - */ - net->find_pseudo_cumack = 1; - net->find_rtx_pseudo_cumack = 1; -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* Choose an initial flowid. */ - net->flowid = stcb->asoc.my_vtag ^ - ntohs(stcb->rport) ^ - ntohs(stcb->sctp_ep->sctp_lport); - net->flowtype = M_HASHTYPE_OPAQUE_HASH; -#endif - if (netp) { - *netp = net; - } - netfirst = TAILQ_FIRST(&stcb->asoc.nets); -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net->ro.ro_nh == NULL) { -#else - if (net->ro.ro_rt == NULL) { -#endif - /* Since we have no route put it at the back */ - TAILQ_INSERT_TAIL(&stcb->asoc.nets, net, sctp_next); - } else if (netfirst == NULL) { - /* We are the first one in the pool. */ - TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next); -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else if (netfirst->ro.ro_nh == NULL) { -#else - } else if (netfirst->ro.ro_rt == NULL) { -#endif - /* - * First one has NO route. Place this one ahead of the first - * one. - */ - TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next); -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else if (net->ro.ro_nh->nh_ifp != netfirst->ro.ro_nh->nh_ifp) { -#else - } else if (net->ro.ro_rt->rt_ifp != netfirst->ro.ro_rt->rt_ifp) { -#endif - /* - * This one has a different interface than the one at the - * top of the list. Place it ahead. - */ - TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next); - } else { - /* - * Ok we have the same interface as the first one. Move - * forward until we find either a) one with a NULL route... - * insert ahead of that b) one with a different ifp.. insert - * after that. c) end of the list.. insert at the tail. - */ - struct sctp_nets *netlook; - - do { - netlook = TAILQ_NEXT(netfirst, sctp_next); - if (netlook == NULL) { - /* End of the list */ - TAILQ_INSERT_TAIL(&stcb->asoc.nets, net, sctp_next); - break; -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else if (netlook->ro.ro_nh == NULL) { -#else - } else if (netlook->ro.ro_rt == NULL) { -#endif - /* next one has NO route */ - TAILQ_INSERT_BEFORE(netfirst, net, sctp_next); - break; -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else if (netlook->ro.ro_nh->nh_ifp != net->ro.ro_nh->nh_ifp) { -#else - } else if (netlook->ro.ro_rt->rt_ifp != net->ro.ro_rt->rt_ifp) { -#endif - TAILQ_INSERT_AFTER(&stcb->asoc.nets, netlook, - net, sctp_next); - break; - } - /* Shift forward */ - netfirst = netlook; - } while (netlook != NULL); - } - - /* got to have a primary set */ - if (stcb->asoc.primary_destination == 0) { - stcb->asoc.primary_destination = net; -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else if ((stcb->asoc.primary_destination->ro.ro_nh == NULL) && - (net->ro.ro_nh) && -#else - } else if ((stcb->asoc.primary_destination->ro.ro_rt == NULL) && - (net->ro.ro_rt) && -#endif - ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) { - /* No route to current primary adopt new primary */ - stcb->asoc.primary_destination = net; - } - /* Validate primary is first */ - net = TAILQ_FIRST(&stcb->asoc.nets); - if ((net != stcb->asoc.primary_destination) && - (stcb->asoc.primary_destination)) { - /* first one on the list is NOT the primary - * sctp_cmpaddr() is much more efficient if - * the primary is the first on the list, make it - * so. - */ - TAILQ_REMOVE(&stcb->asoc.nets, - stcb->asoc.primary_destination, sctp_next); - TAILQ_INSERT_HEAD(&stcb->asoc.nets, - stcb->asoc.primary_destination, sctp_next); - } - return (0); -} - -static uint32_t -sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb) -{ - uint32_t id; - struct sctpasochead *head; - struct sctp_tcb *lstcb; - - try_again: - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - /* TSNH */ - return (0); - } - /* - * We don't allow assoc id to be one of SCTP_FUTURE_ASSOC, - * SCTP_CURRENT_ASSOC and SCTP_ALL_ASSOC. - */ - if (inp->sctp_associd_counter <= SCTP_ALL_ASSOC) { - inp->sctp_associd_counter = SCTP_ALL_ASSOC + 1; - } - id = inp->sctp_associd_counter; - inp->sctp_associd_counter++; - lstcb = sctp_findasoc_ep_asocid_locked(inp, (sctp_assoc_t)id, 0); - if (lstcb) { - goto try_again; - } - head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)]; - LIST_INSERT_HEAD(head, stcb, sctp_tcbasocidhash); - stcb->asoc.in_asocid_hash = 1; - return (id); -} - -/* - * allocate an association and add it to the endpoint. The caller must be - * careful to add all additional addresses once they are know right away or - * else the assoc will be may experience a blackout scenario. - */ -static struct sctp_tcb * -sctp_aloc_assoc_locked(struct sctp_inpcb *inp, struct sockaddr *firstaddr, - int *error, uint32_t override_tag, uint32_t initial_tsn, - uint32_t vrf_id, uint16_t o_streams, uint16_t port, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p, -#elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p, -#else -#if defined(__Userspace__) - /* __Userspace__ NULL proc is going to be passed here. See sctp_lower_sosend */ -#endif - struct proc *p, -#endif - int initialize_auth_params) -{ - /* note the p argument is only valid in unbound sockets */ - - struct sctp_tcb *stcb; - struct sctp_association *asoc; - struct sctpasochead *head; - uint16_t rport; - int err; - - SCTP_INP_INFO_WLOCK_ASSERT(); - SCTP_INP_WLOCK_ASSERT(inp); - - /* - * Assumption made here: Caller has done a - * sctp_findassociation_ep_addr(ep, addr's); to make sure the - * address does not exist already. - */ - if (SCTP_BASE_INFO(ipi_count_asoc) >= SCTP_MAX_NUM_OF_ASOC) { - /* Hit max assoc, sorry no more */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); - *error = ENOBUFS; - return (NULL); - } - if (firstaddr == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && - ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) || - (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { - /* - * If its in the TCP pool, its NOT allowed to create an - * association. The parent listener needs to call - * sctp_aloc_assoc.. or the one-2-many socket. If a peeled - * off, or connected one does this.. its an error. - */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || - (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - } - SCTPDBG(SCTP_DEBUG_PCB3, "Allocate an association for peer:"); -#ifdef SCTP_DEBUG - if (firstaddr) { - SCTPDBG_ADDR(SCTP_DEBUG_PCB3, firstaddr); - switch (firstaddr->sa_family) { -#ifdef INET - case AF_INET: - SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n", - ntohs(((struct sockaddr_in *)firstaddr)->sin_port)); - break; -#endif -#ifdef INET6 - case AF_INET6: - SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n", - ntohs(((struct sockaddr_in6 *)firstaddr)->sin6_port)); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n", - ntohs(((struct sockaddr_conn *)firstaddr)->sconn_port)); - break; -#endif - default: - break; - } - } else { - SCTPDBG(SCTP_DEBUG_PCB3,"None\n"); - } -#endif /* SCTP_DEBUG */ - switch (firstaddr->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)firstaddr; - if ((ntohs(sin->sin_port) == 0) || - (sin->sin_addr.s_addr == INADDR_ANY) || - (sin->sin_addr.s_addr == INADDR_BROADCAST) || - IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) || -#if defined(__Userspace__) - ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - (SCTP_IPV6_V6ONLY(inp) != 0)))) { -#else - ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - (SCTP_IPV6_V6ONLY(inp) != 0))) { -#endif - /* Invalid address */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - rport = sin->sin_port; - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)firstaddr; - if ((ntohs(sin6->sin6_port) == 0) || - IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || - IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)) { - /* Invalid address */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - rport = sin6->sin6_port; - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)firstaddr; - if ((ntohs(sconn->sconn_port) == 0) || - (sconn->sconn_addr == NULL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) == 0)) { - /* Invalid address */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - rport = sconn->sconn_port; - break; - } -#endif - default: - /* not supported family type */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { - /* - * If you have not performed a bind, then we need to do the - * ephemeral bind for you. - */ - if ((err = sctp_inpcb_bind_locked(inp, NULL, NULL, p))) { - /* bind error, probably perm */ - *error = err; - return (NULL); - } - } - stcb = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asoc), struct sctp_tcb); - if (stcb == NULL) { - /* out of memory? */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM); - *error = ENOMEM; - return (NULL); - } - SCTP_INCR_ASOC_COUNT(); - - memset(stcb, 0, sizeof(*stcb)); - asoc = &stcb->asoc; - - SCTP_TCB_LOCK_INIT(stcb); - stcb->rport = rport; - /* setup back pointer's */ - stcb->sctp_ep = inp; - stcb->sctp_socket = inp->sctp_socket; - if ((err = sctp_init_asoc(inp, stcb, override_tag, initial_tsn, vrf_id, o_streams))) { - /* failed */ - SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_DECR_ASOC_COUNT(); - *error = err; - return (NULL); - } - SCTP_TCB_LOCK(stcb); - - asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb); - /* now that my_vtag is set, add it to the hash */ - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; - /* put it in the bucket in the vtag hash of assoc's for the system */ - LIST_INSERT_HEAD(head, stcb, sctp_asocs); - - if (sctp_add_remote_addr(stcb, firstaddr, NULL, port, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC)) { - /* failure.. memory error? */ - if (asoc->strmout) { - SCTP_FREE(asoc->strmout, SCTP_M_STRMO); - asoc->strmout = NULL; - } - if (asoc->mapping_array) { - SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); - asoc->mapping_array = NULL; - } - if (asoc->nr_mapping_array) { - SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); - asoc->nr_mapping_array = NULL; - } - SCTP_DECR_ASOC_COUNT(); - SCTP_TCB_UNLOCK(stcb); - SCTP_TCB_LOCK_DESTROY(stcb); - LIST_REMOVE(stcb, sctp_asocs); - LIST_REMOVE(stcb, sctp_tcbasocidhash); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_INP_WUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); - *error = ENOBUFS; - return (NULL); - } - /* Init all the timers */ - SCTP_OS_TIMER_INIT(&asoc->dack_timer.timer); - SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer); - SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer); - SCTP_OS_TIMER_INIT(&asoc->shut_guard_timer.timer); - SCTP_OS_TIMER_INIT(&asoc->autoclose_timer.timer); - SCTP_OS_TIMER_INIT(&asoc->delete_prim_timer.timer); - - LIST_INSERT_HEAD(&inp->sctp_asoc_list, stcb, sctp_tcblist); - /* now file the port under the hash as well */ - if (inp->sctp_tcbhash != NULL) { - head = &inp->sctp_tcbhash[SCTP_PCBHASH_ALLADDR(stcb->rport, - inp->sctp_hashmark)]; - LIST_INSERT_HEAD(head, stcb, sctp_tcbhash); - } - if (initialize_auth_params == SCTP_INITIALIZE_AUTH_PARAMS) { - sctp_initialize_auth_params(inp, stcb); - } - SCTPDBG(SCTP_DEBUG_PCB1, "Association %p now allocated\n", (void *)stcb); - return (stcb); -} - -struct sctp_tcb * -sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, - int *error, uint32_t override_tag, uint32_t initial_tsn, - uint32_t vrf_id, uint16_t o_streams, uint16_t port, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p, -#elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p, -#else - struct proc *p, -#endif - int initialize_auth_params) -{ - struct sctp_tcb *stcb; - - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); - stcb = sctp_aloc_assoc_locked(inp, firstaddr, error, override_tag, - initial_tsn, vrf_id, o_streams, port, p, initialize_auth_params); - SCTP_INP_INFO_WUNLOCK(); - SCTP_INP_WUNLOCK(inp); - return (stcb); -} - -struct sctp_tcb * -sctp_aloc_assoc_connected(struct sctp_inpcb *inp, struct sockaddr *firstaddr, - int *error, uint32_t override_tag, uint32_t initial_tsn, - uint32_t vrf_id, uint16_t o_streams, uint16_t port, -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *p, -#elif defined(_WIN32) && !defined(__Userspace__) - PKTHREAD p, -#else - struct proc *p, -#endif - int initialize_auth_params) -{ - struct sctp_tcb *stcb; - - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - SCTP_IS_LISTENING(inp)) { - SCTP_INP_INFO_WUNLOCK(); - SCTP_INP_WUNLOCK(inp); - *error = EINVAL; - return (NULL); - } - stcb = sctp_aloc_assoc_locked(inp, firstaddr, error, override_tag, - initial_tsn, vrf_id, o_streams, port, p, initialize_auth_params); - SCTP_INP_INFO_WUNLOCK(); - if (stcb != NULL && (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { - inp->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; - soisconnecting(inp->sctp_socket); - } - SCTP_INP_WUNLOCK(inp); - return (stcb); -} - -void -sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net) -{ - struct sctp_inpcb *inp; - struct sctp_association *asoc; - - inp = stcb->sctp_ep; - asoc = &stcb->asoc; - asoc->numnets--; - TAILQ_REMOVE(&asoc->nets, net, sctp_next); - if (net == asoc->primary_destination) { - /* Reset primary */ - struct sctp_nets *lnet; - - lnet = TAILQ_FIRST(&asoc->nets); - /* Mobility adaptation - Ideally, if deleted destination is the primary, it becomes - a fast retransmission trigger by the subsequent SET PRIMARY. - (by micchie) - */ - if (sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_BASE) || - sctp_is_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_FASTHANDOFF)) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: primary dst is deleting\n"); - if (asoc->deleted_primary != NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: deleted primary may be already stored\n"); - goto out; - } - asoc->deleted_primary = net; - atomic_add_int(&net->ref_count, 1); - memset(&net->lastsa, 0, sizeof(net->lastsa)); - memset(&net->lastsv, 0, sizeof(net->lastsv)); - sctp_mobility_feature_on(stcb->sctp_ep, - SCTP_MOBILITY_PRIM_DELETED); - sctp_timer_start(SCTP_TIMER_TYPE_PRIM_DELETED, - stcb->sctp_ep, stcb, NULL); - } -out: - /* Try to find a confirmed primary */ - asoc->primary_destination = sctp_find_alternate_net(stcb, lnet, 0); - } - if (net == asoc->last_data_chunk_from) { - /* Reset primary */ - asoc->last_data_chunk_from = TAILQ_FIRST(&asoc->nets); - } - if (net == asoc->last_control_chunk_from) { - /* Clear net */ - asoc->last_control_chunk_from = NULL; - } - if (net == asoc->last_net_cmt_send_started) { - /* Clear net */ - asoc->last_net_cmt_send_started = NULL; - } - if (net == stcb->asoc.alternate) { - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_PCB + SCTP_LOC_9); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_PCB + SCTP_LOC_10); - net->dest_state |= SCTP_ADDR_BEING_DELETED; - sctp_free_remote_addr(net); -} - -/* - * remove a remote endpoint address from an association, it will fail if the - * address does not exist. - */ -int -sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr) -{ - /* - * Here we need to remove a remote address. This is quite simple, we - * first find it in the list of address for the association - * (tasoc->asoc.nets) and then if it is there, we do a LIST_REMOVE - * on that item. Note we do not allow it to be removed if there are - * no other addresses. - */ - struct sctp_association *asoc; - struct sctp_nets *net, *nnet; - - asoc = &stcb->asoc; - - /* locate the address */ - TAILQ_FOREACH_SAFE(net, &asoc->nets, sctp_next, nnet) { - if (net->ro._l_addr.sa.sa_family != remaddr->sa_family) { - continue; - } - if (sctp_cmpaddr((struct sockaddr *)&net->ro._l_addr, - remaddr)) { - /* we found the guy */ - if (asoc->numnets < 2) { - /* Must have at LEAST two remote addresses */ - return (-1); - } else { - sctp_remove_net(stcb, net); - return (0); - } - } - } - /* not found. */ - return (-2); -} - -static bool -sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport, uint32_t now) -{ - struct sctpvtaghead *chain; - struct sctp_tagblock *twait_block; - int i; - - SCTP_INP_INFO_LOCK_ASSERT(); - chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; - LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { - for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { - if ((twait_block->vtag_block[i].tv_sec_at_expire >= now) && - (twait_block->vtag_block[i].v_tag == tag) && - (twait_block->vtag_block[i].lport == lport) && - (twait_block->vtag_block[i].rport == rport)) { - return (true); - } - } - } - return (false); -} - -static void -sctp_set_vtag_block(struct sctp_timewait *vtag_block, uint32_t time, - uint32_t tag, uint16_t lport, uint16_t rport) -{ - vtag_block->tv_sec_at_expire = time; - vtag_block->v_tag = tag; - vtag_block->lport = lport; - vtag_block->rport = rport; -} - -static void -sctp_add_vtag_to_timewait(uint32_t tag, uint16_t lport, uint16_t rport) -{ - struct sctpvtaghead *chain; - struct sctp_tagblock *twait_block; - struct timeval now; - uint32_t time; - int i; - bool set; - - SCTP_INP_INFO_WLOCK_ASSERT(); - (void)SCTP_GETTIME_TIMEVAL(&now); - time = (uint32_t)now.tv_sec + SCTP_BASE_SYSCTL(sctp_vtag_time_wait); - chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; - set = false; - LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { - /* Block(s) present, lets find space, and expire on the fly */ - for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { - if ((twait_block->vtag_block[i].v_tag == 0) && !set) { - sctp_set_vtag_block(twait_block->vtag_block + i, time, tag, lport, rport); - set = true; - continue; - } - if ((twait_block->vtag_block[i].v_tag != 0) && - (twait_block->vtag_block[i].tv_sec_at_expire < (uint32_t)now.tv_sec)) { - if (set) { - /* Audit expires this guy */ - sctp_set_vtag_block(twait_block->vtag_block + i, 0, 0, 0, 0); - } else { - /* Reuse it for the new tag */ - sctp_set_vtag_block(twait_block->vtag_block + i, time, tag, lport, rport); - set = true; - } - } - } - if (set) { - /* - * We only do up to the block where we can - * place our tag for audits - */ - break; - } - } - /* Need to add a new block to chain */ - if (!set) { - SCTP_MALLOC(twait_block, struct sctp_tagblock *, - sizeof(struct sctp_tagblock), SCTP_M_TIMW); - if (twait_block == NULL) { - return; - } - memset(twait_block, 0, sizeof(struct sctp_tagblock)); - LIST_INSERT_HEAD(chain, twait_block, sctp_nxt_tagblock); - sctp_set_vtag_block(twait_block->vtag_block, time, tag, lport, rport); - } -} - -void -sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh) -{ - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_queued_to_read *control, *ncontrol; - - TAILQ_FOREACH_SAFE(control, rh, next_instrm, ncontrol) { - TAILQ_REMOVE(rh, control, next_instrm); - control->on_strm_q = 0; - if (control->on_read_q == 0) { - sctp_free_remote_addr(control->whoFrom); - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - } - /* Reassembly free? */ - TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /*sa_ignore FREED_MEMORY*/ - } - /* - * We don't free the address here - * since all the net's were freed - * above. - */ - if (control->on_read_q == 0) { - sctp_free_a_readq(stcb, control); - } - } -} - -/*- - * Free the association after un-hashing the remote port. This - * function ALWAYS returns holding NO LOCK on the stcb. It DOES - * expect that the input to this function IS a locked TCB. - * It will return 0, if it did NOT destroy the association (instead - * it unlocks it. It will return NON-zero if it either destroyed the - * association OR the association is already destroyed. - */ -int -sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfree, int from_location) -{ - int i; - struct sctp_association *asoc; - struct sctp_nets *net, *nnet; - struct sctp_laddr *laddr, *naddr; - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_asconf_addr *aparam, *naparam; - struct sctp_asconf_ack *aack, *naack; - struct sctp_stream_reset_list *strrst, *nstrrst; - struct sctp_queued_to_read *sq, *nsq; - struct sctp_stream_queue_pending *sp, *nsp; - sctp_sharedkey_t *shared_key, *nshared_key; - struct socket *so; - - /* first, lets purge the entry from the hash table. */ -#if defined(__APPLE__) && !defined(__Userspace__) - sctp_lock_assert(SCTP_INP_SO(inp)); -#endif - SCTP_TCB_LOCK_ASSERT(stcb); - -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, stcb, 6); -#endif - if (stcb->asoc.state == 0) { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 7); -#endif - /* there is no asoc, really TSNH :-0 */ - return (1); - } - if (stcb->asoc.alternate) { - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } -#if !(defined(__APPLE__) && !defined(__Userspace__)) - /* TEMP CODE */ - if (stcb->freed_from_where == 0) { - /* Only record the first place free happened from */ - stcb->freed_from_where = from_location; - } - /* TEMP CODE */ -#endif - - asoc = &stcb->asoc; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) - /* nothing around */ - so = NULL; - else - so = inp->sctp_socket; - - /* - * We used timer based freeing if a reader or writer is in the way. - * So we first check if we are actually being called from a timer, - * if so we abort early if a reader or writer is still in the way. - */ - if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) && - (from_inpcbfree == SCTP_NORMAL_PROC)) { - /* - * is it the timer driving us? if so are the reader/writers - * gone? - */ - if (stcb->asoc.refcnt) { - /* nope, reader or writer in the way */ - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); - /* no asoc destroyed */ - SCTP_TCB_UNLOCK(stcb); -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, stcb, 8); -#endif - return (0); - } - } - /* Now clean up any other timers */ - sctp_stop_association_timers(stcb, false); - /* Now the read queue needs to be cleaned up (only once) */ - if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_ABOUT_TO_BE_FREED); - SCTP_INP_READ_LOCK(inp); - TAILQ_FOREACH(sq, &inp->read_queue, next) { - if (sq->stcb == stcb) { - sq->do_not_ref_stcb = 1; - sq->sinfo_cumtsn = stcb->asoc.cumulative_tsn; - /* If there is no end, there never - * will be now. - */ - if (sq->end_added == 0) { - /* Held for PD-API clear that. */ - sq->pdapi_aborted = 1; - sq->held_length = 0; - if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) { - /* - * Need to add a PD-API aborted indication. - * Setting the control_pdapi assures that it will - * be added right after this msg. - */ - sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, - stcb, - SCTP_PARTIAL_DELIVERY_ABORTED, - (void *)sq, - SCTP_SO_LOCKED); - } - /* Add an end to wake them */ - sq->end_added = 1; - } - } - } - SCTP_INP_READ_UNLOCK(inp); - if (stcb->block_entry) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PCB, ECONNRESET); - stcb->block_entry->error = ECONNRESET; - stcb->block_entry = NULL; - } - } - if ((stcb->asoc.refcnt) || (stcb->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE)) { - /* Someone holds a reference OR the socket is unaccepted yet. - */ - if ((stcb->asoc.refcnt) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { - SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) - /* nothing around */ - so = NULL; - if (so) { - /* Wake any reader/writers */ - sctp_sorwakeup(inp, so); - sctp_sowwakeup(inp, so); - } - SCTP_TCB_UNLOCK(stcb); - -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, stcb, 9); -#endif - /* no asoc destroyed */ - return (0); - } -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, stcb, 10); -#endif - /* When I reach here, no others want - * to kill the assoc yet.. and I own - * the lock. Now its possible an abort - * comes in when I do the lock exchange - * below to grab all the locks to do - * the final take out. to prevent this - * we increment the count, which will - * start a timer and blow out above thus - * assuring us that we hold exclusive - * killing of the asoc. Note that - * after getting back the TCB lock - * we will go ahead and increment the - * counter back up and stop any timer - * a passing stranger may have started :-S - */ - if (from_inpcbfree == SCTP_NORMAL_PROC) { - atomic_add_int(&stcb->asoc.refcnt, 1); - - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); - SCTP_TCB_LOCK(stcb); - } - /* Double check the GONE flag */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) - /* nothing around */ - so = NULL; - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* - * For TCP type we need special handling when we are - * connected. We also include the peel'ed off ones to. - */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_CONNECTED; - inp->sctp_flags |= SCTP_PCB_FLAGS_WAS_CONNECTED; - if (so) { - SOCKBUF_LOCK(&so->so_rcv); - so->so_state &= ~(SS_ISCONNECTING | - SS_ISDISCONNECTING | - SS_ISCONFIRMING | - SS_ISCONNECTED); - so->so_state |= SS_ISDISCONNECTED; -#if defined(__APPLE__) && !defined(__Userspace__) - socantrcvmore(so); -#else - socantrcvmore_locked(so); -#endif - socantsendmore(so); - sctp_sowwakeup(inp, so); - sctp_sorwakeup(inp, so); - SCTP_SOWAKEUP(so); - } - } - } - - /* Make it invalid too, that way if its - * about to run it will abort and return. - */ - /* re-increment the lock */ - if (from_inpcbfree == SCTP_NORMAL_PROC) { - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (stcb->asoc.refcnt) { - SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); - if (from_inpcbfree == SCTP_NORMAL_PROC) { - SCTP_INP_INFO_WUNLOCK(); - SCTP_INP_WUNLOCK(inp); - } - SCTP_TCB_UNLOCK(stcb); - return (0); - } - asoc->state = 0; - if (inp->sctp_tcbhash) { - LIST_REMOVE(stcb, sctp_tcbhash); - } - if (stcb->asoc.in_asocid_hash) { - LIST_REMOVE(stcb, sctp_tcbasocidhash); - } - if (inp->sctp_socket == NULL) { - stcb->sctp_socket = NULL; - } - /* Now lets remove it from the list of ALL associations in the EP */ - LIST_REMOVE(stcb, sctp_tcblist); - if (from_inpcbfree == SCTP_NORMAL_PROC) { - SCTP_INP_INCR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - /* pull from vtag hash */ - LIST_REMOVE(stcb, sctp_asocs); - sctp_add_vtag_to_timewait(asoc->my_vtag, inp->sctp_lport, stcb->rport); - - /* Now restop the timers to be sure - * this is paranoia at is finest! - */ - sctp_stop_association_timers(stcb, true); - - /* - * The chunk lists and such SHOULD be empty but we check them just - * in case. - */ - /* anything on the wheel needs to be removed */ - for (i = 0; i < asoc->streamoutcnt; i++) { - struct sctp_stream_out *outs; - - outs = &asoc->strmout[i]; - /* now clean up any chunks here */ - TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { - atomic_subtract_int(&asoc->stream_queue_cnt, 1); - TAILQ_REMOVE(&outs->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp); - sctp_free_spbufspace(stcb, asoc, sp); - if (sp->data) { - if (so) { - /* Still an open socket - report */ - sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, - 0, (void *)sp, SCTP_SO_LOCKED); - } - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - sp->tail_mbuf = NULL; - sp->length = 0; - } - } - if (sp->net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); - } - } - /*sa_ignore FREED_MEMORY*/ - TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) { - TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp); - SCTP_FREE(strrst, SCTP_M_STRESET); - } - TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) { - TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next); - if (sq->data) { - sctp_m_freem(sq->data); - sq->data = NULL; - } - sctp_free_remote_addr(sq->whoFrom); - sq->whoFrom = NULL; - sq->stcb = NULL; - /* Free the ctl entry */ - sctp_free_a_readq(stcb, sq); - /*sa_ignore FREED_MEMORY*/ - } - TAILQ_FOREACH_SAFE(chk, &asoc->free_chunks, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->free_chunks, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - atomic_subtract_int(&SCTP_BASE_INFO(ipi_free_chunks), 1); - asoc->free_chunk_cnt--; - /*sa_ignore FREED_MEMORY*/ - } - /* pending send queue SHOULD be empty */ - TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { - if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[chk->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", chk->rec.data.sid); -#endif - } - TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); - if (chk->data) { - if (so) { - /* Still a socket? */ - sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, - 0, chk, SCTP_SO_LOCKED); - } - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - if (chk->whoTo) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; - } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /*sa_ignore FREED_MEMORY*/ - } - /* sent queue SHOULD be empty */ - TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { - if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { - if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[chk->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", chk->rec.data.sid); -#endif - } - } - TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); - if (chk->data) { - if (so) { - /* Still a socket? */ - sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, - 0, chk, SCTP_SO_LOCKED); - } - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /*sa_ignore FREED_MEMORY*/ - } -#ifdef INVARIANTS - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (stcb->asoc.strmout[i].chunks_on_queues > 0) { - panic("%u chunks left for stream %u.", stcb->asoc.strmout[i].chunks_on_queues, i); - } - } -#endif - /* control queue MAY not be empty */ - TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /*sa_ignore FREED_MEMORY*/ - } - /* ASCONF queue MAY not be empty */ - TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /*sa_ignore FREED_MEMORY*/ - } - if (asoc->mapping_array) { - SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); - asoc->mapping_array = NULL; - } - if (asoc->nr_mapping_array) { - SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); - asoc->nr_mapping_array = NULL; - } - /* the stream outs */ - if (asoc->strmout) { - SCTP_FREE(asoc->strmout, SCTP_M_STRMO); - asoc->strmout = NULL; - } - asoc->strm_realoutsize = asoc->streamoutcnt = 0; - if (asoc->strmin) { - for (i = 0; i < asoc->streamincnt; i++) { - sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue); - sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue); - } - SCTP_FREE(asoc->strmin, SCTP_M_STRMI); - asoc->strmin = NULL; - } - asoc->streamincnt = 0; - TAILQ_FOREACH_SAFE(net, &asoc->nets, sctp_next, nnet) { -#ifdef INVARIANTS - if (SCTP_BASE_INFO(ipi_count_raddr) == 0) { - panic("no net's left alloc'ed, or list points to itself"); - } -#endif - TAILQ_REMOVE(&asoc->nets, net, sctp_next); - sctp_free_remote_addr(net); - } - LIST_FOREACH_SAFE(laddr, &asoc->sctp_restricted_addrs, sctp_nxt_addr, naddr) { - /*sa_ignore FREED_MEMORY*/ - sctp_remove_laddr(laddr); - } - - /* pending asconf (address) parameters */ - TAILQ_FOREACH_SAFE(aparam, &asoc->asconf_queue, next, naparam) { - /*sa_ignore FREED_MEMORY*/ - TAILQ_REMOVE(&asoc->asconf_queue, aparam, next); - SCTP_FREE(aparam,SCTP_M_ASC_ADDR); - } - TAILQ_FOREACH_SAFE(aack, &asoc->asconf_ack_sent, next, naack) { - /*sa_ignore FREED_MEMORY*/ - TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next); - if (aack->data != NULL) { - sctp_m_freem(aack->data); - } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), aack); - } - /* clean up auth stuff */ - if (asoc->local_hmacs) - sctp_free_hmaclist(asoc->local_hmacs); - if (asoc->peer_hmacs) - sctp_free_hmaclist(asoc->peer_hmacs); - - if (asoc->local_auth_chunks) - sctp_free_chunklist(asoc->local_auth_chunks); - if (asoc->peer_auth_chunks) - sctp_free_chunklist(asoc->peer_auth_chunks); - - sctp_free_authinfo(&asoc->authinfo); - - LIST_FOREACH_SAFE(shared_key, &asoc->shared_keys, next, nshared_key) { - LIST_REMOVE(shared_key, next); - sctp_free_sharedkey(shared_key); - /*sa_ignore FREED_MEMORY*/ - } - - /* Insert new items here :> */ - - /* Get rid of LOCK */ - SCTP_TCB_UNLOCK(stcb); - SCTP_TCB_LOCK_DESTROY(stcb); - if (from_inpcbfree == SCTP_NORMAL_PROC) { - SCTP_INP_INFO_WUNLOCK(); - SCTP_INP_RLOCK(inp); - } -#if defined(__APPLE__) && !defined(__Userspace__) - /* TEMP CODE */ - stcb->freed_from_where = from_location; -#endif -#ifdef SCTP_TRACK_FREED_ASOCS - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* now clean up the tasoc itself */ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_DECR_ASOC_COUNT(); - } else { - LIST_INSERT_HEAD(&inp->sctp_asoc_free_list, stcb, sctp_tcblist); - } -#else - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); - SCTP_DECR_ASOC_COUNT(); -#endif - if (from_inpcbfree == SCTP_NORMAL_PROC) { - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - /* If its NOT the inp_free calling us AND - * sctp_close as been called, we - * call back... - */ - SCTP_INP_RUNLOCK(inp); - /* This will start the kill timer (if we are - * the last one) since we hold an increment yet. But - * this is the only safe way to do this - * since otherwise if the socket closes - * at the same time we are here we might - * collide in the cleanup. - */ - sctp_inpcb_free(inp, - SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, - SCTP_CALLED_DIRECTLY_NOCMPSET); - SCTP_INP_DECR_REF(inp); - } else { - /* The socket is still open. */ - SCTP_INP_DECR_REF(inp); - SCTP_INP_RUNLOCK(inp); - } - } - /* destroyed the asoc */ -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 11); -#endif - return (1); -} - -/* - * determine if a destination is "reachable" based upon the addresses bound - * to the current endpoint (e.g. only v4 or v6 currently bound) - */ -/* - * FIX: if we allow assoc-level bindx(), then this needs to be fixed to use - * assoc level v4/v6 flags, as the assoc *may* not have the same address - * types bound as its endpoint - */ -int -sctp_destination_is_reachable(struct sctp_tcb *stcb, struct sockaddr *destaddr) -{ - struct sctp_inpcb *inp; - int answer; - - /* - * No locks here, the TCB, in all cases is already locked and an - * assoc is up. There is either a INP lock by the caller applied (in - * asconf case when deleting an address) or NOT in the HB case, - * however if HB then the INP increment is up and the INP will not - * be removed (on top of the fact that we have a TCB lock). So we - * only want to read the sctp_flags, which is either bound-all or - * not.. no protection needed since once an assoc is up you can't be - * changing your binding. - */ - inp = stcb->sctp_ep; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* if bound all, destination is not restricted */ - /* - * RRS: Question during lock work: Is this correct? If you - * are bound-all you still might need to obey the V4--V6 - * flags??? IMO this bound-all stuff needs to be removed! - */ - return (1); - } - /* NOTE: all "scope" checks are done when local addresses are added */ - switch (destaddr->sa_family) { -#ifdef INET6 - case AF_INET6: - answer = inp->ip_inp.inp.inp_vflag & INP_IPV6; - break; -#endif -#ifdef INET - case AF_INET: - answer = inp->ip_inp.inp.inp_vflag & INP_IPV4; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - answer = inp->ip_inp.inp.inp_vflag & INP_CONN; - break; -#endif - default: - /* invalid family, so it's unreachable */ - answer = 0; - break; - } - return (answer); -} - -/* - * update the inp_vflags on an endpoint - */ -static void -sctp_update_ep_vflag(struct sctp_inpcb *inp) -{ - struct sctp_laddr *laddr; - - /* first clear the flag */ - inp->ip_inp.inp.inp_vflag = 0; - /* set the flag based on addresses on the ep list */ - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_PCB1, "%s: NULL ifa\n", - __func__); - continue; - } - - if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { - continue; - } - switch (laddr->ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - inp->ip_inp.inp.inp_vflag |= INP_IPV6; - break; -#endif -#ifdef INET - case AF_INET: - inp->ip_inp.inp.inp_vflag |= INP_IPV4; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - inp->ip_inp.inp.inp_vflag |= INP_CONN; - break; -#endif - default: - break; - } - } -} - -/* - * Add the address to the endpoint local address list There is nothing to be - * done if we are bound to all addresses - */ -void -sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t action) -{ - struct sctp_laddr *laddr; - struct sctp_tcb *stcb; - int fnd, error = 0; - - fnd = 0; - - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* You are already bound to all. You have it already */ - return; - } -#ifdef INET6 - if (ifa->address.sa.sa_family == AF_INET6) { - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - /* Can't bind a non-useable addr. */ - return; - } - } -#endif - /* first, is it already present? */ - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == ifa) { - fnd = 1; - break; - } - } - - if (fnd == 0) { - /* Not in the ep list */ - error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, action); - if (error != 0) - return; - inp->laddr_count++; - /* update inp_vflag flags */ - switch (ifa->address.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - inp->ip_inp.inp.inp_vflag |= INP_IPV6; - break; -#endif -#ifdef INET - case AF_INET: - inp->ip_inp.inp.inp_vflag |= INP_IPV4; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - inp->ip_inp.inp.inp_vflag |= INP_CONN; - break; -#endif - default: - break; - } - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - sctp_add_local_addr_restricted(stcb, ifa); - } - } - return; -} - -/* - * select a new (hopefully reachable) destination net (should only be used - * when we deleted an ep addr that is the only usable source address to reach - * the destination net) - */ -static void -sctp_select_primary_destination(struct sctp_tcb *stcb) -{ - struct sctp_nets *net; - - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* for now, we'll just pick the first reachable one we find */ - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) - continue; - if (sctp_destination_is_reachable(stcb, - (struct sockaddr *)&net->ro._l_addr)) { - /* found a reachable destination */ - stcb->asoc.primary_destination = net; - } - } - /* I can't there from here! ...we're gonna die shortly... */ -} - -/* - * Delete the address from the endpoint local address list. There is nothing - * to be done if we are bound to all addresses - */ -void -sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa) -{ - struct sctp_laddr *laddr; - int fnd; - - fnd = 0; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* You are already bound to all. You have it already */ - return; - } - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == ifa) { - fnd = 1; - break; - } - } - if (fnd && (inp->laddr_count < 2)) { - /* can't delete unless there are at LEAST 2 addresses */ - return; - } - if (fnd) { - /* - * clean up any use of this address go through our - * associations and clear any last_used_address that match - * this one for each assoc, see if a new primary_destination - * is needed - */ - struct sctp_tcb *stcb; - - /* clean up "next_addr_touse" */ - if (inp->next_addr_touse == laddr) - /* delete this address */ - inp->next_addr_touse = NULL; - - /* clean up "last_used_address" */ - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - struct sctp_nets *net; - - SCTP_TCB_LOCK(stcb); - if (stcb->asoc.last_used_address == laddr) - /* delete this address */ - stcb->asoc.last_used_address = NULL; - /* Now spin through all the nets and purge any ref to laddr */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->ro._s_addr == laddr->ifa) { - /* Yep, purge src address selected */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(&net->ro); -#else - sctp_rtentry_t *rt; - - /* delete this address if cached */ - rt = net->ro.ro_rt; - if (rt != NULL) { - RTFREE(rt); - net->ro.ro_rt = NULL; - } -#endif - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } - } - SCTP_TCB_UNLOCK(stcb); - } /* for each tcb */ - /* remove it from the ep list */ - sctp_remove_laddr(laddr); - inp->laddr_count--; - /* update inp_vflag flags */ - sctp_update_ep_vflag(inp); - } - return; -} - -/* - * Add the address to the TCB local address restricted list. - * This is a "pending" address list (eg. addresses waiting for an - * ASCONF-ACK response) and cannot be used as a valid source address. - */ -void -sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) -{ - struct sctp_laddr *laddr; - struct sctpladdr *list; - - /* - * Assumes TCB is locked.. and possibly the INP. May need to - * confirm/fix that if we need it and is not the case. - */ - list = &stcb->asoc.sctp_restricted_addrs; - -#ifdef INET6 - if (ifa->address.sa.sa_family == AF_INET6) { - if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - /* Can't bind a non-existent addr. */ - return; - } - } -#endif - /* does the address already exist? */ - LIST_FOREACH(laddr, list, sctp_nxt_addr) { - if (laddr->ifa == ifa) { - return; - } - } - - /* add to the list */ - (void)sctp_insert_laddr(list, ifa, 0); - return; -} - -/* - * Remove a local address from the TCB local address restricted list - */ -void -sctp_del_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) -{ - struct sctp_inpcb *inp; - struct sctp_laddr *laddr; - - /* - * This is called by asconf work. It is assumed that a) The TCB is - * locked and b) The INP is locked. This is true in as much as I can - * trace through the entry asconf code where I did these locks. - * Again, the ASCONF code is a bit different in that it does lock - * the INP during its work often times. This must be since we don't - * want other proc's looking up things while what they are looking - * up is changing :-D - */ - - inp = stcb->sctp_ep; - /* if subset bound and don't allow ASCONF's, can't delete last */ - if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && - sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { - if (stcb->sctp_ep->laddr_count < 2) { - /* can't delete last address */ - return; - } - } - LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) { - /* remove the address if it exists */ - if (laddr->ifa == NULL) - continue; - if (laddr->ifa == ifa) { - sctp_remove_laddr(laddr); - return; - } - } - - /* address not found! */ - return; -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -/* sysctl */ -static int sctp_max_number_of_assoc = SCTP_MAX_NUM_OF_ASOC; -static int sctp_scale_up_for_address = SCTP_SCALE_FOR_ADDR; -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_MCORE_INPUT) && defined(SMP) -struct sctp_mcore_ctrl *sctp_mcore_workers = NULL; -int *sctp_cpuarry = NULL; - -void -sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use) -{ - /* Queue a packet to a processor for the specified core */ - struct sctp_mcore_queue *qent; - struct sctp_mcore_ctrl *wkq; - int need_wake = 0; - - if (sctp_mcore_workers == NULL) { - /* Something went way bad during setup */ - sctp_input_with_port(m, off, 0); - return; - } - SCTP_MALLOC(qent, struct sctp_mcore_queue *, - (sizeof(struct sctp_mcore_queue)), - SCTP_M_MCORE); - if (qent == NULL) { - /* This is trouble */ - sctp_input_with_port(m, off, 0); - return; - } - qent->vn = curvnet; - qent->m = m; - qent->off = off; - qent->v6 = 0; - wkq = &sctp_mcore_workers[cpu_to_use]; - SCTP_MCORE_QLOCK(wkq); - - TAILQ_INSERT_TAIL(&wkq->que, qent, next); - if (wkq->running == 0) { - need_wake = 1; - } - SCTP_MCORE_QUNLOCK(wkq); - if (need_wake) { - wakeup(&wkq->running); - } -} - -static void -sctp_mcore_thread(void *arg) -{ - - struct sctp_mcore_ctrl *wkq; - struct sctp_mcore_queue *qent; - - wkq = (struct sctp_mcore_ctrl *)arg; - struct mbuf *m; - int off, v6; - - /* Wait for first tickle */ - SCTP_MCORE_LOCK(wkq); - wkq->running = 0; - msleep(&wkq->running, - &wkq->core_mtx, - 0, "wait for pkt", 0); - SCTP_MCORE_UNLOCK(wkq); - - /* Bind to our cpu */ - thread_lock(curthread); - sched_bind(curthread, wkq->cpuid); - thread_unlock(curthread); - - /* Now lets start working */ - SCTP_MCORE_LOCK(wkq); - /* Now grab lock and go */ - for (;;) { - SCTP_MCORE_QLOCK(wkq); - skip_sleep: - wkq->running = 1; - qent = TAILQ_FIRST(&wkq->que); - if (qent) { - TAILQ_REMOVE(&wkq->que, qent, next); - SCTP_MCORE_QUNLOCK(wkq); - CURVNET_SET(qent->vn); - m = qent->m; - off = qent->off; - v6 = qent->v6; - SCTP_FREE(qent, SCTP_M_MCORE); - if (v6 == 0) { - sctp_input_with_port(m, off, 0); - } else { - SCTP_PRINTF("V6 not yet supported\n"); - sctp_m_freem(m); - } - CURVNET_RESTORE(); - SCTP_MCORE_QLOCK(wkq); - } - wkq->running = 0; - if (!TAILQ_EMPTY(&wkq->que)) { - goto skip_sleep; - } - SCTP_MCORE_QUNLOCK(wkq); - msleep(&wkq->running, - &wkq->core_mtx, - 0, "wait for pkt", 0); - } -} - -static void -sctp_startup_mcore_threads(void) -{ - int i, cpu; - - if (mp_ncpus == 1) - return; - - if (sctp_mcore_workers != NULL) { - /* Already been here in some previous - * vnet? - */ - return; - } - SCTP_MALLOC(sctp_mcore_workers, struct sctp_mcore_ctrl *, - ((mp_maxid+1) * sizeof(struct sctp_mcore_ctrl)), - SCTP_M_MCORE); - if (sctp_mcore_workers == NULL) { - /* TSNH I hope */ - return; - } - memset(sctp_mcore_workers, 0 , ((mp_maxid+1) * - sizeof(struct sctp_mcore_ctrl))); - /* Init the structures */ - for (i = 0; i<=mp_maxid; i++) { - TAILQ_INIT(&sctp_mcore_workers[i].que); - SCTP_MCORE_LOCK_INIT(&sctp_mcore_workers[i]); - SCTP_MCORE_QLOCK_INIT(&sctp_mcore_workers[i]); - sctp_mcore_workers[i].cpuid = i; - } - if (sctp_cpuarry == NULL) { - SCTP_MALLOC(sctp_cpuarry, int *, - (mp_ncpus * sizeof(int)), - SCTP_M_MCORE); - i = 0; - CPU_FOREACH(cpu) { - sctp_cpuarry[i] = cpu; - i++; - } - } - /* Now start them all */ - CPU_FOREACH(cpu) { - (void)kproc_create(sctp_mcore_thread, - (void *)&sctp_mcore_workers[cpu], - &sctp_mcore_workers[cpu].thread_proc, - 0, - SCTP_KTHREAD_PAGES, - SCTP_MCORE_NAME); - } -} -#endif -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_NOT_YET) -static struct mbuf * -sctp_netisr_hdlr(struct mbuf *m, uintptr_t source) -{ - struct ip *ip; - struct sctphdr *sh; - int offset; - uint32_t flowid, tag; - - /* - * No flow id built by lower layers fix it so we - * create one. - */ - ip = mtod(m, struct ip *); - offset = (ip->ip_hl << 2) + sizeof(struct sctphdr); - if (SCTP_BUF_LEN(m) < offset) { - if ((m = m_pullup(m, offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - return (NULL); - } - ip = mtod(m, struct ip *); - } - sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); - tag = htonl(sh->v_tag); - flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); - m->m_pkthdr.flowid = flowid; - /* FIX ME */ - m->m_flags |= M_FLOWID; - return (m); -} - -#endif -#endif -void -#if defined(__Userspace__) -sctp_pcb_init(int start_threads) -#else -sctp_pcb_init(void) -#endif -{ - /* - * SCTP initialization for the PCB structures should be called by - * the sctp_init() function. - */ - int i; - struct timeval tv; - - if (SCTP_BASE_VAR(sctp_pcb_initialized) != 0) { - /* error I was called twice */ - return; - } - SCTP_BASE_VAR(sctp_pcb_initialized) = 1; - -#if defined(SCTP_PROCESS_LEVEL_LOCKS) -#if !defined(_WIN32) - pthread_mutexattr_init(&SCTP_BASE_VAR(mtx_attr)); - pthread_rwlockattr_init(&SCTP_BASE_VAR(rwlock_attr)); -#ifdef INVARIANTS - pthread_mutexattr_settype(&SCTP_BASE_VAR(mtx_attr), PTHREAD_MUTEX_ERRORCHECK); -#endif -#endif -#endif -#if defined(SCTP_LOCAL_TRACE_BUF) -#if defined(_WIN32) && !defined(__Userspace__) - if (SCTP_BASE_SYSCTL(sctp_log) != NULL) { - memset(SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); - } -#else - memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); -#endif -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) - SCTP_MALLOC(SCTP_BASE_STATS, struct sctpstat *, - ((mp_maxid+1) * sizeof(struct sctpstat)), - SCTP_M_MCORE); -#endif -#endif - (void)SCTP_GETTIME_TIMEVAL(&tv); -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) - memset(SCTP_BASE_STATS, 0, sizeof(struct sctpstat) * (mp_maxid+1)); - SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_sec = (uint32_t)tv.tv_sec; - SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_usec = (uint32_t)tv.tv_usec; -#else - memset(&SCTP_BASE_STATS, 0, sizeof(struct sctpstat)); - SCTP_BASE_STAT(sctps_discontinuitytime).tv_sec = (uint32_t)tv.tv_sec; - SCTP_BASE_STAT(sctps_discontinuitytime).tv_usec = (uint32_t)tv.tv_usec; -#endif -#else - memset(&SCTP_BASE_STATS, 0, sizeof(struct sctpstat)); - SCTP_BASE_STAT(sctps_discontinuitytime).tv_sec = (uint32_t)tv.tv_sec; - SCTP_BASE_STAT(sctps_discontinuitytime).tv_usec = (uint32_t)tv.tv_usec; -#endif - /* init the empty list of (All) Endpoints */ - LIST_INIT(&SCTP_BASE_INFO(listhead)); -#if defined(__APPLE__) && !defined(__Userspace__) - LIST_INIT(&SCTP_BASE_INFO(inplisthead)); -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION) - SCTP_BASE_INFO(sctbinfo).listhead = &SCTP_BASE_INFO(inplisthead); - SCTP_BASE_INFO(sctbinfo).mtx_grp_attr = lck_grp_attr_alloc_init(); - lck_grp_attr_setdefault(SCTP_BASE_INFO(sctbinfo).mtx_grp_attr); - SCTP_BASE_INFO(sctbinfo).mtx_grp = lck_grp_alloc_init("sctppcb", SCTP_BASE_INFO(sctbinfo).mtx_grp_attr); - SCTP_BASE_INFO(sctbinfo).mtx_attr = lck_attr_alloc_init(); - lck_attr_setdefault(SCTP_BASE_INFO(sctbinfo).mtx_attr); -#else - SCTP_BASE_INFO(sctbinfo).ipi_listhead = &SCTP_BASE_INFO(inplisthead); - SCTP_BASE_INFO(sctbinfo).ipi_lock_grp_attr = lck_grp_attr_alloc_init(); - lck_grp_attr_setdefault(SCTP_BASE_INFO(sctbinfo).ipi_lock_grp_attr); - SCTP_BASE_INFO(sctbinfo).ipi_lock_grp = lck_grp_alloc_init("sctppcb", SCTP_BASE_INFO(sctbinfo).ipi_lock_grp_attr); - SCTP_BASE_INFO(sctbinfo).ipi_lock_attr = lck_attr_alloc_init(); - lck_attr_setdefault(SCTP_BASE_INFO(sctbinfo).ipi_lock_attr); -#endif -#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) - SCTP_BASE_INFO(sctbinfo).ipi_gc = sctp_gc; - in_pcbinfo_attach(&SCTP_BASE_INFO(sctbinfo)); -#endif -#endif - - /* init the hash table of endpoints */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", &SCTP_BASE_SYSCTL(sctp_hashtblsize)); - TUNABLE_INT_FETCH("net.inet.sctp.pcbhashsize", &SCTP_BASE_SYSCTL(sctp_pcbtblsize)); - TUNABLE_INT_FETCH("net.inet.sctp.chunkscale", &SCTP_BASE_SYSCTL(sctp_chunkscale)); -#endif - SCTP_BASE_INFO(sctp_asochash) = SCTP_HASH_INIT((SCTP_BASE_SYSCTL(sctp_hashtblsize) * 31), - &SCTP_BASE_INFO(hashasocmark)); - SCTP_BASE_INFO(sctp_ephash) = SCTP_HASH_INIT(SCTP_BASE_SYSCTL(sctp_hashtblsize), - &SCTP_BASE_INFO(hashmark)); - SCTP_BASE_INFO(sctp_tcpephash) = SCTP_HASH_INIT(SCTP_BASE_SYSCTL(sctp_hashtblsize), - &SCTP_BASE_INFO(hashtcpmark)); - SCTP_BASE_INFO(hashtblsize) = SCTP_BASE_SYSCTL(sctp_hashtblsize); - SCTP_BASE_INFO(sctp_vrfhash) = SCTP_HASH_INIT(SCTP_SIZE_OF_VRF_HASH, - &SCTP_BASE_INFO(hashvrfmark)); - - SCTP_BASE_INFO(vrf_ifn_hash) = SCTP_HASH_INIT(SCTP_VRF_IFN_HASH_SIZE, - &SCTP_BASE_INFO(vrf_ifn_hashmark)); - /* init the zones */ - /* - * FIX ME: Should check for NULL returns, but if it does fail we are - * doomed to panic anyways... add later maybe. - */ - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_ep), "sctp_ep", - sizeof(struct sctp_inpcb), maxsockets); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_asoc), "sctp_asoc", - sizeof(struct sctp_tcb), sctp_max_number_of_assoc); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_laddr), "sctp_laddr", - sizeof(struct sctp_laddr), - (sctp_max_number_of_assoc * sctp_scale_up_for_address)); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_net), "sctp_raddr", - sizeof(struct sctp_nets), - (sctp_max_number_of_assoc * sctp_scale_up_for_address)); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_chunk), "sctp_chunk", - sizeof(struct sctp_tmit_chunk), - (sctp_max_number_of_assoc * SCTP_BASE_SYSCTL(sctp_chunkscale))); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_readq), "sctp_readq", - sizeof(struct sctp_queued_to_read), - (sctp_max_number_of_assoc * SCTP_BASE_SYSCTL(sctp_chunkscale))); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_strmoq), "sctp_stream_msg_out", - sizeof(struct sctp_stream_queue_pending), - (sctp_max_number_of_assoc * SCTP_BASE_SYSCTL(sctp_chunkscale))); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_asconf), "sctp_asconf", - sizeof(struct sctp_asconf), - (sctp_max_number_of_assoc * SCTP_BASE_SYSCTL(sctp_chunkscale))); - - SCTP_ZONE_INIT(SCTP_BASE_INFO(ipi_zone_asconf_ack), "sctp_asconf_ack", - sizeof(struct sctp_asconf_ack), - (sctp_max_number_of_assoc * SCTP_BASE_SYSCTL(sctp_chunkscale))); - - /* Master Lock INIT for info structure */ - SCTP_INP_INFO_LOCK_INIT(); - SCTP_STATLOG_INIT_LOCK(); - - SCTP_IPI_COUNT_INIT(); - SCTP_IPI_ADDR_INIT(); -#ifdef SCTP_PACKET_LOGGING - SCTP_IP_PKTLOG_INIT(); -#endif - LIST_INIT(&SCTP_BASE_INFO(addr_wq)); - - SCTP_WQ_ADDR_INIT(); - /* not sure if we need all the counts */ - SCTP_BASE_INFO(ipi_count_ep) = 0; - /* assoc/tcb zone info */ - SCTP_BASE_INFO(ipi_count_asoc) = 0; - /* local addrlist zone info */ - SCTP_BASE_INFO(ipi_count_laddr) = 0; - /* remote addrlist zone info */ - SCTP_BASE_INFO(ipi_count_raddr) = 0; - /* chunk info */ - SCTP_BASE_INFO(ipi_count_chunk) = 0; - - /* socket queue zone info */ - SCTP_BASE_INFO(ipi_count_readq) = 0; - - /* stream out queue cont */ - SCTP_BASE_INFO(ipi_count_strmoq) = 0; - - SCTP_BASE_INFO(ipi_free_strmoq) = 0; - SCTP_BASE_INFO(ipi_free_chunks) = 0; - - SCTP_OS_TIMER_INIT(&SCTP_BASE_INFO(addr_wq_timer.timer)); - - /* Init the TIMEWAIT list */ - for (i = 0; i < SCTP_STACK_VTAG_HASH_SIZE; i++) { - LIST_INIT(&SCTP_BASE_INFO(vtag_timewait)[i]); - } -#if defined(SCTP_PROCESS_LEVEL_LOCKS) -#if defined(_WIN32) - InitializeConditionVariable(&sctp_it_ctl.iterator_wakeup); -#else - (void)pthread_cond_init(&sctp_it_ctl.iterator_wakeup, NULL); -#endif -#endif - sctp_startup_iterator(); - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_MCORE_INPUT) && defined(SMP) - sctp_startup_mcore_threads(); -#endif -#endif - - /* - * INIT the default VRF which for BSD is the only one, other O/S's - * may have more. But initially they must start with one and then - * add the VRF's as addresses are added. - */ - sctp_init_vrf_list(SCTP_DEFAULT_VRF); -#if defined(__FreeBSD__) && !defined(__Userspace__) && defined(SCTP_NOT_YET) - if (ip_register_flow_handler(sctp_netisr_hdlr, IPPROTO_SCTP)) { - SCTP_PRINTF("***SCTP- Error can't register netisr handler***\n"); - } -#endif -#if defined(_SCTP_NEEDS_CALLOUT_) || defined(_USER_SCTP_NEEDS_CALLOUT_) - /* allocate the lock for the callout/timer queue */ - SCTP_TIMERQ_LOCK_INIT(); - TAILQ_INIT(&SCTP_BASE_INFO(callqueue)); -#endif -#if defined(__Userspace__) - mbuf_initialize(NULL); - atomic_init(); -#if defined(INET) || defined(INET6) - if (start_threads) - recv_thread_init(); -#endif -#endif -} - -/* - * Assumes that the SCTP_BASE_INFO() lock is NOT held. - */ -void -sctp_pcb_finish(void) -{ - struct sctp_vrflist *vrf_bucket; - struct sctp_vrf *vrf, *nvrf; - struct sctp_ifn *ifn, *nifn; - struct sctp_ifa *ifa, *nifa; - struct sctpvtaghead *chain; - struct sctp_tagblock *twait_block, *prev_twait_block; - struct sctp_laddr *wi, *nwi; - int i; - struct sctp_iterator *it, *nit; - - if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { - SCTP_PRINTF("%s: race condition on teardown.\n", __func__); - return; - } - SCTP_BASE_VAR(sctp_pcb_initialized) = 0; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - /* Notify the iterator to exit. */ - SCTP_IPI_ITERATOR_WQ_LOCK(); - sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_MUST_EXIT; - sctp_wakeup_iterator(); - SCTP_IPI_ITERATOR_WQ_UNLOCK(); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) - in_pcbinfo_detach(&SCTP_BASE_INFO(sctbinfo)); -#endif - SCTP_IPI_ITERATOR_WQ_LOCK(); - do { - msleep(&sctp_it_ctl.iterator_flags, - sctp_it_ctl.ipi_iterator_wq_mtx, - 0, "waiting_for_work", 0); - } while ((sctp_it_ctl.iterator_flags & SCTP_ITERATOR_EXITED) == 0); - thread_deallocate(sctp_it_ctl.thread_proc); - SCTP_IPI_ITERATOR_WQ_UNLOCK(); -#endif -#if defined(_WIN32) && !defined(__Userspace__) - if (sctp_it_ctl.iterator_thread_obj != NULL) { - NTSTATUS status = STATUS_SUCCESS; - - KeSetEvent(&sctp_it_ctl.iterator_wakeup[1], IO_NO_INCREMENT, FALSE); - status = KeWaitForSingleObject(sctp_it_ctl.iterator_thread_obj, - Executive, - KernelMode, - FALSE, - NULL); - ObDereferenceObject(sctp_it_ctl.iterator_thread_obj); - } -#endif -#if defined(__Userspace__) - if (SCTP_BASE_VAR(iterator_thread_started)) { -#if defined(_WIN32) - WaitForSingleObject(sctp_it_ctl.thread_proc, INFINITE); - CloseHandle(sctp_it_ctl.thread_proc); - sctp_it_ctl.thread_proc = NULL; -#else - pthread_join(sctp_it_ctl.thread_proc, NULL); - sctp_it_ctl.thread_proc = 0; -#endif - } -#endif -#if defined(SCTP_PROCESS_LEVEL_LOCKS) -#if defined(_WIN32) - DeleteConditionVariable(&sctp_it_ctl.iterator_wakeup); -#else - pthread_cond_destroy(&sctp_it_ctl.iterator_wakeup); - pthread_mutexattr_destroy(&SCTP_BASE_VAR(mtx_attr)); - pthread_rwlockattr_destroy(&SCTP_BASE_VAR(rwlock_attr)); -#endif -#endif - /* In FreeBSD the iterator thread never exits - * but we do clean up. - * The only way FreeBSD reaches here is if we have VRF's - * but we still add the ifdef to make it compile on old versions. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -retry: -#endif - SCTP_IPI_ITERATOR_WQ_LOCK(); -#if defined(__FreeBSD__) && !defined(__Userspace__) - /* - * sctp_iterator_worker() might be working on an it entry without - * holding the lock. We won't find it on the list either and - * continue and free/destroy it. While holding the lock, spin, to - * avoid the race condition as sctp_iterator_worker() will have to - * wait to re-acquire the lock. - */ - if (sctp_it_ctl.iterator_running != 0 || sctp_it_ctl.cur_it != NULL) { - SCTP_IPI_ITERATOR_WQ_UNLOCK(); - SCTP_PRINTF("%s: Iterator running while we held the lock. Retry. " - "cur_it=%p\n", __func__, sctp_it_ctl.cur_it); - DELAY(10); - goto retry; - } -#endif - TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (it->vn != curvnet) { - continue; - } -#endif - TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); - if (it->function_atend != NULL) { - (*it->function_atend) (it->pointer, it->val); - } - SCTP_FREE(it,SCTP_M_ITER); - } - SCTP_IPI_ITERATOR_WQ_UNLOCK(); -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_ITERATOR_LOCK(); - if ((sctp_it_ctl.cur_it) && - (sctp_it_ctl.cur_it->vn == curvnet)) { - sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_STOP_CUR_IT; - } - SCTP_ITERATOR_UNLOCK(); -#endif -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - SCTP_IPI_ITERATOR_WQ_DESTROY(); - SCTP_ITERATOR_LOCK_DESTROY(); -#endif - SCTP_OS_TIMER_STOP_DRAIN(&SCTP_BASE_INFO(addr_wq_timer.timer)); - SCTP_WQ_ADDR_LOCK(); - LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { - LIST_REMOVE(wi, sctp_nxt_addr); - SCTP_DECR_LADDR_COUNT(); - if (wi->action == SCTP_DEL_IP_ADDRESS) { - SCTP_FREE(wi->ifa, SCTP_M_IFA); - } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), wi); - } - SCTP_WQ_ADDR_UNLOCK(); - - /* - * free the vrf/ifn/ifa lists and hashes (be sure address monitor - * is destroyed first). - */ - SCTP_IPI_ADDR_WLOCK(); - vrf_bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(SCTP_DEFAULT_VRFID & SCTP_BASE_INFO(hashvrfmark))]; - LIST_FOREACH_SAFE(vrf, vrf_bucket, next_vrf, nvrf) { - LIST_FOREACH_SAFE(ifn, &vrf->ifnlist, next_ifn, nifn) { - LIST_FOREACH_SAFE(ifa, &ifn->ifalist, next_ifa, nifa) { - /* free the ifa */ - LIST_REMOVE(ifa, next_bucket); - LIST_REMOVE(ifa, next_ifa); - SCTP_FREE(ifa, SCTP_M_IFA); - } - /* free the ifn */ - LIST_REMOVE(ifn, next_bucket); - LIST_REMOVE(ifn, next_ifn); - SCTP_FREE(ifn, SCTP_M_IFN); - } - SCTP_HASH_FREE(vrf->vrf_addr_hash, vrf->vrf_addr_hashmark); - /* free the vrf */ - LIST_REMOVE(vrf, next_vrf); - SCTP_FREE(vrf, SCTP_M_VRF); - } - SCTP_IPI_ADDR_WUNLOCK(); - /* free the vrf hashes */ - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_vrfhash), SCTP_BASE_INFO(hashvrfmark)); - SCTP_HASH_FREE(SCTP_BASE_INFO(vrf_ifn_hash), SCTP_BASE_INFO(vrf_ifn_hashmark)); - - /* free the TIMEWAIT list elements malloc'd in the function - * sctp_add_vtag_to_timewait()... - */ - for (i = 0; i < SCTP_STACK_VTAG_HASH_SIZE; i++) { - chain = &SCTP_BASE_INFO(vtag_timewait)[i]; - if (!LIST_EMPTY(chain)) { - prev_twait_block = NULL; - LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { - if (prev_twait_block) { - SCTP_FREE(prev_twait_block, SCTP_M_TIMW); - } - prev_twait_block = twait_block; - } - SCTP_FREE(prev_twait_block, SCTP_M_TIMW); - } - } - - /* free the locks and mutexes */ -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_TIMERQ_LOCK_DESTROY(); -#endif -#ifdef SCTP_PACKET_LOGGING - SCTP_IP_PKTLOG_DESTROY(); -#endif - SCTP_IPI_ADDR_DESTROY(); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_IPI_COUNT_DESTROY(); -#endif - SCTP_STATLOG_DESTROY(); - SCTP_INP_INFO_LOCK_DESTROY(); - - SCTP_WQ_ADDR_DESTROY(); - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION) - lck_grp_attr_free(SCTP_BASE_INFO(sctbinfo).mtx_grp_attr); - lck_grp_free(SCTP_BASE_INFO(sctbinfo).mtx_grp); - lck_attr_free(SCTP_BASE_INFO(sctbinfo).mtx_attr); -#else - lck_grp_attr_free(SCTP_BASE_INFO(sctbinfo).ipi_lock_grp_attr); - lck_grp_free(SCTP_BASE_INFO(sctbinfo).ipi_lock_grp); - lck_attr_free(SCTP_BASE_INFO(sctbinfo).ipi_lock_attr); -#endif -#endif -#if defined(__Userspace__) - SCTP_TIMERQ_LOCK_DESTROY(); - SCTP_ZONE_DESTROY(zone_mbuf); - SCTP_ZONE_DESTROY(zone_clust); - SCTP_ZONE_DESTROY(zone_ext_refcnt); -#endif - /* Get rid of other stuff too. */ - if (SCTP_BASE_INFO(sctp_asochash) != NULL) - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark)); - if (SCTP_BASE_INFO(sctp_ephash) != NULL) - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark)); - if (SCTP_BASE_INFO(sctp_tcpephash) != NULL) - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark)); - -#if defined(_WIN32) || defined(__FreeBSD__) || defined(__Userspace__) - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_ep)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asoc)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_laddr)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_net)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_chunk)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_readq)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_strmoq)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf)); - SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf_ack)); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) - SCTP_FREE(SCTP_BASE_STATS, SCTP_M_MCORE); -#endif -#endif -} - -int -sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, - int offset, int limit, - struct sockaddr *src, struct sockaddr *dst, - struct sockaddr *altsa, uint16_t port) -{ - /* - * grub through the INIT pulling addresses and loading them to the - * nets structure in the asoc. The from address in the mbuf should - * also be loaded (if it is not already). This routine can be called - * with either INIT or INIT-ACK's as long as the m points to the IP - * packet and the offset points to the beginning of the parameters. - */ - struct sctp_inpcb *inp; - struct sctp_nets *net, *nnet, *net_tmp; - struct sctp_paramhdr *phdr, param_buf; - struct sctp_tcb *stcb_tmp; - uint16_t ptype, plen; - struct sockaddr *sa; - uint8_t random_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_random *p_random = NULL; - uint16_t random_len = 0; - uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_hmac_algo *hmacs = NULL; - uint16_t hmacs_len = 0; - uint8_t saw_asconf = 0; - uint8_t saw_asconf_ack = 0; - uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_chunk_list *chunks = NULL; - uint16_t num_chunks = 0; - sctp_key_t *new_key; - uint32_t keylen; - int got_random = 0, got_hmacs = 0, got_chklist = 0; - uint8_t peer_supports_ecn; - uint8_t peer_supports_prsctp; - uint8_t peer_supports_auth; - uint8_t peer_supports_asconf; - uint8_t peer_supports_asconf_ack; - uint8_t peer_supports_reconfig; - uint8_t peer_supports_nrsack; - uint8_t peer_supports_pktdrop; - uint8_t peer_supports_idata; -#ifdef INET - struct sockaddr_in sin; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - - /* First get the destination address setup too. */ -#ifdef INET - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin.sin_len = sizeof(sin); -#endif - sin.sin_port = stcb->rport; -#endif -#ifdef INET6 - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6.sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6.sin6_port = stcb->rport; -#endif - if (altsa) { - sa = altsa; - } else { - sa = src; - } - peer_supports_idata = 0; - peer_supports_ecn = 0; - peer_supports_prsctp = 0; - peer_supports_auth = 0; - peer_supports_asconf = 0; - peer_supports_asconf_ack = 0; - peer_supports_reconfig = 0; - peer_supports_nrsack = 0; - peer_supports_pktdrop = 0; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - /* mark all addresses that we have currently on the list */ - net->dest_state |= SCTP_ADDR_NOT_IN_ASSOC; - } - /* does the source address already exist? if so skip it */ - inp = stcb->sctp_ep; - atomic_add_int(&stcb->asoc.refcnt, 1); - stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net_tmp, dst, stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - - if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || inp == NULL) { - /* we must add the source address */ - /* no scope set here since we have a tcb already. */ - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - if (stcb->asoc.scope.ipv4_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { - return (-1); - } - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (stcb->asoc.scope.ipv6_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { - return (-2); - } - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (stcb->asoc.scope.conn_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { - return (-2); - } - } - break; -#endif - default: - break; - } - } else { - if (net_tmp != NULL && stcb_tmp == stcb) { - net_tmp->dest_state &= ~SCTP_ADDR_NOT_IN_ASSOC; - } else if (stcb_tmp != stcb) { - /* It belongs to another association? */ - if (stcb_tmp) - SCTP_TCB_UNLOCK(stcb_tmp); - return (-3); - } - } - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-4); - } - /* now we must go through each of the params. */ - phdr = sctp_get_next_param(m, offset, ¶m_buf, sizeof(param_buf)); - while (phdr) { - ptype = ntohs(phdr->param_type); - plen = ntohs(phdr->param_length); - /* - * SCTP_PRINTF("ptype => %0x, plen => %d\n", (uint32_t)ptype, - * (int)plen); - */ - if (offset + plen > limit) { - break; - } - if (plen < sizeof(struct sctp_paramhdr)) { - break; - } -#ifdef INET - if (ptype == SCTP_IPV4_ADDRESS) { - if (stcb->asoc.scope.ipv4_addr_legal) { - struct sctp_ipv4addr_param *p4, p4_buf; - - /* ok get the v4 address and check/add */ - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&p4_buf, - sizeof(p4_buf)); - if (plen != sizeof(struct sctp_ipv4addr_param) || - phdr == NULL) { - return (-5); - } - p4 = (struct sctp_ipv4addr_param *)phdr; - sin.sin_addr.s_addr = p4->addr; - if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { - /* Skip multi-cast addresses */ - goto next_param; - } - if ((sin.sin_addr.s_addr == INADDR_BROADCAST) || - (sin.sin_addr.s_addr == INADDR_ANY)) { - goto next_param; - } - sa = (struct sockaddr *)&sin; - inp = stcb->sctp_ep; - atomic_add_int(&stcb->asoc.refcnt, 1); - stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, - dst, stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - - if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || - inp == NULL) { - /* we must add the source address */ - /* - * no scope set since we have a tcb - * already - */ - - /* - * we must validate the state again - * here - */ - add_it_now: - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-7); - } - if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { - return (-8); - } - } else if (stcb_tmp == stcb) { - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-10); - } - if (net != NULL) { - /* clear flag */ - net->dest_state &= - ~SCTP_ADDR_NOT_IN_ASSOC; - } - } else { - /* - * strange, address is in another - * assoc? straighten out locks. - */ - if (stcb_tmp) { - if (SCTP_GET_STATE(stcb_tmp) == SCTP_STATE_COOKIE_WAIT) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - /* in setup state we abort this guy */ - SCTP_SNPRINTF(msg, sizeof(msg), - "%s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - sctp_abort_an_association(stcb_tmp->sctp_ep, - stcb_tmp, op_err, false, - SCTP_SO_NOT_LOCKED); - goto add_it_now; - } - SCTP_TCB_UNLOCK(stcb_tmp); - } - - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-12); - } - return (-13); - } - } - } else -#endif -#ifdef INET6 - if (ptype == SCTP_IPV6_ADDRESS) { - if (stcb->asoc.scope.ipv6_addr_legal) { - /* ok get the v6 address and check/add */ - struct sctp_ipv6addr_param *p6, p6_buf; - - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&p6_buf, - sizeof(p6_buf)); - if (plen != sizeof(struct sctp_ipv6addr_param) || - phdr == NULL) { - return (-14); - } - p6 = (struct sctp_ipv6addr_param *)phdr; - memcpy((caddr_t)&sin6.sin6_addr, p6->addr, - sizeof(p6->addr)); - if (IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) { - /* Skip multi-cast addresses */ - goto next_param; - } - if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { - /* Link local make no sense without scope */ - goto next_param; - } - sa = (struct sockaddr *)&sin6; - inp = stcb->sctp_ep; - atomic_add_int(&stcb->asoc.refcnt, 1); - stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, - dst, stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb_tmp == NULL && - (inp == stcb->sctp_ep || inp == NULL)) { - /* - * we must validate the state again - * here - */ - add_it_now6: - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-16); - } - /* - * we must add the address, no scope - * set - */ - if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { - return (-17); - } - } else if (stcb_tmp == stcb) { - /* - * we must validate the state again - * here - */ - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-19); - } - if (net != NULL) { - /* clear flag */ - net->dest_state &= - ~SCTP_ADDR_NOT_IN_ASSOC; - } - } else { - /* - * strange, address is in another - * assoc? straighten out locks. - */ - if (stcb_tmp) { - if (SCTP_GET_STATE(stcb_tmp) == SCTP_STATE_COOKIE_WAIT) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - - /* in setup state we abort this guy */ - SCTP_SNPRINTF(msg, sizeof(msg), - "%s:%d at %s", __FILE__, __LINE__, __func__); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - msg); - sctp_abort_an_association(stcb_tmp->sctp_ep, - stcb_tmp, op_err, false, - SCTP_SO_NOT_LOCKED); - goto add_it_now6; - } - SCTP_TCB_UNLOCK(stcb_tmp); - } - if (stcb->asoc.state == 0) { - /* the assoc was freed? */ - return (-21); - } - return (-22); - } - } - } else -#endif - if (ptype == SCTP_ECN_CAPABLE) { - peer_supports_ecn = 1; - } else if (ptype == SCTP_ULP_ADAPTATION) { - if (stcb->asoc.state != SCTP_STATE_OPEN) { - struct sctp_adaptation_layer_indication ai, *aip; - - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&ai, sizeof(ai)); - aip = (struct sctp_adaptation_layer_indication *)phdr; - if (aip) { - stcb->asoc.peers_adaptation = ntohl(aip->indication); - stcb->asoc.adaptation_needed = 1; - } - } - } else if (ptype == SCTP_SET_PRIM_ADDR) { - struct sctp_asconf_addr_param lstore, *fee; - int lptype; - struct sockaddr *lsa = NULL; -#ifdef INET - struct sctp_asconf_addrv4_param *fii; -#endif - - if (stcb->asoc.asconf_supported == 0) { - return (-100); - } - if (plen > sizeof(lstore)) { - return (-23); - } - if (plen < sizeof(struct sctp_asconf_addrv4_param)) { - return (-101); - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&lstore, - plen); - if (phdr == NULL) { - return (-24); - } - fee = (struct sctp_asconf_addr_param *)phdr; - lptype = ntohs(fee->addrp.ph.param_type); - switch (lptype) { -#ifdef INET - case SCTP_IPV4_ADDRESS: - if (plen != - sizeof(struct sctp_asconf_addrv4_param)) { - SCTP_PRINTF("Sizeof setprim in init/init ack not %d but %d - ignored\n", - (int)sizeof(struct sctp_asconf_addrv4_param), - plen); - } else { - fii = (struct sctp_asconf_addrv4_param *)fee; - sin.sin_addr.s_addr = fii->addrp.addr; - lsa = (struct sockaddr *)&sin; - } - break; -#endif -#ifdef INET6 - case SCTP_IPV6_ADDRESS: - if (plen != - sizeof(struct sctp_asconf_addr_param)) { - SCTP_PRINTF("Sizeof setprim (v6) in init/init ack not %d but %d - ignored\n", - (int)sizeof(struct sctp_asconf_addr_param), - plen); - } else { - memcpy(sin6.sin6_addr.s6_addr, - fee->addrp.addr, - sizeof(fee->addrp.addr)); - lsa = (struct sockaddr *)&sin6; - } - break; -#endif - default: - break; - } - if (lsa) { - (void)sctp_set_primary_addr(stcb, sa, NULL); - } - } else if (ptype == SCTP_HAS_NAT_SUPPORT) { - stcb->asoc.peer_supports_nat = 1; - } else if (ptype == SCTP_PRSCTP_SUPPORTED) { - /* Peer supports pr-sctp */ - peer_supports_prsctp = 1; - } else if (ptype == SCTP_ZERO_CHECKSUM_ACCEPTABLE) { - struct sctp_zero_checksum_acceptable zero_chksum, *zero_chksum_p; - - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&zero_chksum, - sizeof(struct sctp_zero_checksum_acceptable)); - if (phdr != NULL) { - /* - * Only send zero checksums if the upper layer - * has enabled the support for the same method - * as allowed by the peer. - */ - zero_chksum_p = (struct sctp_zero_checksum_acceptable *)phdr; - if ((ntohl(zero_chksum_p->edmid) != SCTP_EDMID_NONE) && - (ntohl(zero_chksum_p->edmid) == stcb->asoc.rcv_edmid)) { - stcb->asoc.snd_edmid = stcb->asoc.rcv_edmid; - } - } - } else if (ptype == SCTP_SUPPORTED_CHUNK_EXT) { - /* A supported extension chunk */ - struct sctp_supported_chunk_types_param *pr_supported; - uint8_t local_store[SCTP_PARAM_BUFFER_SIZE]; - int num_ent, i; - - if (plen > sizeof(local_store)) { - return (-35); - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&local_store, plen); - if (phdr == NULL) { - return (-25); - } - pr_supported = (struct sctp_supported_chunk_types_param *)phdr; - num_ent = plen - sizeof(struct sctp_paramhdr); - for (i = 0; i < num_ent; i++) { - switch (pr_supported->chunk_types[i]) { - case SCTP_ASCONF: - peer_supports_asconf = 1; - break; - case SCTP_ASCONF_ACK: - peer_supports_asconf_ack = 1; - break; - case SCTP_FORWARD_CUM_TSN: - peer_supports_prsctp = 1; - break; - case SCTP_PACKET_DROPPED: - peer_supports_pktdrop = 1; - break; - case SCTP_NR_SELECTIVE_ACK: - peer_supports_nrsack = 1; - break; - case SCTP_STREAM_RESET: - peer_supports_reconfig = 1; - break; - case SCTP_AUTHENTICATION: - peer_supports_auth = 1; - break; - case SCTP_IDATA: - peer_supports_idata = 1; - break; - default: - /* one I have not learned yet */ - break; - } - } - } else if (ptype == SCTP_RANDOM) { - if (plen > sizeof(random_store)) - break; - if (got_random) { - /* already processed a RANDOM */ - goto next_param; - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)random_store, - plen); - if (phdr == NULL) - return (-26); - p_random = (struct sctp_auth_random *)phdr; - random_len = plen - sizeof(*p_random); - /* enforce the random length */ - if (random_len != SCTP_AUTH_RANDOM_SIZE_REQUIRED) { - SCTPDBG(SCTP_DEBUG_AUTH1, "SCTP: invalid RANDOM len\n"); - return (-27); - } - got_random = 1; - } else if (ptype == SCTP_HMAC_LIST) { - uint16_t num_hmacs; - uint16_t i; - - if (plen > sizeof(hmacs_store)) - break; - if (got_hmacs) { - /* already processed a HMAC list */ - goto next_param; - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)hmacs_store, - plen); - if (phdr == NULL) - return (-28); - hmacs = (struct sctp_auth_hmac_algo *)phdr; - hmacs_len = plen - sizeof(*hmacs); - num_hmacs = hmacs_len / sizeof(hmacs->hmac_ids[0]); - /* validate the hmac list */ - if (sctp_verify_hmac_param(hmacs, num_hmacs)) { - return (-29); - } - if (stcb->asoc.peer_hmacs != NULL) - sctp_free_hmaclist(stcb->asoc.peer_hmacs); - stcb->asoc.peer_hmacs = sctp_alloc_hmaclist(num_hmacs); - if (stcb->asoc.peer_hmacs != NULL) { - for (i = 0; i < num_hmacs; i++) { - (void)sctp_auth_add_hmacid(stcb->asoc.peer_hmacs, - ntohs(hmacs->hmac_ids[i])); - } - } - got_hmacs = 1; - } else if (ptype == SCTP_CHUNK_LIST) { - int i; - - if (plen > sizeof(chunks_store)) - break; - if (got_chklist) { - /* already processed a Chunks list */ - goto next_param; - } - phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)chunks_store, - plen); - if (phdr == NULL) - return (-30); - chunks = (struct sctp_auth_chunk_list *)phdr; - num_chunks = plen - sizeof(*chunks); - if (stcb->asoc.peer_auth_chunks != NULL) - sctp_clear_chunklist(stcb->asoc.peer_auth_chunks); - else - stcb->asoc.peer_auth_chunks = sctp_alloc_chunklist(); - for (i = 0; i < num_chunks; i++) { - (void)sctp_auth_add_chunk(chunks->chunk_types[i], - stcb->asoc.peer_auth_chunks); - /* record asconf/asconf-ack if listed */ - if (chunks->chunk_types[i] == SCTP_ASCONF) - saw_asconf = 1; - if (chunks->chunk_types[i] == SCTP_ASCONF_ACK) - saw_asconf_ack = 1; - } - got_chklist = 1; - } else if ((ptype == SCTP_HEARTBEAT_INFO) || - (ptype == SCTP_STATE_COOKIE) || - (ptype == SCTP_UNRECOG_PARAM) || - (ptype == SCTP_COOKIE_PRESERVE) || - (ptype == SCTP_SUPPORTED_ADDRTYPE) || - (ptype == SCTP_ADD_IP_ADDRESS) || - (ptype == SCTP_DEL_IP_ADDRESS) || - (ptype == SCTP_ERROR_CAUSE_IND) || - (ptype == SCTP_SUCCESS_REPORT)) { - /* don't care */ - } else { - if ((ptype & 0x8000) == 0x0000) { - /* - * must stop processing the rest of the - * param's. Any report bits were handled - * with the call to - * sctp_arethere_unrecognized_parameters() - * when the INIT or INIT-ACK was first seen. - */ - break; - } - } - - next_param: - offset += SCTP_SIZE32(plen); - if (offset >= limit) { - break; - } - phdr = sctp_get_next_param(m, offset, ¶m_buf, - sizeof(param_buf)); - } - /* Now check to see if we need to purge any addresses */ - TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) { - if ((net->dest_state & SCTP_ADDR_NOT_IN_ASSOC) == - SCTP_ADDR_NOT_IN_ASSOC) { - /* This address has been removed from the asoc */ - /* remove and free it */ - stcb->asoc.numnets--; - TAILQ_REMOVE(&stcb->asoc.nets, net, sctp_next); - if (net == stcb->asoc.alternate) { - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - if (net == stcb->asoc.primary_destination) { - stcb->asoc.primary_destination = NULL; - sctp_select_primary_destination(stcb); - } - sctp_free_remote_addr(net); - } - } - if ((stcb->asoc.ecn_supported == 1) && - (peer_supports_ecn == 0)) { - stcb->asoc.ecn_supported = 0; - } - if ((stcb->asoc.prsctp_supported == 1) && - (peer_supports_prsctp == 0)) { - stcb->asoc.prsctp_supported = 0; - } - if ((stcb->asoc.auth_supported == 1) && - ((peer_supports_auth == 0) || - (got_random == 0) || (got_hmacs == 0))) { - stcb->asoc.auth_supported = 0; - } - if ((stcb->asoc.asconf_supported == 1) && - ((peer_supports_asconf == 0) || (peer_supports_asconf_ack == 0) || - (stcb->asoc.auth_supported == 0) || - (saw_asconf == 0) || (saw_asconf_ack == 0))) { - stcb->asoc.asconf_supported = 0; - } - if ((stcb->asoc.reconfig_supported == 1) && - (peer_supports_reconfig == 0)) { - stcb->asoc.reconfig_supported = 0; - } - if ((stcb->asoc.idata_supported == 1) && - (peer_supports_idata == 0)) { - stcb->asoc.idata_supported = 0; - } - if ((stcb->asoc.nrsack_supported == 1) && - (peer_supports_nrsack == 0)) { - stcb->asoc.nrsack_supported = 0; - } - if ((stcb->asoc.pktdrop_supported == 1) && - (peer_supports_pktdrop == 0)) { - stcb->asoc.pktdrop_supported = 0; - } - /* validate authentication required parameters */ - if ((peer_supports_auth == 0) && (got_chklist == 1)) { - /* peer does not support auth but sent a chunks list? */ - return (-31); - } - if ((peer_supports_asconf == 1) && (peer_supports_auth == 0)) { - /* peer supports asconf but not auth? */ - return (-32); - } else if ((peer_supports_asconf == 1) && - (peer_supports_auth == 1) && - ((saw_asconf == 0) || (saw_asconf_ack == 0))) { - return (-33); - } - /* concatenate the full random key */ - keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; - if (chunks != NULL) { - keylen += sizeof(*chunks) + num_chunks; - } - new_key = sctp_alloc_key(keylen); - if (new_key != NULL) { - /* copy in the RANDOM */ - if (p_random != NULL) { - keylen = sizeof(*p_random) + random_len; - memcpy(new_key->key, p_random, keylen); - } else { - keylen = 0; - } - /* append in the AUTH chunks */ - if (chunks != NULL) { - memcpy(new_key->key + keylen, chunks, - sizeof(*chunks) + num_chunks); - keylen += sizeof(*chunks) + num_chunks; - } - /* append in the HMACs */ - if (hmacs != NULL) { - memcpy(new_key->key + keylen, hmacs, - sizeof(*hmacs) + hmacs_len); - } - } else { - /* failed to get memory for the key */ - return (-34); - } - if (stcb->asoc.authinfo.peer_random != NULL) - sctp_free_key(stcb->asoc.authinfo.peer_random); - stcb->asoc.authinfo.peer_random = new_key; - sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.assoc_keyid); - sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.recv_keyid); - - return (0); -} - -int -sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa, - struct sctp_nets *net) -{ - /* make sure the requested primary address exists in the assoc */ - if (net == NULL && sa) - net = sctp_findnet(stcb, sa); - - if (net == NULL) { - /* didn't find the requested primary address! */ - return (-1); - } else { - /* set the primary address */ - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { - /* Must be confirmed, so queue to set */ - net->dest_state |= SCTP_ADDR_REQ_PRIMARY; - return (0); - } - stcb->asoc.primary_destination = net; - if (((net->dest_state & SCTP_ADDR_PF) == 0) && - (stcb->asoc.alternate != NULL)) { - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - net = TAILQ_FIRST(&stcb->asoc.nets); - if (net != stcb->asoc.primary_destination) { - /* first one on the list is NOT the primary - * sctp_cmpaddr() is much more efficient if - * the primary is the first on the list, make it - * so. - */ - TAILQ_REMOVE(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); - TAILQ_INSERT_HEAD(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); - } - return (0); - } -} - -bool -sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now) -{ - struct sctpasochead *head; - struct sctp_tcb *stcb; - - SCTP_INP_INFO_LOCK_ASSERT(); - - head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, SCTP_BASE_INFO(hashasocmark))]; - LIST_FOREACH(stcb, head, sctp_asocs) { - /* We choose not to lock anything here. TCB's can't be - * removed since we have the read lock, so they can't - * be freed on us, same thing for the INP. I may - * be wrong with this assumption, but we will go - * with it for now :-) - */ - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - continue; - } - if (stcb->asoc.my_vtag == tag) { - /* candidate */ - if (stcb->rport != rport) { - continue; - } - if (stcb->sctp_ep->sctp_lport != lport) { - continue; - } - /* The tag is currently used, so don't use it. */ - return (false); - } - } - return (!sctp_is_in_timewait(tag, lport, rport, (uint32_t)now->tv_sec)); -} - -static void -sctp_drain_mbufs(struct sctp_tcb *stcb) -{ - /* - * We must hunt this association for MBUF's past the cumack (i.e. - * out of order data that we can renege on). - */ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk, *nchk; - uint32_t cumulative_tsn_p1; - struct sctp_queued_to_read *control, *ncontrol; - int cnt, strmat; - uint32_t gap, i; - int fnd = 0; - - /* We look for anything larger than the cum-ack + 1 */ - - asoc = &stcb->asoc; - if (asoc->cumulative_tsn == asoc->highest_tsn_inside_map) { - /* none we can reneg on. */ - return; - } - SCTP_STAT_INCR(sctps_protocol_drains_done); - cumulative_tsn_p1 = asoc->cumulative_tsn + 1; - cnt = 0; - /* Ok that was fun, now we will drain all the inbound streams? */ - for (strmat = 0; strmat < asoc->streamincnt; strmat++) { - TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].inqueue, next_instrm, ncontrol) { -#ifdef INVARIANTS - if (control->on_strm_q != SCTP_ON_ORDERED) { - panic("Huh control: %p on_q: %d -- not ordered?", - control, control->on_strm_q); - } -#endif - if (SCTP_TSN_GT(control->sinfo_tsn, cumulative_tsn_p1)) { - /* Yep it is above cum-ack */ - cnt++; - SCTP_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn); - KASSERT(control->length > 0, ("control has zero length")); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - if (control->on_read_q) { - TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next); - control->on_read_q = 0; - } - TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, control, next_instrm); - control->on_strm_q = 0; - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_free_remote_addr(control->whoFrom); - /* Now its reasm? */ - TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { - cnt++; - SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn); - KASSERT(chk->send_size > 0, ("chunk has zero length")); - if (asoc->size_on_reasm_queue >= chk->send_size) { - asoc->size_on_reasm_queue -= chk->send_size; - } else { -#ifdef INVARIANTS - panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size); -#else - asoc->size_on_reasm_queue = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - sctp_free_a_readq(stcb, control); - } - } - TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].uno_inqueue, next_instrm, ncontrol) { -#ifdef INVARIANTS - if (control->on_strm_q != SCTP_ON_UNORDERED) { - panic("Huh control: %p on_q: %d -- not unordered?", - control, control->on_strm_q); - } -#endif - if (SCTP_TSN_GT(control->sinfo_tsn, cumulative_tsn_p1)) { - /* Yep it is above cum-ack */ - cnt++; - SCTP_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn); - KASSERT(control->length > 0, ("control has zero length")); - if (asoc->size_on_all_streams >= control->length) { - asoc->size_on_all_streams -= control->length; - } else { -#ifdef INVARIANTS - panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length); -#else - asoc->size_on_all_streams = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_all_streams); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - if (control->on_read_q) { - TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next); - control->on_read_q = 0; - } - TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, control, next_instrm); - control->on_strm_q = 0; - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_free_remote_addr(control->whoFrom); - /* Now its reasm? */ - TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { - cnt++; - SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn); - KASSERT(chk->send_size > 0, ("chunk has zero length")); - if (asoc->size_on_reasm_queue >= chk->send_size) { - asoc->size_on_reasm_queue -= chk->send_size; - } else { -#ifdef INVARIANTS - panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size); -#else - asoc->size_on_reasm_queue = 0; -#endif - } - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - TAILQ_REMOVE(&control->reasm, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - sctp_free_a_readq(stcb, control); - } - } - } - if (cnt) { - /* We must back down to see what the new highest is */ - for (i = asoc->highest_tsn_inside_map; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) { - SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn); - if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { - asoc->highest_tsn_inside_map = i; - fnd = 1; - break; - } - } - if (!fnd) { - asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1; - } - - /* - * Question, should we go through the delivery queue? The only - * reason things are on here is the app not reading OR a p-d-api up. - * An attacker COULD send enough in to initiate the PD-API and then - * send a bunch of stuff to other streams... these would wind up on - * the delivery queue.. and then we would not get to them. But in - * order to do this I then have to back-track and un-deliver - * sequence numbers in streams.. el-yucko. I think for now we will - * NOT look at the delivery queue and leave it to be something to - * consider later. An alternative would be to abort the P-D-API with - * a notification and then deliver the data.... Or another method - * might be to keep track of how many times the situation occurs and - * if we see a possible attack underway just abort the association. - */ -#ifdef SCTP_DEBUG - SCTPDBG(SCTP_DEBUG_PCB1, "Freed %d chunks from reneg harvest\n", cnt); -#endif - /* - * Now do we need to find a new - * asoc->highest_tsn_inside_map? - */ - asoc->last_revoke_count = cnt; - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_PCB + SCTP_LOC_11); - /*sa_ignore NO_NULL_CHK*/ - sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN, SCTP_SO_NOT_LOCKED); - } - /* - * Another issue, in un-setting the TSN's in the mapping array we - * DID NOT adjust the highest_tsn marker. This will cause one of two - * things to occur. It may cause us to do extra work in checking for - * our mapping array movement. More importantly it may cause us to - * SACK every datagram. This may not be a bad thing though since we - * will recover once we get our cum-ack above and all this stuff we - * dumped recovered. - */ -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static void -#else -void -#endif -sctp_drain(void) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; - VNET_ITERATOR_DECL(vnet_iter); - - NET_EPOCH_ENTER(et); -#else - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - - SCTP_STAT_INCR(sctps_protocol_drain_calls); - if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { - return; - } -#endif - /* - * We must walk the PCB lists for ALL associations here. The system - * is LOW on MBUF's and needs help. This is where reneging will - * occur. We really hope this does NOT happen! - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - VNET_LIST_RLOCK_NOSLEEP(); - VNET_FOREACH(vnet_iter) { - CURVNET_SET(vnet_iter); - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_STAT_INCR(sctps_protocol_drain_calls); - if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { -#ifdef VIMAGE - continue; -#else - NET_EPOCH_EXIT(et); - return; -#endif - } -#endif - SCTP_INP_INFO_RLOCK(); - LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) { - /* For each endpoint */ - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - /* For each association */ - SCTP_TCB_LOCK(stcb); - sctp_drain_mbufs(stcb); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - SCTP_INP_INFO_RUNLOCK(); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_RESTORE(); - } - VNET_LIST_RUNLOCK_NOSLEEP(); - NET_EPOCH_EXIT(et); -#endif -} -#if defined(__FreeBSD__) && !defined(__Userspace__) -EVENTHANDLER_DEFINE(vm_lowmem, sctp_drain, NULL, LOWMEM_PRI_DEFAULT); -EVENTHANDLER_DEFINE(mbuf_lowmem, sctp_drain, NULL, LOWMEM_PRI_DEFAULT); -#endif - -/* - * start a new iterator - * iterates through all endpoints and associations based on the pcb_state - * flags and asoc_state. "af" (mandatory) is executed for all matching - * assocs and "ef" (optional) is executed when the iterator completes. - * "inpf" (optional) is executed for each new endpoint as it is being - * iterated through. inpe (optional) is called when the inp completes - * its way through all the stcbs. - */ -int -sctp_initiate_iterator(inp_func inpf, - asoc_func af, - inp_func inpe, - uint32_t pcb_state, - uint32_t pcb_features, - uint32_t asoc_state, - void *argp, - uint32_t argi, - end_func ef, - struct sctp_inpcb *s_inp, - uint8_t chunk_output_off) -{ - struct sctp_iterator *it = NULL; - - if (af == NULL) { - return (-1); - } - if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { - SCTP_PRINTF("%s: abort on initialize being %d\n", __func__, - SCTP_BASE_VAR(sctp_pcb_initialized)); - return (-1); - } - SCTP_MALLOC(it, struct sctp_iterator *, sizeof(struct sctp_iterator), - SCTP_M_ITER); - if (it == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM); - return (-1); - } - memset(it, 0, sizeof(*it)); - it->function_assoc = af; - it->function_inp = inpf; - if (inpf) - it->done_current_ep = 0; - else - it->done_current_ep = 1; - it->function_atend = ef; - it->pointer = argp; - it->val = argi; - it->pcb_flags = pcb_state; - it->pcb_features = pcb_features; - it->asoc_state = asoc_state; - it->function_inp_end = inpe; - it->no_chunk_output = chunk_output_off; -#if defined(__FreeBSD__) && !defined(__Userspace__) - it->vn = curvnet; -#endif - if (s_inp) { - /* Assume lock is held here */ - it->inp = s_inp; - SCTP_INP_INCR_REF(it->inp); - it->iterator_flags = SCTP_ITERATOR_DO_SINGLE_INP; - } else { - SCTP_INP_INFO_RLOCK(); - it->inp = LIST_FIRST(&SCTP_BASE_INFO(listhead)); - if (it->inp) { - SCTP_INP_INCR_REF(it->inp); - } - SCTP_INP_INFO_RUNLOCK(); - it->iterator_flags = SCTP_ITERATOR_DO_ALL_INP; - } - SCTP_IPI_ITERATOR_WQ_LOCK(); - if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { - SCTP_IPI_ITERATOR_WQ_UNLOCK(); - SCTP_PRINTF("%s: rollback on initialize being %d it=%p\n", __func__, - SCTP_BASE_VAR(sctp_pcb_initialized), it); - SCTP_FREE(it, SCTP_M_ITER); - return (-1); - } - TAILQ_INSERT_TAIL(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); - if (sctp_it_ctl.iterator_running == 0) { - sctp_wakeup_iterator(); - } - SCTP_IPI_ITERATOR_WQ_UNLOCK(); - /* sa_ignore MEMLEAK {memory is put on the tailq for the iterator} */ - return (0); -} - -/* - * Atomically add flags to the sctp_flags of an inp. - * To be used when the write lock of the inp is not held. - */ -void -sctp_pcb_add_flags(struct sctp_inpcb *inp, uint32_t flags) -{ - uint32_t old_flags, new_flags; - - do { - old_flags = inp->sctp_flags; - new_flags = old_flags | flags; - } while (atomic_cmpset_int(&inp->sctp_flags, old_flags, new_flags) == 0); -} diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.h deleted file mode 100644 index aabd328c..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_pcb.h +++ /dev/null @@ -1,881 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_PCB_H_ -#define _NETINET_SCTP_PCB_H_ - -#include -#include -#include -#include - -LIST_HEAD(sctppcbhead, sctp_inpcb); -LIST_HEAD(sctpasochead, sctp_tcb); -LIST_HEAD(sctpladdr, sctp_laddr); -LIST_HEAD(sctpvtaghead, sctp_tagblock); -LIST_HEAD(sctp_vrflist, sctp_vrf); -LIST_HEAD(sctp_ifnlist, sctp_ifn); -LIST_HEAD(sctp_ifalist, sctp_ifa); -TAILQ_HEAD(sctp_readhead, sctp_queued_to_read); -TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending); - -#include -#include - -#define SCTP_PCBHASH_ALLADDR(port, mask) (port & mask) -#define SCTP_PCBHASH_ASOC(tag, mask) (tag & mask) - -struct sctp_vrf { - LIST_ENTRY (sctp_vrf) next_vrf; - struct sctp_ifalist *vrf_addr_hash; - struct sctp_ifnlist ifnlist; - uint32_t vrf_id; - uint32_t tbl_id_v4; /* default v4 table id */ - uint32_t tbl_id_v6; /* default v6 table id */ - uint32_t total_ifa_count; - u_long vrf_addr_hashmark; - uint32_t refcount; -}; - -struct sctp_ifn { - struct sctp_ifalist ifalist; - struct sctp_vrf *vrf; - LIST_ENTRY(sctp_ifn) next_ifn; - LIST_ENTRY(sctp_ifn) next_bucket; - void *ifn_p; /* never access without appropriate lock */ - uint32_t ifn_mtu; - uint32_t ifn_type; - uint32_t ifn_index; /* shorthand way to look at ifn for reference */ - uint32_t refcount; /* number of reference held should be >= ifa_count */ - uint32_t ifa_count; /* IFA's we hold (in our list - ifalist)*/ - uint32_t num_v6; /* number of v6 addresses */ - uint32_t num_v4; /* number of v4 addresses */ - uint32_t registered_af; /* registered address family for i/f events */ - char ifn_name[SCTP_IFNAMSIZ]; -}; - -/* SCTP local IFA flags */ -#define SCTP_ADDR_VALID 0x00000001 /* its up and active */ -#define SCTP_BEING_DELETED 0x00000002 /* being deleted, - * when refcount = 0. Note - * that it is pulled from the ifn list - * and ifa_p is nulled right away but - * it cannot be freed until the last *net - * pointing to it is deleted. - */ -#define SCTP_ADDR_DEFER_USE 0x00000004 /* Hold off using this one */ -#define SCTP_ADDR_IFA_UNUSEABLE 0x00000008 - -struct sctp_ifa { - LIST_ENTRY(sctp_ifa) next_ifa; - LIST_ENTRY(sctp_ifa) next_bucket; - struct sctp_ifn *ifn_p; /* back pointer to parent ifn */ - void *ifa; /* pointer to ifa, needed for flag - * update for that we MUST lock - * appropriate locks. This is for V6. - */ - union sctp_sockstore address; - uint32_t refcount; /* number of folks referring to this */ - uint32_t flags; - uint32_t localifa_flags; - uint32_t vrf_id; /* vrf_id of this addr (for deleting) */ - uint8_t src_is_loop; - uint8_t src_is_priv; - uint8_t src_is_glob; - uint8_t resv; -}; - -struct sctp_laddr { - LIST_ENTRY(sctp_laddr) sctp_nxt_addr; /* next in list */ - struct sctp_ifa *ifa; - uint32_t action; /* Used during asconf and adding - * if no-zero src-addr selection will - * not consider this address. - */ - struct timeval start_time; /* time when this address was created */ -}; - -struct sctp_block_entry { - int error; -}; - -struct sctp_timewait { - uint32_t tv_sec_at_expire; /* the seconds from boot to expire */ - uint32_t v_tag; /* the vtag that can not be reused */ - uint16_t lport; /* the local port used in vtag */ - uint16_t rport; /* the remote port used in vtag */ -}; - -struct sctp_tagblock { - LIST_ENTRY(sctp_tagblock) sctp_nxt_tagblock; - struct sctp_timewait vtag_block[SCTP_NUMBER_IN_VTAG_BLOCK]; -}; - -struct sctp_epinfo { -#if defined(__FreeBSD__) && !defined(__Userspace__) -#ifdef INET - struct socket *udp4_tun_socket; -#endif -#ifdef INET6 - struct socket *udp6_tun_socket; -#endif -#endif - struct sctpasochead *sctp_asochash; - u_long hashasocmark; - - struct sctppcbhead *sctp_ephash; - u_long hashmark; - - /*- - * The TCP model represents a substantial overhead in that we get an - * additional hash table to keep explicit connections in. The - * listening TCP endpoint will exist in the usual ephash above and - * accept only INIT's. It will be incapable of sending off an INIT. - * When a dg arrives we must look in the normal ephash. If we find a - * TCP endpoint that will tell us to go to the specific endpoint - * hash and re-hash to find the right assoc/socket. If we find a UDP - * model socket we then must complete the lookup. If this fails, - * i.e. no association can be found then we must continue to see if - * a sctp_peeloff()'d socket is in the tcpephash (a spun off socket - * acts like a TCP model connected socket). - */ - struct sctppcbhead *sctp_tcpephash; - u_long hashtcpmark; - uint32_t hashtblsize; - - struct sctp_vrflist *sctp_vrfhash; - u_long hashvrfmark; - - struct sctp_ifnlist *vrf_ifn_hash; - u_long vrf_ifn_hashmark; - - struct sctppcbhead listhead; - struct sctpladdr addr_wq; - -#if defined(__APPLE__) && !defined(__Userspace__) - struct inpcbhead inplisthead; - struct inpcbinfo sctbinfo; -#endif - /* ep zone info */ - sctp_zone_t ipi_zone_ep; - sctp_zone_t ipi_zone_asoc; - sctp_zone_t ipi_zone_laddr; - sctp_zone_t ipi_zone_net; - sctp_zone_t ipi_zone_chunk; - sctp_zone_t ipi_zone_readq; - sctp_zone_t ipi_zone_strmoq; - sctp_zone_t ipi_zone_asconf; - sctp_zone_t ipi_zone_asconf_ack; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct rwlock ipi_ep_mtx; - struct mtx ipi_iterator_wq_mtx; - struct rwlock ipi_addr_mtx; - struct mtx ipi_pktlog_mtx; - struct mtx wq_addr_mtx; -#elif defined(SCTP_PROCESS_LEVEL_LOCKS) - userland_rwlock_t ipi_ep_mtx; - userland_rwlock_t ipi_addr_mtx; - userland_mutex_t ipi_count_mtx; - userland_mutex_t ipi_pktlog_mtx; - userland_mutex_t wq_addr_mtx; -#elif defined(__APPLE__) && !defined(__Userspace__) -#ifdef _KERN_LOCKS_H_ - lck_mtx_t *ipi_addr_mtx; - lck_mtx_t *ipi_count_mtx; - lck_mtx_t *ipi_pktlog_mtx; - lck_mtx_t *logging_mtx; - lck_mtx_t *wq_addr_mtx; -#else - void *ipi_count_mtx; - void *logging_mtx; -#endif /* _KERN_LOCKS_H_ */ -#elif defined(_WIN32) && !defined(__Userspace__) - struct rwlock ipi_ep_lock; - struct rwlock ipi_addr_lock; - struct spinlock ipi_pktlog_mtx; - struct rwlock wq_addr_mtx; -#elif defined(__Userspace__) -#endif - uint32_t ipi_count_ep; - - /* assoc/tcb zone info */ - uint32_t ipi_count_asoc; - - /* local addrlist zone info */ - uint32_t ipi_count_laddr; - - /* remote addrlist zone info */ - uint32_t ipi_count_raddr; - - /* chunk structure list for output */ - uint32_t ipi_count_chunk; - - /* socket queue zone info */ - uint32_t ipi_count_readq; - - /* socket queue zone info */ - uint32_t ipi_count_strmoq; - - /* Number of vrfs */ - uint32_t ipi_count_vrfs; - - /* Number of ifns */ - uint32_t ipi_count_ifns; - - /* Number of ifas */ - uint32_t ipi_count_ifas; - - /* system wide number of free chunks hanging around */ - uint32_t ipi_free_chunks; - uint32_t ipi_free_strmoq; - - struct sctpvtaghead vtag_timewait[SCTP_STACK_VTAG_HASH_SIZE]; - - /* address work queue handling */ - struct sctp_timer addr_wq_timer; - -#if defined(_SCTP_NEEDS_CALLOUT_) || defined(_USER_SCTP_NEEDS_CALLOUT_) - struct calloutlist callqueue; -#endif -}; - -struct sctp_base_info { - /* All static structures that - * anchor the system must be here. - */ - struct sctp_epinfo sctppcbinfo; -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) - struct sctpstat *sctpstat; -#else - struct sctpstat sctpstat; -#endif -#else - struct sctpstat sctpstat; -#endif - struct sctp_sysctl sctpsysctl; - uint8_t first_time; - char sctp_pcb_initialized; -#if defined(SCTP_PACKET_LOGGING) - int packet_log_writers; - int packet_log_end; - uint8_t packet_log_buffer[SCTP_PACKET_LOG_SIZE]; -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - eventhandler_tag eh_tag; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - int sctp_main_timer_ticks; -#endif -#if defined(__Userspace__) - userland_mutex_t timer_mtx; - userland_thread_t timer_thread; - int timer_thread_should_exit; - int iterator_thread_started; - int timer_thread_started; -#if !defined(_WIN32) - pthread_mutexattr_t mtx_attr; - pthread_rwlockattr_t rwlock_attr; -#if defined(INET) || defined(INET6) - int userspace_route; - userland_thread_t recvthreadroute; -#endif -#endif -#ifdef INET -#if defined(_WIN32) && !defined(__MINGW32__) - SOCKET userspace_rawsctp; - SOCKET userspace_udpsctp; -#else - int userspace_rawsctp; - int userspace_udpsctp; -#endif - userland_thread_t recvthreadraw; - userland_thread_t recvthreadudp; -#endif -#ifdef INET6 -#if defined(_WIN32) && !defined(__MINGW32__) - SOCKET userspace_rawsctp6; - SOCKET userspace_udpsctp6; -#else - int userspace_rawsctp6; - int userspace_udpsctp6; -#endif - userland_thread_t recvthreadraw6; - userland_thread_t recvthreadudp6; -#endif - int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df); - void (*debug_printf)(const char *format, ...); - int crc32c_offloaded; -#endif -}; - -/*- - * Here we have all the relevant information for each SCTP entity created. We - * will need to modify this as approprate. We also need to figure out how to - * access /dev/random. - */ -struct sctp_pcb { - unsigned int time_of_secret_change; /* number of seconds from - * timeval.tv_sec */ - uint32_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_NUMBER_OF_SECRETS]; - unsigned int size_of_a_cookie; - - uint32_t sctp_timeoutticks[SCTP_NUM_TMRS]; - uint32_t sctp_minrto; - uint32_t sctp_maxrto; - uint32_t initial_rto; - uint32_t initial_init_rto_max; - - unsigned int sctp_sack_freq; - uint32_t sctp_sws_sender; - uint32_t sctp_sws_receiver; - - uint32_t sctp_default_cc_module; - uint32_t sctp_default_ss_module; - /* authentication related fields */ - struct sctp_keyhead shared_keys; - sctp_auth_chklist_t *local_auth_chunks; - sctp_hmaclist_t *local_hmacs; - uint16_t default_keyid; - uint32_t default_mtu; - - /* various thresholds */ - /* Max times I will init at a guy */ - uint16_t max_init_times; - - /* Max times I will send before we consider someone dead */ - uint16_t max_send_times; - - uint16_t def_net_failure; - - uint16_t def_net_pf_threshold; - - /* number of streams to pre-open on a association */ - uint16_t pre_open_stream_count; - uint16_t max_open_streams_intome; - - /* random number generator */ - uint32_t random_counter; - uint8_t random_numbers[SCTP_SIGNATURE_ALOC_SIZE]; - uint8_t random_store[SCTP_SIGNATURE_ALOC_SIZE]; - - /* - * This timer is kept running per endpoint. When it fires it will - * change the secret key. The default is once a hour - */ - struct sctp_timer signature_change; - - uint32_t def_cookie_life; - /* defaults to 0 */ - uint32_t auto_close_time; - uint32_t initial_sequence_debug; - uint32_t adaptation_layer_indicator; - uint8_t adaptation_layer_indicator_provided; - uint32_t store_at; - uint32_t max_burst; - uint32_t fr_max_burst; -#ifdef INET6 - uint32_t default_flowlabel; -#endif - uint8_t default_dscp; - char current_secret_number; - char last_secret_number; - uint16_t port; /* remote UDP encapsulation port */ -}; - -#ifndef SCTP_ALIGNMENT -#define SCTP_ALIGNMENT 32 -#endif - -#ifndef SCTP_ALIGNM1 -#define SCTP_ALIGNM1 (SCTP_ALIGNMENT-1) -#endif - -#define sctp_lport ip_inp.inp.inp_lport - -struct sctp_pcbtsn_rlog { - uint32_t vtag; - uint16_t strm; - uint16_t seq; - uint16_t sz; - uint16_t flgs; -}; -#define SCTP_READ_LOG_SIZE 135 /* we choose the number to make a pcb a page */ - -struct sctp_inpcb { - /*- - * put an inpcb in front of it all, kind of a waste but we need to - * for compatibility with all the other stuff. - */ - union { - struct inpcb inp; - char align[(sizeof(struct inpcb) + SCTP_ALIGNM1) & - ~SCTP_ALIGNM1]; - } ip_inp; -#if defined(__APPLE__) && !defined(__Userspace__) - /* leave some space in case i386 inpcb is bigger than ppc */ - uint8_t padding[128]; -#endif - - /* Socket buffer lock protects read_queue and of course sb_cc */ - struct sctp_readhead read_queue; - - LIST_ENTRY(sctp_inpcb) sctp_list; /* lists all endpoints */ - /* hash of all endpoints for model */ - LIST_ENTRY(sctp_inpcb) sctp_hash; - /* count of local addresses bound, 0 if bound all */ - int laddr_count; - - /* list of addrs in use by the EP, NULL if bound-all */ - struct sctpladdr sctp_addr_list; - /* used for source address selection rotation when we are subset bound */ - struct sctp_laddr *next_addr_touse; - - /* back pointer to our socket */ - struct socket *sctp_socket; - uint64_t sctp_features; /* Feature flags */ - uint32_t sctp_flags; /* INP state flag set */ - uint32_t sctp_mobility_features; /* Mobility Feature flags */ - struct sctp_pcb sctp_ep;/* SCTP ep data */ - /* head of the hash of all associations */ - struct sctpasochead *sctp_tcbhash; - u_long sctp_hashmark; - /* head of the list of all associations */ - struct sctpasochead sctp_asoc_list; -#ifdef SCTP_TRACK_FREED_ASOCS - struct sctpasochead sctp_asoc_free_list; -#endif - uint32_t sctp_frag_point; - uint32_t partial_delivery_point; - uint32_t sctp_context; - uint32_t max_cwnd; - uint8_t local_strreset_support; - uint32_t sctp_cmt_on_off; - uint8_t ecn_supported; - uint8_t prsctp_supported; - uint8_t auth_supported; - uint8_t idata_supported; - uint8_t asconf_supported; - uint8_t reconfig_supported; - uint8_t nrsack_supported; - uint8_t pktdrop_supported; - uint8_t rcv_edmid; - struct sctp_nonpad_sndrcvinfo def_send; - /*- - * These three are here for the sosend_dgram - * (pkt, pkt_last and control). - * routine. However, I don't think anyone in - * the current FreeBSD kernel calls this. So - * they are candidates with sctp_sendm for - * de-supporting. - */ - struct mbuf *pkt, *pkt_last; - struct mbuf *control; -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct mtx inp_mtx; - struct mtx inp_create_mtx; - struct mtx inp_rdata_mtx; - int32_t refcount; -#elif defined(SCTP_PROCESS_LEVEL_LOCKS) - userland_mutex_t inp_mtx; - userland_mutex_t inp_create_mtx; - userland_mutex_t inp_rdata_mtx; - int32_t refcount; -#elif defined(__APPLE__) && !defined(__Userspace__) -#if defined(SCTP_APPLE_RWLOCK) - lck_rw_t *inp_mtx; -#else - lck_mtx_t *inp_mtx; -#endif - lck_mtx_t *inp_create_mtx; - lck_mtx_t *inp_rdata_mtx; -#elif defined(_WIN32) && !defined(__Userspace__) - struct rwlock inp_lock; - struct spinlock inp_create_lock; - struct spinlock inp_rdata_lock; - int32_t refcount; -#elif defined(__Userspace__) - int32_t refcount; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - int32_t refcount; - - uint32_t lock_caller1; - uint32_t lock_caller2; - uint32_t lock_caller3; - uint32_t unlock_caller1; - uint32_t unlock_caller2; - uint32_t unlock_caller3; - uint32_t getlock_caller1; - uint32_t getlock_caller2; - uint32_t getlock_caller3; - uint32_t gen_count; - uint32_t lock_gen_count; - uint32_t unlock_gen_count; - uint32_t getlock_gen_count; - - uint32_t i_am_here_file; - uint32_t i_am_here_line; -#endif - uint32_t def_vrf_id; - uint16_t fibnum; -#ifdef SCTP_MVRF - uint32_t *m_vrf_ids; - uint32_t num_vrfs; - uint32_t vrf_size; -#endif - uint32_t total_sends; - uint32_t total_recvs; - uint32_t last_abort_code; - uint32_t total_nospaces; - struct sctpasochead *sctp_asocidhash; - u_long hashasocidmark; - uint32_t sctp_associd_counter; - -#ifdef SCTP_ASOCLOG_OF_TSNS - struct sctp_pcbtsn_rlog readlog[SCTP_READ_LOG_SIZE]; - uint32_t readlog_index; -#endif -#if defined(__Userspace__) - void *ulp_info; - int (*recv_callback)(struct socket *, union sctp_sockstore, void *, size_t, - struct sctp_rcvinfo, int, void *); - uint32_t send_sb_threshold; - int (*send_callback)(struct socket *, uint32_t, void *); -#endif -}; - -#if defined(__Userspace__) -int register_recv_cb (struct socket *, - int (*)(struct socket *, union sctp_sockstore, void *, size_t, - struct sctp_rcvinfo, int, void *)); -int register_send_cb (struct socket *, uint32_t, int (*)(struct socket *, uint32_t, void *)); -int register_ulp_info (struct socket *, void *); -int retrieve_ulp_info (struct socket *, void **); - -#endif -struct sctp_tcb { - struct socket *sctp_socket; /* back pointer to socket */ - struct sctp_inpcb *sctp_ep; /* back pointer to ep */ - LIST_ENTRY(sctp_tcb) sctp_tcbhash; /* next link in hash - * table */ - LIST_ENTRY(sctp_tcb) sctp_tcblist; /* list of all of the - * TCB's */ - LIST_ENTRY(sctp_tcb) sctp_tcbasocidhash; /* next link in asocid - * hash table - */ - LIST_ENTRY(sctp_tcb) sctp_asocs; /* vtag hash list */ - struct sctp_block_entry *block_entry; /* pointer locked by socket - * send buffer */ - struct sctp_association asoc; - /*- - * freed_by_sorcv_sincelast is protected by the sockbuf_lock NOT the - * tcb_lock. Its special in this way to help avoid extra mutex calls - * in the reading of data. - */ - uint32_t freed_by_sorcv_sincelast; - uint32_t total_sends; - uint32_t total_recvs; - int freed_from_where; - uint16_t rport; /* remote port in network format */ - uint16_t resv; -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct mtx tcb_mtx; -#elif defined(SCTP_PROCESS_LEVEL_LOCKS) - userland_mutex_t tcb_mtx; -#elif defined(__APPLE__) && !defined(__Userspace__) - lck_mtx_t* tcb_mtx; -#elif defined(_WIN32) && !defined(__Userspace__) - struct spinlock tcb_lock; -#elif defined(__Userspace__) -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - uint32_t caller1; - uint32_t caller2; - uint32_t caller3; -#endif -}; - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#elif defined(__APPLE__) && !defined(__Userspace__) -/* - * Apple MacOS X 10.4 "Tiger" - */ - -#include - -#elif defined(SCTP_PROCESS_LEVEL_LOCKS) - -#include - -#elif defined(_WIN32) && !defined(__Userspace__) - -#include - -#elif defined(__Userspace__) - -#include - -#else -/* - * Pre-5.x FreeBSD, and others. - */ -#include -#endif - -#if defined(_KERNEL) || defined(__Userspace__) - -/* Attention Julian, this is the extern that - * goes with the base info. sctp_pcb.c has - * the real definition. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -VNET_DECLARE(struct sctp_base_info, system_base_info); -#else -extern struct sctp_base_info system_base_info; -#endif - -#ifdef INET6 -int SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b); -#endif - -void sctp_fill_pcbinfo(struct sctp_pcbinfo *); - -struct sctp_ifn * -sctp_find_ifn(void *ifn, uint32_t ifn_index); - -struct sctp_vrf *sctp_allocate_vrf(int vrfid); -struct sctp_vrf *sctp_find_vrf(uint32_t vrfid); -void sctp_free_vrf(struct sctp_vrf *vrf); - -/*- - * Change address state, can be used if - * O/S supports telling transports about - * changes to IFA/IFN's (link layer triggers). - * If a ifn goes down, we will do src-addr-selection - * and NOT use that, as a source address. This does - * not stop the routing system from routing out - * that interface, but we won't put it as a source. - */ -void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); -void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); - -struct sctp_ifa * -sctp_add_addr_to_vrf(uint32_t vrfid, - void *ifn, uint32_t ifn_index, uint32_t ifn_type, - const char *if_name, - void *ifa, struct sockaddr *addr, uint32_t ifa_flags, - int dynamic_add); - -void sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu); - -void sctp_free_ifn(struct sctp_ifn *sctp_ifnp); -void sctp_free_ifa(struct sctp_ifa *sctp_ifap); - -void sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, - uint32_t ifn_index, const char *if_name); - -struct sctp_nets *sctp_findnet(struct sctp_tcb *, struct sockaddr *); - -struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, int, uint32_t); - -#if defined(__FreeBSD__) && !defined(__Userspace__) -int -sctp_inpcb_bind(struct socket *, struct sockaddr *, - struct sctp_ifa *, struct thread *); -int -sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *, - struct sctp_ifa *, struct thread *); -#elif defined(_WIN32) && !defined(__Userspace__) -int -sctp_inpcb_bind(struct socket *, struct sockaddr *, - struct sctp_ifa *, PKTHREAD); -int -sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *, - struct sctp_ifa *, PKTHREAD); -#else -/* struct proc is a dummy for __Userspace__ */ -int -sctp_inpcb_bind(struct socket *, struct sockaddr *, - struct sctp_ifa *, struct proc *); -int -sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *, - struct sctp_ifa *, struct proc *); -#endif - -struct sctp_tcb * -sctp_findassociation_addr(struct mbuf *, int, - struct sockaddr *, struct sockaddr *, - struct sctphdr *, struct sctp_chunkhdr *, struct sctp_inpcb **, - struct sctp_nets **, uint32_t vrf_id); - -struct sctp_tcb * -sctp_findassociation_addr_sa(struct sockaddr *, - struct sockaddr *, struct sctp_inpcb **, struct sctp_nets **, int, uint32_t); - -void -sctp_move_pcb_and_assoc(struct sctp_inpcb *, struct sctp_inpcb *, - struct sctp_tcb *); - -/*- - * For this call ep_addr, the to is the destination endpoint address of the - * peer (relative to outbound). The from field is only used if the TCP model - * is enabled and helps distingush amongst the subset bound (non-boundall). - * The TCP model MAY change the actual ep field, this is why it is passed. - */ -struct sctp_tcb * -sctp_findassociation_ep_addr(struct sctp_inpcb **, - struct sockaddr *, struct sctp_nets **, struct sockaddr *, - struct sctp_tcb *); - -struct sctp_tcb * -sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock); - -struct sctp_tcb * -sctp_findassociation_ep_asocid(struct sctp_inpcb *, - sctp_assoc_t, int); - -struct sctp_tcb * -sctp_findassociation_ep_asconf(struct mbuf *, int, struct sockaddr *, - struct sctphdr *, struct sctp_inpcb **, struct sctp_nets **, uint32_t vrf_id); - -int sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id); - -int sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id); - -void sctp_inpcb_free(struct sctp_inpcb *, int, int); - -#define SCTP_DONT_INITIALIZE_AUTH_PARAMS 0 -#define SCTP_INITIALIZE_AUTH_PARAMS 1 - -#if defined(__FreeBSD__) && !defined(__Userspace__) -struct sctp_tcb * -sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, - int *, uint32_t, uint32_t, uint32_t, uint16_t, uint16_t, - struct thread *, int); -struct sctp_tcb * -sctp_aloc_assoc_connected(struct sctp_inpcb *, struct sockaddr *, - int *, uint32_t, uint32_t, uint32_t, uint16_t, uint16_t, - struct thread *, int); -#elif defined(_WIN32) && !defined(__Userspace__) -struct sctp_tcb * -sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, - uint32_t, uint32_t, uint16_t, uint16_t, PKTHREAD, int); -struct sctp_tcb * -sctp_aloc_assoc_connected(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, - uint32_t, uint32_t, uint16_t, uint16_t, PKTHREAD, int); -#else -/* proc will be NULL for __Userspace__ */ -struct sctp_tcb * -sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, - uint32_t, uint32_t, uint16_t, uint16_t, struct proc *, int); -struct sctp_tcb * -sctp_aloc_assoc_connected(struct sctp_inpcb *, struct sockaddr *, int *, uint32_t, - uint32_t, uint32_t, uint16_t, uint16_t, struct proc *, int); -#endif - -int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int); - -void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t); - -void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *); - -int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, uint16_t, int, int); - -void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *); - -int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *); - -#if defined(__Userspace__) -void sctp_pcb_init(int); -#else -void sctp_pcb_init(void); -#endif - -void sctp_pcb_finish(void); - -void sctp_add_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); -void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); - -int -sctp_load_addresses_from_init(struct sctp_tcb *, struct mbuf *, int, int, - struct sockaddr *, struct sockaddr *, struct sockaddr *, uint16_t); - -int -sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *, - struct sctp_nets *); - -bool -sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *); - -int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *); - -int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp); - -void sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh); - -void -sctp_pcb_add_flags(struct sctp_inpcb *, uint32_t); - -/*- - * Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg - * indicates run on ONLY assoc's of the specified endpoint. - */ -int -sctp_initiate_iterator(inp_func inpf, - asoc_func af, - inp_func inpe, - uint32_t, uint32_t, - uint32_t, void *, - uint32_t, - end_func ef, - struct sctp_inpcb *, - uint8_t co_off); -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_MCORE_INPUT) && defined(SMP) -void -sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use); - -#endif -#endif - -#endif /* _KERNEL */ -#endif /* !__sctp_pcb_h__ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.c deleted file mode 100644 index 548c3d82..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.c +++ /dev/null @@ -1,302 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id) -{ - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - uint32_t state; - - if (head == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EBADF); - return (EBADF); - } - inp = (struct sctp_inpcb *)head->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); - return (EFAULT); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EOPNOTSUPP); - return (EOPNOTSUPP); - } - stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOENT); - return (ENOENT); - } - state = SCTP_GET_STATE(stcb); - if ((state == SCTP_STATE_EMPTY) || - (state == SCTP_STATE_INUSE)) { - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); - return (ENOTCONN); - } - SCTP_TCB_UNLOCK(stcb); - /* We are clear to peel this one off */ - return (0); -} - -int -sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) -{ - struct sctp_inpcb *inp, *n_inp; - struct sctp_tcb *stcb; - uint32_t state; - - inp = (struct sctp_inpcb *)head->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); - return (EFAULT); - } - stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); - return (ENOTCONN); - } - - state = SCTP_GET_STATE(stcb); - if ((state == SCTP_STATE_EMPTY) || - (state == SCTP_STATE_INUSE)) { - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); - return (ENOTCONN); - } - - n_inp = (struct sctp_inpcb *)so->so_pcb; - n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | - SCTP_PCB_FLAGS_CONNECTED | - SCTP_PCB_FLAGS_IN_TCPPOOL | /* Turn on Blocking IO */ - (SCTP_PCB_COPY_FLAGS & inp->sctp_flags)); - n_inp->sctp_socket = so; - n_inp->sctp_features = inp->sctp_features; - n_inp->sctp_mobility_features = inp->sctp_mobility_features; - n_inp->sctp_frag_point = inp->sctp_frag_point; - n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; - n_inp->ecn_supported = inp->ecn_supported; - n_inp->prsctp_supported = inp->prsctp_supported; - n_inp->auth_supported = inp->auth_supported; - n_inp->asconf_supported = inp->asconf_supported; - n_inp->reconfig_supported = inp->reconfig_supported; - n_inp->nrsack_supported = inp->nrsack_supported; - n_inp->pktdrop_supported = inp->pktdrop_supported; - n_inp->partial_delivery_point = inp->partial_delivery_point; - n_inp->sctp_context = inp->sctp_context; - n_inp->max_cwnd = inp->max_cwnd; - n_inp->local_strreset_support = inp->local_strreset_support; - /* copy in the authentication parameters from the original endpoint */ - if (n_inp->sctp_ep.local_hmacs) - sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs); - n_inp->sctp_ep.local_hmacs = - sctp_copy_hmaclist(inp->sctp_ep.local_hmacs); - if (n_inp->sctp_ep.local_auth_chunks) - sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks); - n_inp->sctp_ep.local_auth_chunks = - sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks); - (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys, - &n_inp->sctp_ep.shared_keys); -#if defined(__Userspace__) - n_inp->ulp_info = inp->ulp_info; - n_inp->recv_callback = inp->recv_callback; - n_inp->send_callback = inp->send_callback; - n_inp->send_sb_threshold = inp->send_sb_threshold; -#endif - /* - * Now we must move it from one hash table to another and get the - * stcb in the right place. - */ - sctp_move_pcb_and_assoc(inp, n_inp, stcb); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - -#if defined(__FreeBSD__) && !defined(__Userspace__) - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT); -#else - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK); -#endif - atomic_subtract_int(&stcb->asoc.refcnt, 1); - - return (0); -} - -#if defined(HAVE_SCTP_PEELOFF_SOCKOPT) -struct socket * -sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) -{ - struct socket *newso; - struct sctp_inpcb *inp, *n_inp; - struct sctp_tcb *stcb; - - SCTPDBG(SCTP_DEBUG_PEEL1, "SCTP peel-off called\n"); - inp = (struct sctp_inpcb *)head->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); - *error = EFAULT; - return (NULL); - } - stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); - *error = ENOTCONN; - return (NULL); - } - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_SET(head->so_vnet); -#endif - newso = sonewconn(head, SS_ISCONNECTED -#if defined(__APPLE__) && !defined(__Userspace__) - , NULL -#endif - ); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_RESTORE(); -#endif - if (newso == NULL) { - SCTPDBG(SCTP_DEBUG_PEEL1, "sctp_peeloff:sonewconn failed\n"); - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOMEM); - *error = ENOMEM; - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return (NULL); - - } -#if defined(__APPLE__) && !defined(__Userspace__) - else { - SCTP_SOCKET_LOCK(newso, 1); - } -#endif - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - n_inp = (struct sctp_inpcb *)newso->so_pcb; - SOCK_LOCK(head); - n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | - SCTP_PCB_FLAGS_CONNECTED | - SCTP_PCB_FLAGS_IN_TCPPOOL | /* Turn on Blocking IO */ - (SCTP_PCB_COPY_FLAGS & inp->sctp_flags)); - n_inp->sctp_features = inp->sctp_features; - n_inp->sctp_frag_point = inp->sctp_frag_point; - n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; - n_inp->ecn_supported = inp->ecn_supported; - n_inp->prsctp_supported = inp->prsctp_supported; - n_inp->auth_supported = inp->auth_supported; - n_inp->asconf_supported = inp->asconf_supported; - n_inp->reconfig_supported = inp->reconfig_supported; - n_inp->nrsack_supported = inp->nrsack_supported; - n_inp->pktdrop_supported = inp->pktdrop_supported; - n_inp->partial_delivery_point = inp->partial_delivery_point; - n_inp->sctp_context = inp->sctp_context; - n_inp->max_cwnd = inp->max_cwnd; - n_inp->local_strreset_support = inp->local_strreset_support; - n_inp->inp_starting_point_for_iterator = NULL; -#if defined(__Userspace__) - n_inp->ulp_info = inp->ulp_info; - n_inp->recv_callback = inp->recv_callback; - n_inp->send_callback = inp->send_callback; - n_inp->send_sb_threshold = inp->send_sb_threshold; -#endif - - /* copy in the authentication parameters from the original endpoint */ - if (n_inp->sctp_ep.local_hmacs) - sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs); - n_inp->sctp_ep.local_hmacs = - sctp_copy_hmaclist(inp->sctp_ep.local_hmacs); - if (n_inp->sctp_ep.local_auth_chunks) - sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks); - n_inp->sctp_ep.local_auth_chunks = - sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks); - (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys, - &n_inp->sctp_ep.shared_keys); - - n_inp->sctp_socket = newso; - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { - sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE); - n_inp->sctp_ep.auto_close_time = 0; - sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, n_inp, stcb, NULL, - SCTP_FROM_SCTP_PEELOFF + SCTP_LOC_1); - } - /* Turn off any non-blocking semantic. */ - SOCK_LOCK(newso); - SCTP_CLEAR_SO_NBIO(newso); - newso->so_state |= SS_ISCONNECTED; - SOCK_UNLOCK(newso); - /* We remove it right away */ - -#ifdef SCTP_LOCK_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { - sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); - } -#endif - TAILQ_REMOVE(&head->so_comp, newso, so_list); - head->so_qlen--; - SOCK_UNLOCK(head); - /* - * Now we must move it from one hash table to another and get the - * stcb in the right place. - */ - sctp_move_pcb_and_assoc(inp, n_inp, stcb); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - /* - * And now the final hack. We move data in the pending side i.e. - * head to the new socket buffer. Let the GRUBBING begin :-0 - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT); -#else - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK); -#endif - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return (newso); -} -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.h deleted file mode 100644 index c22bfca9..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_peeloff.h +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_PEELOFF_H_ -#define _NETINET_SCTP_PEELOFF_H_ -#if defined(HAVE_SCTP_PEELOFF_SOCKOPT) -/* socket option peeloff */ -struct sctp_peeloff_opt { -#if !(defined(_WIN32) && !defined(__Userspace__)) - int s; -#else - HANDLE s; -#endif - sctp_assoc_t assoc_id; -#if !(defined(_WIN32) && !defined(__Userspace__)) - int new_sd; -#else - HANDLE new_sd; -#endif -}; -#endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ -#if defined(_KERNEL) -int sctp_can_peel_off(struct socket *, sctp_assoc_t); -int sctp_do_peeloff(struct socket *, struct socket *, sctp_assoc_t); -#if defined(HAVE_SCTP_PEELOFF_SOCKOPT) -struct socket *sctp_get_peeloff(struct socket *, sctp_assoc_t, int *); -int sctp_peeloff_option(struct proc *p, struct sctp_peeloff_opt *peeloff); -#endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ -#endif /* _KERNEL */ -#if defined(__Userspace__) -int sctp_can_peel_off(struct socket *, sctp_assoc_t); -int sctp_do_peeloff(struct socket *, struct socket *, sctp_assoc_t); -#endif /* __Userspace__ */ -#endif /* _NETINET_SCTP_PEELOFF_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_process_lock.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_process_lock.h deleted file mode 100644 index feaa2c6a..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_process_lock.h +++ /dev/null @@ -1,693 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef __sctp_process_lock_h__ -#define __sctp_process_lock_h__ - -/* - * Need to yet define five atomic fuctions or - * their equivalant. - * - atomic_add_int(&foo, val) - add atomically the value - * - atomic_fetchadd_int(&foo, val) - does same as atomic_add_int - * but value it was is returned. - * - atomic_subtract_int(&foo, val) - can be made from atomic_add_int() - * - * - atomic_cmpset_int(&foo, value, newvalue) - Does a set of newvalue - * in foo if and only if - * foo is value. Returns 0 - * on success. - */ - -#ifdef SCTP_PER_SOCKET_LOCKING -/* - * per socket level locking - */ - -#if defined(_WIN32) -/* Lock for INFO stuff */ -#define SCTP_INP_INFO_LOCK_INIT() -#define SCTP_INP_INFO_RLOCK() -#define SCTP_INP_INFO_RUNLOCK() -#define SCTP_INP_INFO_WLOCK() -#define SCTP_INP_INFO_WUNLOCK() -#define SCTP_INP_INFO_LOCK_ASSERT() -#define SCTP_INP_INFO_RLOCK_ASSERT() -#define SCTP_INP_INFO_WLOCK_ASSERT() -#define SCTP_INP_INFO_LOCK_DESTROY() -#define SCTP_IPI_COUNT_INIT() -#define SCTP_IPI_COUNT_DESTROY() -#else -#define SCTP_INP_INFO_LOCK_INIT() -#define SCTP_INP_INFO_RLOCK() -#define SCTP_INP_INFO_RUNLOCK() -#define SCTP_INP_INFO_WLOCK() -#define SCTP_INP_INFO_WUNLOCK() -#define SCTP_INP_INFO_LOCK_ASSERT() -#define SCTP_INP_INFO_RLOCK_ASSERT() -#define SCTP_INP_INFO_WLOCK_ASSERT() -#define SCTP_INP_INFO_LOCK_DESTROY() -#define SCTP_IPI_COUNT_INIT() -#define SCTP_IPI_COUNT_DESTROY() -#endif - -/* Lock for INP */ -#define SCTP_INP_LOCK_INIT(_inp) -#define SCTP_INP_LOCK_DESTROY(_inp) - -#define SCTP_INP_RLOCK(_inp) -#define SCTP_INP_RUNLOCK(_inp) -#define SCTP_INP_WLOCK(_inp) -#define SCTP_INP_WUNLOCK(_inp) -#define SCTP_INP_RLOCK_ASSERT(_inp) -#define SCTP_INP_WLOCK_ASSERT(_inp) -#define SCTP_INP_INCR_REF(_inp) -#define SCTP_INP_DECR_REF(_inp) - -#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) -#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) -#define SCTP_ASOC_CREATE_LOCK(_inp) -#define SCTP_ASOC_CREATE_UNLOCK(_inp) - -#define SCTP_INP_READ_LOCK_INIT(_inp) -#define SCTP_INP_READ_LOCK_DESTROY(_inp) -#define SCTP_INP_READ_LOCK(_inp) -#define SCTP_INP_READ_UNLOCK(_inp) -#define SCTP_INP_READ_LOCK_ASSERT(_inp) - -/* Lock for TCB */ -#define SCTP_TCB_LOCK_INIT(_tcb) -#define SCTP_TCB_LOCK_DESTROY(_tcb) -#define SCTP_TCB_LOCK(_tcb) -#define SCTP_TCB_TRYLOCK(_tcb) 1 -#define SCTP_TCB_UNLOCK(_tcb) -#define SCTP_TCB_UNLOCK_IFOWNED(_tcb) -#define SCTP_TCB_LOCK_ASSERT(_tcb) - -#else -/* - * per tcb level locking - */ -#define SCTP_IPI_COUNT_INIT() - -#if defined(_WIN32) -#define SCTP_WQ_ADDR_INIT() \ - InitializeCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx)) -#define SCTP_WQ_ADDR_DESTROY() \ - DeleteCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx)) -#define SCTP_WQ_ADDR_LOCK() \ - EnterCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx)) -#define SCTP_WQ_ADDR_UNLOCK() \ - LeaveCriticalSection(&SCTP_BASE_INFO(wq_addr_mtx)) -#define SCTP_WQ_ADDR_LOCK_ASSERT() - -#if WINVER < 0x0600 -#define SCTP_INP_INFO_LOCK_INIT() \ - InitializeCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_LOCK_DESTROY() \ - DeleteCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_RLOCK() \ - EnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_TRYLOCK() \ - TryEnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_WLOCK() \ - EnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_RUNLOCK() \ - LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_WUNLOCK() \ - LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_LOCK_ASSERT() -#define SCTP_INP_INFO_RLOCK_ASSERT() -#define SCTP_INP_INFO_WLOCK_ASSERT() -#else -#define SCTP_INP_INFO_LOCK_INIT() \ - InitializeSRWLock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_LOCK_DESTROY() -#define SCTP_INP_INFO_RLOCK() \ - AcquireSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_TRYLOCK() \ - TryAcquireSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_WLOCK() \ - AcquireSRWLockExclusive(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_RUNLOCK() \ - ReleaseSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_WUNLOCK() \ - ReleaseSRWLockExclusive(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_LOCK_ASSERT() -#define SCTP_INP_INFO_RLOCK_ASSERT() -#define SCTP_INP_INFO_WLOCK_ASSERT() -#endif - -#define SCTP_IP_PKTLOG_INIT() \ - InitializeCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#define SCTP_IP_PKTLOG_DESTROY () \ - DeleteCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#define SCTP_IP_PKTLOG_LOCK() \ - EnterCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#define SCTP_IP_PKTLOG_UNLOCK() \ - LeaveCriticalSection(&SCTP_BASE_INFO(ipi_pktlog_mtx)) - -/* - * The INP locks we will use for locking an SCTP endpoint, so for example if - * we want to change something at the endpoint level for example random_store - * or cookie secrets we lock the INP level. - */ -#define SCTP_INP_READ_LOCK_INIT(_inp) \ - InitializeCriticalSection(&(_inp)->inp_rdata_mtx) -#define SCTP_INP_READ_LOCK_DESTROY(_inp) \ - DeleteCriticalSection(&(_inp)->inp_rdata_mtx) -#define SCTP_INP_READ_LOCK(_inp) \ - EnterCriticalSection(&(_inp)->inp_rdata_mtx) -#define SCTP_INP_READ_UNLOCK(_inp) \ - LeaveCriticalSection(&(_inp)->inp_rdata_mtx) -#define SCTP_INP_READ_LOCK_ASSERT(_inp) - -#define SCTP_INP_LOCK_INIT(_inp) \ - InitializeCriticalSection(&(_inp)->inp_mtx) -#define SCTP_INP_LOCK_DESTROY(_inp) \ - DeleteCriticalSection(&(_inp)->inp_mtx) -#ifdef SCTP_LOCK_LOGGING -#define SCTP_INP_RLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - EnterCriticalSection(&(_inp)->inp_mtx); \ -} while (0) -#define SCTP_INP_WLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - EnterCriticalSection(&(_inp)->inp_mtx); \ -} while (0) -#else -#define SCTP_INP_RLOCK(_inp) \ - EnterCriticalSection(&(_inp)->inp_mtx) -#define SCTP_INP_WLOCK(_inp) \ - EnterCriticalSection(&(_inp)->inp_mtx) -#endif -#define SCTP_INP_RLOCK_ASSERT(_tcb) -#define SCTP_INP_WLOCK_ASSERT(_tcb) - -#define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1) -#define SCTP_INP_DECR_REF(_inp) atomic_subtract_int(&((_inp)->refcount), 1) - -#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \ - InitializeCriticalSection(&(_inp)->inp_create_mtx) -#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \ - DeleteCriticalSection(&(_inp)->inp_create_mtx) -#ifdef SCTP_LOCK_LOGGING -#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE); \ - EnterCriticalSection(&(_inp)->inp_create_mtx); \ -} while (0) -#else -#define SCTP_ASOC_CREATE_LOCK(_inp) \ - EnterCriticalSection(&(_inp)->inp_create_mtx) -#endif - -#define SCTP_INP_RUNLOCK(_inp) \ - LeaveCriticalSection(&(_inp)->inp_mtx) -#define SCTP_INP_WUNLOCK(_inp) \ - LeaveCriticalSection(&(_inp)->inp_mtx) -#define SCTP_ASOC_CREATE_UNLOCK(_inp) \ - LeaveCriticalSection(&(_inp)->inp_create_mtx) - -/* - * For the majority of things (once we have found the association) we will - * lock the actual association mutex. This will protect all the assoiciation - * level queues and streams and such. We will need to lock the socket layer - * when we stuff data up into the receiving sb_mb. I.e. we will need to do an - * extra SOCKBUF_LOCK(&so->so_rcv) even though the association is locked. - */ - -#define SCTP_TCB_LOCK_INIT(_tcb) \ - InitializeCriticalSection(&(_tcb)->tcb_mtx) -#define SCTP_TCB_LOCK_DESTROY(_tcb) \ - DeleteCriticalSection(&(_tcb)->tcb_mtx) -#ifdef SCTP_LOCK_LOGGING -#define SCTP_TCB_LOCK(_tcb) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB); \ - EnterCriticalSection(&(_tcb)->tcb_mtx); \ -} while (0) -#else -#define SCTP_TCB_LOCK(_tcb) \ - EnterCriticalSection(&(_tcb)->tcb_mtx) -#endif -#define SCTP_TCB_TRYLOCK(_tcb) ((TryEnterCriticalSection(&(_tcb)->tcb_mtx))) -#define SCTP_TCB_UNLOCK(_tcb) \ - LeaveCriticalSection(&(_tcb)->tcb_mtx) -#define SCTP_TCB_LOCK_ASSERT(_tcb) - -#else /* all Userspaces except Windows */ -#define SCTP_WQ_ADDR_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(wq_addr_mtx), &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_WQ_ADDR_DESTROY() \ - (void)pthread_mutex_destroy(&SCTP_BASE_INFO(wq_addr_mtx)) -#ifdef INVARIANTS -#define SCTP_WQ_ADDR_LOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s:%d: wq_addr_mtx already locked", __FILE__, __LINE__)) -#define SCTP_WQ_ADDR_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s:%d: wq_addr_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_WQ_ADDR_LOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) -#define SCTP_WQ_ADDR_UNLOCK() \ - (void)pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) -#endif -#define SCTP_WQ_ADDR_LOCK_ASSERT() \ - KASSERT(pthread_mutex_trylock(&SCTP_BASE_INFO(wq_addr_mtx)) == EBUSY, ("%s:%d: wq_addr_mtx not locked", __FILE__, __LINE__)) - -#define SCTP_INP_INFO_LOCK_INIT() \ - (void)pthread_rwlock_init(&SCTP_BASE_INFO(ipi_ep_mtx), &SCTP_BASE_VAR(rwlock_attr)) -#define SCTP_INP_INFO_LOCK_DESTROY() \ - (void)pthread_rwlock_destroy(&SCTP_BASE_INFO(ipi_ep_mtx)) -#ifdef INVARIANTS -#define SCTP_INP_INFO_RLOCK() \ - KASSERT(pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s%d: ipi_ep_mtx already locked", __FILE__, __LINE__)) -#define SCTP_INP_INFO_WLOCK() \ - KASSERT(pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s:%d: ipi_ep_mtx already locked", __FILE__, __LINE__)) -#define SCTP_INP_INFO_RUNLOCK() \ - KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s:%d: ipi_ep_mtx not locked", __FILE__, __LINE__)) -#define SCTP_INP_INFO_WUNLOCK() \ - KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s:%d: ipi_ep_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_INP_INFO_RLOCK() \ - (void)pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_WLOCK() \ - (void)pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_RUNLOCK() \ - (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_WUNLOCK() \ - (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#endif -#define SCTP_INP_INFO_LOCK_ASSERT() -#define SCTP_INP_INFO_RLOCK_ASSERT() -#define SCTP_INP_INFO_WLOCK_ASSERT() -#define SCTP_INP_INFO_TRYLOCK() \ - (!(pthread_rwlock_tryrdlock(&SCTP_BASE_INFO(ipi_ep_mtx)))) - -#define SCTP_IP_PKTLOG_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_IP_PKTLOG_DESTROY() \ - (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#ifdef INVARIANTS -#define SCTP_IP_PKTLOG_LOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s:%d: ipi_pktlog_mtx already locked", __FILE__, __LINE__)) -#define SCTP_IP_PKTLOG_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s:%d: ipi_pktlog_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_IP_PKTLOG_LOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#define SCTP_IP_PKTLOG_UNLOCK() \ - (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#endif - - -/* - * The INP locks we will use for locking an SCTP endpoint, so for example if - * we want to change something at the endpoint level for example random_store - * or cookie secrets we lock the INP level. - */ -#define SCTP_INP_READ_LOCK_INIT(_inp) \ - (void)pthread_mutex_init(&(_inp)->inp_rdata_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_INP_READ_LOCK_DESTROY(_inp) \ - (void)pthread_mutex_destroy(&(_inp)->inp_rdata_mtx) -#ifdef INVARIANTS -#define SCTP_INP_READ_LOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_rdata_mtx) == 0, ("%s:%d: inp_rdata_mtx already locked", __FILE__, __LINE__)) -#define SCTP_INP_READ_UNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) == 0, ("%s:%d: inp_rdata_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_INP_READ_LOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_rdata_mtx) -#define SCTP_INP_READ_UNLOCK(_inp) \ - (void)pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) -#endif -#define SCTP_INP_READ_LOCK_ASSERT(_inp) \ - KASSERT(pthread_mutex_trylock(&(_inp)->inp_rdata_mtx) == EBUSY, ("%s:%d: inp_rdata_mtx not locked", __FILE__, __LINE__)) - -#define SCTP_INP_LOCK_INIT(_inp) \ - (void)pthread_mutex_init(&(_inp)->inp_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_INP_LOCK_DESTROY(_inp) \ - (void)pthread_mutex_destroy(&(_inp)->inp_mtx) -#ifdef INVARIANTS -#ifdef SCTP_LOCK_LOGGING -#define SCTP_INP_RLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx already locked", __FILE__, __LINE__)); \ -} while (0) -#define SCTP_INP_WLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx already locked", __FILE__, __LINE__)); \ -} while (0) -#else -#define SCTP_INP_RLOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx already locked", __FILE__, __LINE__)) -#define SCTP_INP_WLOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx already locked", __FILE__, __LINE__)) -#endif -#define SCTP_INP_RUNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) -#define SCTP_INP_WUNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) -#else -#ifdef SCTP_LOCK_LOGGING -#define SCTP_INP_RLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ -} while (0) -#define SCTP_INP_WLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_INP); \ - (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ -} while (0) -#else -#define SCTP_INP_RLOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_mtx) -#define SCTP_INP_WLOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_mtx) -#endif -#define SCTP_INP_RUNLOCK(_inp) \ - (void)pthread_mutex_unlock(&(_inp)->inp_mtx) -#define SCTP_INP_WUNLOCK(_inp) \ - (void)pthread_mutex_unlock(&(_inp)->inp_mtx) -#endif -#define SCTP_INP_RLOCK_ASSERT(_inp) \ - KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) -#define SCTP_INP_WLOCK_ASSERT(_inp) \ - KASSERT(pthread_mutex_trylock(&(_inp)->inp_mtx) == EBUSY, ("%s:%d: inp_mtx not locked", __FILE__, __LINE__)) -#define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1) -#define SCTP_INP_DECR_REF(_inp) atomic_subtract_int(&((_inp)->refcount), 1) - -#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \ - (void)pthread_mutex_init(&(_inp)->inp_create_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \ - (void)pthread_mutex_destroy(&(_inp)->inp_create_mtx) -#ifdef INVARIANTS -#ifdef SCTP_LOCK_LOGGING -#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s:%d: inp_create_mtx already locked", __FILE__, __LINE__)); \ -} while (0) -#else -#define SCTP_ASOC_CREATE_LOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s:%d: inp_create_mtx already locked", __FILE__, __LINE__)) -#endif -#define SCTP_ASOC_CREATE_UNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_create_mtx) == 0, ("%s:%d: inp_create_mtx not locked", __FILE__, __LINE__)) -#else -#ifdef SCTP_LOCK_LOGGING -#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, NULL, SCTP_LOG_LOCK_CREATE); \ - (void)pthread_mutex_lock(&(_inp)->inp_create_mtx); \ -} while (0) -#else -#define SCTP_ASOC_CREATE_LOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_create_mtx) -#endif -#define SCTP_ASOC_CREATE_UNLOCK(_inp) \ - (void)pthread_mutex_unlock(&(_inp)->inp_create_mtx) -#endif -/* - * For the majority of things (once we have found the association) we will - * lock the actual association mutex. This will protect all the assoiciation - * level queues and streams and such. We will need to lock the socket layer - * when we stuff data up into the receiving sb_mb. I.e. we will need to do an - * extra SOCKBUF_LOCK(&so->so_rcv) even though the association is locked. - */ - -#define SCTP_TCB_LOCK_INIT(_tcb) \ - (void)pthread_mutex_init(&(_tcb)->tcb_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_TCB_LOCK_DESTROY(_tcb) \ - (void)pthread_mutex_destroy(&(_tcb)->tcb_mtx) -#ifdef INVARIANTS -#ifdef SCTP_LOCK_LOGGING -#define SCTP_TCB_LOCK(_tcb) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB); \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s:%d: tcb_mtx already locked", __FILE__, __LINE__)) \ -} while (0) -#else -#define SCTP_TCB_LOCK(_tcb) \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s:%d: tcb_mtx already locked", __FILE__, __LINE__)) -#endif -#define SCTP_TCB_UNLOCK(_tcb) \ - KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_mtx) == 0, ("%s:%d: tcb_mtx not locked", __FILE__, __LINE__)) -#else -#ifdef SCTP_LOCK_LOGGING -#define SCTP_TCB_LOCK(_tcb) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB); \ - (void)pthread_mutex_lock(&(_tcb)->tcb_mtx); \ -} while (0) -#else -#define SCTP_TCB_LOCK(_tcb) \ - (void)pthread_mutex_lock(&(_tcb)->tcb_mtx) -#endif -#define SCTP_TCB_UNLOCK(_tcb) (void)pthread_mutex_unlock(&(_tcb)->tcb_mtx) -#endif -#define SCTP_TCB_LOCK_ASSERT(_tcb) \ - KASSERT(pthread_mutex_trylock(&(_tcb)->tcb_mtx) == EBUSY, ("%s:%d: tcb_mtx not locked", __FILE__, __LINE__)) -#define SCTP_TCB_TRYLOCK(_tcb) (!(pthread_mutex_trylock(&(_tcb)->tcb_mtx))) -#endif - -#endif /* SCTP_PER_SOCKET_LOCKING */ - - -/* - * common locks - */ - -/* copied over to compile */ -#define SCTP_INP_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */ -#define SCTP_INP_READ_CONTENDED(_inp) (0) /* Don't know if this is possible */ -#define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) (0) /* Don't know if this is possible */ - -/* socket locks */ - -#if defined(_WIN32) -#define SOCKBUF_LOCK_ASSERT(_so_buf) -#define SOCKBUF_LOCK(_so_buf) \ - EnterCriticalSection(&(_so_buf)->sb_mtx) -#define SOCKBUF_UNLOCK(_so_buf) \ - LeaveCriticalSection(&(_so_buf)->sb_mtx) -#define SOCK_LOCK(_so) \ - SOCKBUF_LOCK(&(_so)->so_rcv) -#define SOCK_UNLOCK(_so) \ - SOCKBUF_UNLOCK(&(_so)->so_rcv) -#else -#define SOCKBUF_LOCK_ASSERT(_so_buf) \ - KASSERT(pthread_mutex_trylock(SOCKBUF_MTX(_so_buf)) == EBUSY, ("%s:%d: socket buffer not locked", __FILE__, __LINE__)) -#ifdef INVARIANTS -#define SOCKBUF_LOCK(_so_buf) \ - KASSERT(pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) == 0, ("%s:%d: sockbuf_mtx already locked", __FILE__, __LINE__)) -#define SOCKBUF_UNLOCK(_so_buf) \ - KASSERT(pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) == 0, ("%s:%d: sockbuf_mtx not locked", __FILE__, __LINE__)) -#else -#define SOCKBUF_LOCK(_so_buf) \ - pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) -#define SOCKBUF_UNLOCK(_so_buf) \ - pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) -#endif -#define SOCK_LOCK(_so) \ - SOCKBUF_LOCK(&(_so)->so_rcv) -#define SOCK_UNLOCK(_so) \ - SOCKBUF_UNLOCK(&(_so)->so_rcv) -#endif - -#define SCTP_STATLOG_INIT_LOCK() -#define SCTP_STATLOG_LOCK() -#define SCTP_STATLOG_UNLOCK() -#define SCTP_STATLOG_DESTROY() - -#if defined(_WIN32) -/* address list locks */ -#if WINVER < 0x0600 -#define SCTP_IPI_ADDR_INIT() \ - InitializeCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_DESTROY() \ - DeleteCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_RLOCK() \ - EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_RUNLOCK() \ - LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WLOCK() \ - EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WUNLOCK() \ - LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_LOCK_ASSERT() -#define SCTP_IPI_ADDR_WLOCK_ASSERT() -#else -#define SCTP_IPI_ADDR_INIT() \ - InitializeSRWLock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_DESTROY() -#define SCTP_IPI_ADDR_RLOCK() \ - AcquireSRWLockShared(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_RUNLOCK() \ - ReleaseSRWLockShared(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WLOCK() \ - AcquireSRWLockExclusive(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WUNLOCK() \ - ReleaseSRWLockExclusive(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_LOCK_ASSERT() -#define SCTP_IPI_ADDR_WLOCK_ASSERT() -#endif - -/* iterator locks */ -#define SCTP_ITERATOR_LOCK_INIT() \ - InitializeCriticalSection(&sctp_it_ctl.it_mtx) -#define SCTP_ITERATOR_LOCK_DESTROY() \ - DeleteCriticalSection(&sctp_it_ctl.it_mtx) -#define SCTP_ITERATOR_LOCK() \ - EnterCriticalSection(&sctp_it_ctl.it_mtx) -#define SCTP_ITERATOR_UNLOCK() \ - LeaveCriticalSection(&sctp_it_ctl.it_mtx) - -#define SCTP_IPI_ITERATOR_WQ_INIT() \ - InitializeCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx) -#define SCTP_IPI_ITERATOR_WQ_DESTROY() \ - DeleteCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx) -#define SCTP_IPI_ITERATOR_WQ_LOCK() \ - EnterCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx) -#define SCTP_IPI_ITERATOR_WQ_UNLOCK() \ - LeaveCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx) - -#else -/* address list locks */ -#define SCTP_IPI_ADDR_INIT() \ - (void)pthread_rwlock_init(&SCTP_BASE_INFO(ipi_addr_mtx), &SCTP_BASE_VAR(rwlock_attr)) -#define SCTP_IPI_ADDR_DESTROY() \ - (void)pthread_rwlock_destroy(&SCTP_BASE_INFO(ipi_addr_mtx)) -#ifdef INVARIANTS -#define SCTP_IPI_ADDR_RLOCK() \ - KASSERT(pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx already locked", __FILE__, __LINE__)) -#define SCTP_IPI_ADDR_RUNLOCK() \ - KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx not locked", __FILE__, __LINE__)) -#define SCTP_IPI_ADDR_WLOCK() \ - KASSERT(pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx already locked", __FILE__, __LINE__)) -#define SCTP_IPI_ADDR_WUNLOCK() \ - KASSERT(pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s:%d: ipi_addr_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_IPI_ADDR_RLOCK() \ - (void)pthread_rwlock_rdlock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_RUNLOCK() \ - (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WLOCK() \ - (void)pthread_rwlock_wrlock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WUNLOCK() \ - (void)pthread_rwlock_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#endif -#define SCTP_IPI_ADDR_LOCK_ASSERT() -#define SCTP_IPI_ADDR_WLOCK_ASSERT() - -/* iterator locks */ -#define SCTP_ITERATOR_LOCK_INIT() \ - (void)pthread_mutex_init(&sctp_it_ctl.it_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_ITERATOR_LOCK_DESTROY() \ - (void)pthread_mutex_destroy(&sctp_it_ctl.it_mtx) -#ifdef INVARIANTS -#define SCTP_ITERATOR_LOCK() \ - KASSERT(pthread_mutex_lock(&sctp_it_ctl.it_mtx) == 0, ("%s:%d: it_mtx already locked", __FILE__, __LINE__)) -#define SCTP_ITERATOR_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&sctp_it_ctl.it_mtx) == 0, ("%s:%d: it_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_ITERATOR_LOCK() \ - (void)pthread_mutex_lock(&sctp_it_ctl.it_mtx) -#define SCTP_ITERATOR_UNLOCK() \ - (void)pthread_mutex_unlock(&sctp_it_ctl.it_mtx) -#endif - -#define SCTP_IPI_ITERATOR_WQ_INIT() \ - (void)pthread_mutex_init(&sctp_it_ctl.ipi_iterator_wq_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_IPI_ITERATOR_WQ_DESTROY() \ - (void)pthread_mutex_destroy(&sctp_it_ctl.ipi_iterator_wq_mtx) -#ifdef INVARIANTS -#define SCTP_IPI_ITERATOR_WQ_LOCK() \ - KASSERT(pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s:%d: ipi_iterator_wq_mtx already locked", __FILE__, __LINE__)) -#define SCTP_IPI_ITERATOR_WQ_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s:%d: ipi_iterator_wq_mtx not locked", __FILE__, __LINE__)) -#else -#define SCTP_IPI_ITERATOR_WQ_LOCK() \ - (void)pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) -#define SCTP_IPI_ITERATOR_WQ_UNLOCK() \ - (void)pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) -#endif -#endif - -#define SCTP_INCR_EP_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_ep), 1) - -#define SCTP_DECR_EP_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_ep), 1) - -#define SCTP_INCR_ASOC_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_asoc), 1) - -#define SCTP_DECR_ASOC_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_asoc), 1) - -#define SCTP_INCR_LADDR_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_laddr), 1) - -#define SCTP_DECR_LADDR_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_laddr), 1) - -#define SCTP_INCR_RADDR_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_raddr), 1) - -#define SCTP_DECR_RADDR_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_raddr), 1) - -#define SCTP_INCR_CHK_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_chunk), 1) - -#define SCTP_DECR_CHK_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1) - -#define SCTP_INCR_READQ_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_readq), 1) - -#define SCTP_DECR_READQ_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_readq), 1) - -#define SCTP_INCR_STRMOQ_COUNT() \ - atomic_add_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1) - -#define SCTP_DECR_STRMOQ_COUNT() \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1) - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.c deleted file mode 100644 index 8472c3a1..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.c +++ /dev/null @@ -1,347 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2013, by Michael Tuexen. All rights reserved. - * Copyright (c) 2013, by Lally Singh. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#if defined(SCTP_USE_NSS_SHA1) -/* A SHA-1 Digest is 160 bits, or 20 bytes */ -#define SHA_DIGEST_LENGTH (20) - -void -sctp_sha1_init(struct sctp_sha1_context *ctx) -{ - ctx->pk11_ctx = PK11_CreateDigestContext(SEC_OID_SHA1); - PK11_DigestBegin(ctx->pk11_ctx); -} - -void -sctp_sha1_update(struct sctp_sha1_context *ctx, const unsigned char *ptr, unsigned int siz) -{ - PK11_DigestOp(ctx->pk11_ctx, ptr, siz); -} - -void -sctp_sha1_final(unsigned char *digest, struct sctp_sha1_context *ctx) -{ - unsigned int output_len = 0; - - PK11_DigestFinal(ctx->pk11_ctx, digest, &output_len, SHA_DIGEST_LENGTH); - PK11_DestroyContext(ctx->pk11_ctx, PR_TRUE); -} - -#elif defined(SCTP_USE_OPENSSL_SHA1) - -void -sctp_sha1_init(struct sctp_sha1_context *ctx) -{ - SHA1_Init(&ctx->sha_ctx); -} - -void -sctp_sha1_update(struct sctp_sha1_context *ctx, const unsigned char *ptr, unsigned int siz) -{ - SHA1_Update(&ctx->sha_ctx, ptr, (unsigned long)siz); -} - -void -sctp_sha1_final(unsigned char *digest, struct sctp_sha1_context *ctx) -{ - SHA1_Final(digest, &ctx->sha_ctx); -} -#elif defined(SCTP_USE_MBEDTLS_SHA1) -void -sctp_sha1_init(struct sctp_sha1_context *ctx) -{ - mbedtls_sha1_init(&ctx->sha1_ctx); - mbedtls_sha1_starts_ret(&ctx->sha1_ctx); -} - -void -sctp_sha1_update(struct sctp_sha1_context *ctx, const unsigned char *ptr, unsigned int siz) -{ - mbedtls_sha1_update_ret(&ctx->sha1_ctx, ptr, siz); -} - -void -sctp_sha1_final(unsigned char *digest, struct sctp_sha1_context *ctx) -{ - mbedtls_sha1_finish_ret(&ctx->sha1_ctx, digest); -} -#else - -#include -#if defined(_WIN32) && defined(__Userspace__) -#include -#elif !(defined(_WIN32) && !defined(__Userspace__)) -#include -#endif - -#define F1(B,C,D) (((B & C) | ((~B) & D))) /* 0 <= t <= 19 */ -#define F2(B,C,D) (B ^ C ^ D) /* 20 <= t <= 39 */ -#define F3(B,C,D) ((B & C) | (B & D) | (C & D)) /* 40 <= t <= 59 */ -#define F4(B,C,D) (B ^ C ^ D) /* 600 <= t <= 79 */ - -/* circular shift */ -#define CSHIFT(A,B) ((B << A) | (B >> (32-A))) - -#define K1 0x5a827999 /* 0 <= t <= 19 */ -#define K2 0x6ed9eba1 /* 20 <= t <= 39 */ -#define K3 0x8f1bbcdc /* 40 <= t <= 59 */ -#define K4 0xca62c1d6 /* 60 <= t <= 79 */ - -#define H0INIT 0x67452301 -#define H1INIT 0xefcdab89 -#define H2INIT 0x98badcfe -#define H3INIT 0x10325476 -#define H4INIT 0xc3d2e1f0 - -void -sctp_sha1_init(struct sctp_sha1_context *ctx) -{ - /* Init the SHA-1 context structure */ - ctx->A = 0; - ctx->B = 0; - ctx->C = 0; - ctx->D = 0; - ctx->E = 0; - ctx->H0 = H0INIT; - ctx->H1 = H1INIT; - ctx->H2 = H2INIT; - ctx->H3 = H3INIT; - ctx->H4 = H4INIT; - ctx->TEMP = 0; - memset(ctx->words, 0, sizeof(ctx->words)); - ctx->how_many_in_block = 0; - ctx->running_total = 0; -} - -static void -sctp_sha1_process_a_block(struct sctp_sha1_context *ctx, unsigned int *block) -{ - int i; - - /* init the W0-W15 to the block of words being hashed. */ - /* step a) */ - for (i = 0; i < 16; i++) { - ctx->words[i] = ntohl(block[i]); - } - /* now init the rest based on the SHA-1 formula, step b) */ - for (i = 16; i < 80; i++) { - ctx->words[i] = CSHIFT(1, ((ctx->words[(i - 3)]) ^ - (ctx->words[(i - 8)]) ^ - (ctx->words[(i - 14)]) ^ - (ctx->words[(i - 16)]))); - } - /* step c) */ - ctx->A = ctx->H0; - ctx->B = ctx->H1; - ctx->C = ctx->H2; - ctx->D = ctx->H3; - ctx->E = ctx->H4; - - /* step d) */ - for (i = 0; i < 80; i++) { - if (i < 20) { - ctx->TEMP = ((CSHIFT(5, ctx->A)) + - (F1(ctx->B, ctx->C, ctx->D)) + - (ctx->E) + - ctx->words[i] + - K1); - } else if (i < 40) { - ctx->TEMP = ((CSHIFT(5, ctx->A)) + - (F2(ctx->B, ctx->C, ctx->D)) + - (ctx->E) + - (ctx->words[i]) + - K2); - } else if (i < 60) { - ctx->TEMP = ((CSHIFT(5, ctx->A)) + - (F3(ctx->B, ctx->C, ctx->D)) + - (ctx->E) + - (ctx->words[i]) + - K3); - } else { - ctx->TEMP = ((CSHIFT(5, ctx->A)) + - (F4(ctx->B, ctx->C, ctx->D)) + - (ctx->E) + - (ctx->words[i]) + - K4); - } - ctx->E = ctx->D; - ctx->D = ctx->C; - ctx->C = CSHIFT(30, ctx->B); - ctx->B = ctx->A; - ctx->A = ctx->TEMP; - } - /* step e) */ - ctx->H0 = (ctx->H0) + (ctx->A); - ctx->H1 = (ctx->H1) + (ctx->B); - ctx->H2 = (ctx->H2) + (ctx->C); - ctx->H3 = (ctx->H3) + (ctx->D); - ctx->H4 = (ctx->H4) + (ctx->E); -} - -void -sctp_sha1_update(struct sctp_sha1_context *ctx, const unsigned char *ptr, unsigned int siz) -{ - unsigned int number_left, left_to_fill; - - number_left = siz; - while (number_left > 0) { - left_to_fill = sizeof(ctx->sha_block) - ctx->how_many_in_block; - if (left_to_fill > number_left) { - /* can only partially fill up this one */ - memcpy(&ctx->sha_block[ctx->how_many_in_block], - ptr, number_left); - ctx->how_many_in_block += number_left; - ctx->running_total += number_left; - break; - } else { - /* block is now full, process it */ - memcpy(&ctx->sha_block[ctx->how_many_in_block], - ptr, left_to_fill); - sctp_sha1_process_a_block(ctx, - (unsigned int *)ctx->sha_block); - number_left -= left_to_fill; - ctx->running_total += left_to_fill; - ctx->how_many_in_block = 0; - ptr = (const unsigned char *)(ptr + left_to_fill); - } - } -} - -void -sctp_sha1_final(unsigned char *digest, struct sctp_sha1_context *ctx) -{ - /* - * if any left in block fill with padding and process. Then transfer - * the digest to the pointer. At the last block some special rules - * need to apply. We must add a 1 bit following the message, then we - * pad with 0's. The total size is encoded as a 64 bit number at the - * end. Now if the last buffer has more than 55 octets in it we - * cannot fit the 64 bit number + 10000000 pad on the end and must - * add the 10000000 pad, pad the rest of the message with 0's and - * then create an all 0 message with just the 64 bit size at the end - * and run this block through by itself. Also the 64 bit int must - * be in network byte order. - */ - int left_to_fill; - unsigned int i, *ptr; - - if (ctx->how_many_in_block > 55) { - /* - * special case, we need to process two blocks here. One for - * the current stuff plus possibly the pad. The other for - * the size. - */ - left_to_fill = sizeof(ctx->sha_block) - ctx->how_many_in_block; - if (left_to_fill == 0) { - /* Should not really happen but I am paranoid */ - sctp_sha1_process_a_block(ctx, - (unsigned int *)ctx->sha_block); - /* init last block, a bit different than the rest */ - ctx->sha_block[0] = '\x80'; - for (i = 1; i < sizeof(ctx->sha_block); i++) { - ctx->sha_block[i] = 0x0; - } - } else if (left_to_fill == 1) { - ctx->sha_block[ctx->how_many_in_block] = '\x80'; - sctp_sha1_process_a_block(ctx, - (unsigned int *)ctx->sha_block); - /* init last block */ - memset(ctx->sha_block, 0, sizeof(ctx->sha_block)); - } else { - ctx->sha_block[ctx->how_many_in_block] = '\x80'; - for (i = (ctx->how_many_in_block + 1); - i < sizeof(ctx->sha_block); - i++) { - ctx->sha_block[i] = 0x0; - } - sctp_sha1_process_a_block(ctx, - (unsigned int *)ctx->sha_block); - /* init last block */ - memset(ctx->sha_block, 0, sizeof(ctx->sha_block)); - } - /* This is in bits so multiply by 8 */ - ctx->running_total *= 8; - ptr = (unsigned int *)&ctx->sha_block[60]; - *ptr = htonl(ctx->running_total); - sctp_sha1_process_a_block(ctx, (unsigned int *)ctx->sha_block); - } else { - /* - * easy case, we just pad this message to size - end with 0 - * add the magic 0x80 to the next word and then put the - * network byte order size in the last spot and process the - * block. - */ - ctx->sha_block[ctx->how_many_in_block] = '\x80'; - for (i = (ctx->how_many_in_block + 1); - i < sizeof(ctx->sha_block); - i++) { - ctx->sha_block[i] = 0x0; - } - /* get last int spot */ - ctx->running_total *= 8; - ptr = (unsigned int *)&ctx->sha_block[60]; - *ptr = htonl(ctx->running_total); - sctp_sha1_process_a_block(ctx, (unsigned int *)ctx->sha_block); - } - /* transfer the digest back to the user */ - digest[3] = (ctx->H0 & 0xff); - digest[2] = ((ctx->H0 >> 8) & 0xff); - digest[1] = ((ctx->H0 >> 16) & 0xff); - digest[0] = ((ctx->H0 >> 24) & 0xff); - - digest[7] = (ctx->H1 & 0xff); - digest[6] = ((ctx->H1 >> 8) & 0xff); - digest[5] = ((ctx->H1 >> 16) & 0xff); - digest[4] = ((ctx->H1 >> 24) & 0xff); - - digest[11] = (ctx->H2 & 0xff); - digest[10] = ((ctx->H2 >> 8) & 0xff); - digest[9] = ((ctx->H2 >> 16) & 0xff); - digest[8] = ((ctx->H2 >> 24) & 0xff); - - digest[15] = (ctx->H3 & 0xff); - digest[14] = ((ctx->H3 >> 8) & 0xff); - digest[13] = ((ctx->H3 >> 16) & 0xff); - digest[12] = ((ctx->H3 >> 24) & 0xff); - - digest[19] = (ctx->H4 & 0xff); - digest[18] = ((ctx->H4 >> 8) & 0xff); - digest[17] = ((ctx->H4 >> 16) & 0xff); - digest[16] = ((ctx->H4 >> 24) & 0xff); -} - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.h deleted file mode 100644 index 9ff4ff7b..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sha1.h +++ /dev/null @@ -1,94 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - - -#ifndef __NETINET_SCTP_SHA1_H__ -#define __NETINET_SCTP_SHA1_H__ - -#include -#if defined(SCTP_USE_NSS_SHA1) -#include -#elif defined(SCTP_USE_OPENSSL_SHA1) -#include -#elif defined(SCTP_USE_MBEDTLS_SHA1) -#include -#endif - -struct sctp_sha1_context { -#if defined(SCTP_USE_NSS_SHA1) - struct PK11Context *pk11_ctx; -#elif defined(SCTP_USE_OPENSSL_SHA1) - SHA_CTX sha_ctx; -#elif defined(SCTP_USE_MBEDTLS_SHA1) - mbedtls_sha1_context sha1_ctx; -#else - unsigned int A; - unsigned int B; - unsigned int C; - unsigned int D; - unsigned int E; - unsigned int H0; - unsigned int H1; - unsigned int H2; - unsigned int H3; - unsigned int H4; - unsigned int words[80]; - unsigned int TEMP; - /* block I am collecting to process */ - char sha_block[64]; - /* collected so far */ - int how_many_in_block; - unsigned int running_total; -#endif -}; - -#if (defined(__APPLE__) && !defined(__Userspace__) && defined(KERNEL)) -#ifndef _KERNEL -#define _KERNEL -#endif -#endif - -#if defined(_KERNEL) || defined(__Userspace__) - -void sctp_sha1_init(struct sctp_sha1_context *); -void sctp_sha1_update(struct sctp_sha1_context *, const unsigned char *, unsigned int); -void sctp_sha1_final(unsigned char *, struct sctp_sha1_context *); - -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_ss_functions.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_ss_functions.c deleted file mode 100644 index c1d2aada..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_ss_functions.c +++ /dev/null @@ -1,1128 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved. - * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2010-2012, by Robin Seggelmann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#if defined(__Userspace__) -#include -#endif - -/* - * Default simple round-robin algorithm. - * Just iterates the streams in the order they appear. - */ - -static void -sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *, - struct sctp_stream_out *, - struct sctp_stream_queue_pending *); - -static void -sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *, - struct sctp_stream_out *, - struct sctp_stream_queue_pending *); - -static void -sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc) -{ - uint16_t i; - - SCTP_TCB_LOCK_ASSERT(stcb); - - asoc->ss_data.locked_on_sending = NULL; - asoc->ss_data.last_out_stream = NULL; - TAILQ_INIT(&asoc->ss_data.out.wheel); - /* - * If there is data in the stream queues already, - * the scheduler of an existing association has - * been changed. We need to add all stream queues - * to the wheel. - */ - for (i = 0; i < asoc->streamoutcnt; i++) { - stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, - &asoc->strmout[i], - NULL); - } - return; -} - -static void -sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - bool clear_values SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - struct sctp_stream_out *strq; - - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); - TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); - strq->ss_params.scheduled = false; - } - asoc->ss_data.last_out_stream = NULL; - return; -} - -static void -sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (with_strq != NULL) { - if (stcb->asoc.ss_data.locked_on_sending == with_strq) { - stcb->asoc.ss_data.locked_on_sending = strq; - } - if (stcb->asoc.ss_data.last_out_stream == with_strq) { - stcb->asoc.ss_data.last_out_stream = strq; - } - } - strq->ss_params.scheduled = false; - return; -} - -static void -sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Add to wheel if not already on it and stream queue not empty */ - if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { - TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, - strq, ss_params.ss.rr.next_spoke); - strq->ss_params.scheduled = true; - } - return; -} - -static bool -sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - return (TAILQ_EMPTY(&asoc->ss_data.out.wheel)); -} - -static void -sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Remove from wheel if stream queue is empty and actually is on the wheel */ - if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { - if (asoc->ss_data.last_out_stream == strq) { - asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, - sctpwheel_listhead, - ss_params.ss.rr.next_spoke); - if (asoc->ss_data.last_out_stream == NULL) { - asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, - sctpwheel_listhead); - } - if (asoc->ss_data.last_out_stream == strq) { - asoc->ss_data.last_out_stream = NULL; - } - } - if (asoc->ss_data.locked_on_sending == strq) { - asoc->ss_data.locked_on_sending = NULL; - } - TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); - strq->ss_params.scheduled = false; - } - return; -} - -static struct sctp_stream_out * -sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, - struct sctp_association *asoc) -{ - struct sctp_stream_out *strq, *strqt; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (asoc->ss_data.locked_on_sending != NULL) { - KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, - ("locked_on_sending %p not scheduled", - (void *)asoc->ss_data.locked_on_sending)); - return (asoc->ss_data.locked_on_sending); - } - strqt = asoc->ss_data.last_out_stream; - KASSERT(strqt == NULL || strqt->ss_params.scheduled, - ("last_out_stream %p not scheduled", (void *)strqt)); -default_again: - /* Find the next stream to use */ - if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } else { - strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); - if (strq == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } - } - KASSERT(strq == NULL || strq->ss_params.scheduled, - ("strq %p not scheduled", (void *)strq)); - - /* If CMT is off, we must validate that - * the stream in question has the first - * item pointed towards are network destination - * requested by the caller. Note that if we - * turn out to be locked to a stream (assigning - * TSN's then we must stop, since we cannot - * look for another stream with data to send - * to that destination). In CMT's case, by - * skipping this check, we will send one - * data packet towards the requested net. - */ - if (net != NULL && strq != NULL && - SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { - if (TAILQ_FIRST(&strq->outqueue) && - TAILQ_FIRST(&strq->outqueue)->net != NULL && - TAILQ_FIRST(&strq->outqueue)->net != net) { - if (strq == asoc->ss_data.last_out_stream) { - return (NULL); - } else { - strqt = strq; - goto default_again; - } - } - } - return (strq); -} - -static void -sctp_ss_default_scheduled(struct sctp_tcb *stcb, - struct sctp_nets *net SCTP_UNUSED, - struct sctp_association *asoc, - struct sctp_stream_out *strq, - int moved_how_much SCTP_UNUSED) -{ - struct sctp_stream_queue_pending *sp; - - KASSERT(strq != NULL, ("strq is NULL")); - KASSERT(strq->ss_params.scheduled, ("strq %p is not scheduled", (void *)strq)); - SCTP_TCB_LOCK_ASSERT(stcb); - - asoc->ss_data.last_out_stream = strq; - if (asoc->idata_supported == 0) { - sp = TAILQ_FIRST(&strq->outqueue); - if ((sp != NULL) && (sp->some_taken == 1)) { - asoc->ss_data.locked_on_sending = strq; - } else { - asoc->ss_data.locked_on_sending = NULL; - } - } else { - asoc->ss_data.locked_on_sending = NULL; - } - return; -} - -static void -sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, - struct sctp_association *asoc SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Nothing to be done here */ - return; -} - -static int -sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, - struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Nothing to be done here */ - return (-1); -} - -static int -sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, - struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Nothing to be done here */ - return (-1); -} - -static bool -sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) -{ - struct sctp_stream_out *strq; - struct sctp_stream_queue_pending *sp; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (asoc->stream_queue_cnt != 1) { - return (false); - } - strq = asoc->ss_data.locked_on_sending; - if (strq == NULL) { - return (false); - } - sp = TAILQ_FIRST(&strq->outqueue); - if (sp == NULL) { - return (false); - } - return (sp->msg_is_complete == 0); -} - -/* - * Real round-robin algorithm. - * Always iterates the streams in ascending order. - */ -static void -sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - struct sctp_stream_out *strqt; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { - if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); - } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); - while (strqt != NULL && (strqt->sid < strq->sid)) { - strqt = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); - } - if (strqt != NULL) { - TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.rr.next_spoke); - } else { - TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); - } - } - strq->ss_params.scheduled = true; - } - return; -} - -/* - * Real round-robin per packet algorithm. - * Always iterates the streams in ascending order and - * only fills messages of the same stream in a packet. - */ -static struct sctp_stream_out * -sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, - struct sctp_association *asoc) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - return (asoc->ss_data.last_out_stream); -} - -static void -sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, - struct sctp_association *asoc) -{ - struct sctp_stream_out *strq, *strqt; - - SCTP_TCB_LOCK_ASSERT(stcb); - - strqt = asoc->ss_data.last_out_stream; - KASSERT(strqt == NULL || strqt->ss_params.scheduled, - ("last_out_stream %p not scheduled", (void *)strqt)); -rrp_again: - /* Find the next stream to use */ - if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } else { - strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); - if (strq == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } - } - KASSERT(strq == NULL || strq->ss_params.scheduled, - ("strq %p not scheduled", (void *)strq)); - - /* If CMT is off, we must validate that - * the stream in question has the first - * item pointed towards are network destination - * requested by the caller. Note that if we - * turn out to be locked to a stream (assigning - * TSN's then we must stop, since we cannot - * look for another stream with data to send - * to that destination). In CMT's case, by - * skipping this check, we will send one - * data packet towards the requested net. - */ - if (net != NULL && strq != NULL && - SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { - if (TAILQ_FIRST(&strq->outqueue) && - TAILQ_FIRST(&strq->outqueue)->net != NULL && - TAILQ_FIRST(&strq->outqueue)->net != net) { - if (strq == asoc->ss_data.last_out_stream) { - strq = NULL; - } else { - strqt = strq; - goto rrp_again; - } - } - } - asoc->ss_data.last_out_stream = strq; - return; -} - -/* - * Priority algorithm. - * Always prefers streams based on their priority id. - */ -static void -sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - bool clear_values) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - struct sctp_stream_out *strq; - - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); - if (clear_values) { - strq->ss_params.ss.prio.priority = 0; - } - TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); - strq->ss_params.scheduled = false; - } - asoc->ss_data.last_out_stream = NULL; - return; -} - -static void -sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (with_strq != NULL) { - if (stcb->asoc.ss_data.locked_on_sending == with_strq) { - stcb->asoc.ss_data.locked_on_sending = strq; - } - if (stcb->asoc.ss_data.last_out_stream == with_strq) { - stcb->asoc.ss_data.last_out_stream = strq; - } - } - strq->ss_params.scheduled = false; - if (with_strq != NULL) { - strq->ss_params.ss.prio.priority = with_strq->ss_params.ss.prio.priority; - } else { - strq->ss_params.ss.prio.priority = 0; - } - return; -} - -static void -sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - struct sctp_stream_out *strqt; - - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Add to wheel if not already on it and stream queue not empty */ - if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { - if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); - } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); - while (strqt != NULL && strqt->ss_params.ss.prio.priority < strq->ss_params.ss.prio.priority) { - strqt = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke); - } - if (strqt != NULL) { - TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.prio.next_spoke); - } else { - TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); - } - } - strq->ss_params.scheduled = true; - } - return; -} - -static void -sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Remove from wheel if stream queue is empty and actually is on the wheel */ - if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { - if (asoc->ss_data.last_out_stream == strq) { - asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, - sctpwheel_listhead, - ss_params.ss.prio.next_spoke); - if (asoc->ss_data.last_out_stream == NULL) { - asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, - sctpwheel_listhead); - } - if (asoc->ss_data.last_out_stream == strq) { - asoc->ss_data.last_out_stream = NULL; - } - } - if (asoc->ss_data.locked_on_sending == strq) { - asoc->ss_data.locked_on_sending = NULL; - } - TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); - strq->ss_params.scheduled = false; - } - return; -} - -static struct sctp_stream_out* -sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, - struct sctp_association *asoc) -{ - struct sctp_stream_out *strq, *strqt, *strqn; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (asoc->ss_data.locked_on_sending != NULL) { - KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, - ("locked_on_sending %p not scheduled", - (void *)asoc->ss_data.locked_on_sending)); - return (asoc->ss_data.locked_on_sending); - } - strqt = asoc->ss_data.last_out_stream; - KASSERT(strqt == NULL || strqt->ss_params.scheduled, - ("last_out_stream %p not scheduled", (void *)strqt)); -prio_again: - /* Find the next stream to use */ - if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } else { - strqn = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke); - if (strqn != NULL && - strqn->ss_params.ss.prio.priority == strqt->ss_params.ss.prio.priority) { - strq = strqn; - } else { - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } - } - KASSERT(strq == NULL || strq->ss_params.scheduled, - ("strq %p not scheduled", (void *)strq)); - - /* If CMT is off, we must validate that - * the stream in question has the first - * item pointed towards are network destination - * requested by the caller. Note that if we - * turn out to be locked to a stream (assigning - * TSN's then we must stop, since we cannot - * look for another stream with data to send - * to that destination). In CMT's case, by - * skipping this check, we will send one - * data packet towards the requested net. - */ - if (net != NULL && strq != NULL && - SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { - if (TAILQ_FIRST(&strq->outqueue) && - TAILQ_FIRST(&strq->outqueue)->net != NULL && - TAILQ_FIRST(&strq->outqueue)->net != net) { - if (strq == asoc->ss_data.last_out_stream) { - return (NULL); - } else { - strqt = strq; - goto prio_again; - } - } - } - return (strq); -} - -static int -sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, - struct sctp_stream_out *strq, uint16_t *value) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (strq == NULL) { - return (-1); - } - *value = strq->ss_params.ss.prio.priority; - return (1); -} - -static int -sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, uint16_t value) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (strq == NULL) { - return (-1); - } - strq->ss_params.ss.prio.priority = value; - sctp_ss_prio_remove(stcb, asoc, strq, NULL); - sctp_ss_prio_add(stcb, asoc, strq, NULL); - return (1); -} - -/* - * Fair bandwidth algorithm. - * Maintains an equal throughput per stream. - */ -static void -sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - bool clear_values) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { - struct sctp_stream_out *strq; - - strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); - if (clear_values) { - strq->ss_params.ss.fb.rounds = -1; - } - TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); - strq->ss_params.scheduled = false; - } - asoc->ss_data.last_out_stream = NULL; - return; -} - -static void -sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (with_strq != NULL) { - if (stcb->asoc.ss_data.locked_on_sending == with_strq) { - stcb->asoc.ss_data.locked_on_sending = strq; - } - if (stcb->asoc.ss_data.last_out_stream == with_strq) { - stcb->asoc.ss_data.last_out_stream = strq; - } - } - strq->ss_params.scheduled = false; - if (with_strq != NULL) { - strq->ss_params.ss.fb.rounds = with_strq->ss_params.ss.fb.rounds; - } else { - strq->ss_params.ss.fb.rounds = -1; - } - return; -} - -static void -sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { - if (strq->ss_params.ss.fb.rounds < 0) - strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; - TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); - strq->ss_params.scheduled = true; - } - return; -} - -static void -sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - /* Remove from wheel if stream queue is empty and actually is on the wheel */ - if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { - if (asoc->ss_data.last_out_stream == strq) { - asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, - sctpwheel_listhead, - ss_params.ss.fb.next_spoke); - if (asoc->ss_data.last_out_stream == NULL) { - asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, - sctpwheel_listhead); - } - if (asoc->ss_data.last_out_stream == strq) { - asoc->ss_data.last_out_stream = NULL; - } - } - if (asoc->ss_data.locked_on_sending == strq) { - asoc->ss_data.locked_on_sending = NULL; - } - TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); - strq->ss_params.scheduled = false; - } - return; -} - -static struct sctp_stream_out* -sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, - struct sctp_association *asoc) -{ - struct sctp_stream_out *strq = NULL, *strqt; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (asoc->ss_data.locked_on_sending != NULL) { - KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, - ("locked_on_sending %p not scheduled", - (void *)asoc->ss_data.locked_on_sending)); - return (asoc->ss_data.locked_on_sending); - } - if (asoc->ss_data.last_out_stream == NULL || - TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) { - strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } else { - strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.ss.fb.next_spoke); - } - do { - if ((strqt != NULL) && - ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) || - (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 && - (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) || - (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL && - TAILQ_FIRST(&strqt->outqueue)->net == net))))) { - if ((strqt->ss_params.ss.fb.rounds >= 0) && - ((strq == NULL) || - (strqt->ss_params.ss.fb.rounds < strq->ss_params.ss.fb.rounds))) { - strq = strqt; - } - } - if (strqt != NULL) { - strqt = TAILQ_NEXT(strqt, ss_params.ss.fb.next_spoke); - } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); - } - } while (strqt != strq); - return (strq); -} - -static void -sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, - struct sctp_association *asoc, struct sctp_stream_out *strq, - int moved_how_much SCTP_UNUSED) -{ - struct sctp_stream_queue_pending *sp; - struct sctp_stream_out *strqt; - int subtract; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (asoc->idata_supported == 0) { - sp = TAILQ_FIRST(&strq->outqueue); - if ((sp != NULL) && (sp->some_taken == 1)) { - asoc->ss_data.locked_on_sending = strq; - } else { - asoc->ss_data.locked_on_sending = NULL; - } - } else { - asoc->ss_data.locked_on_sending = NULL; - } - subtract = strq->ss_params.ss.fb.rounds; - TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.ss.fb.next_spoke) { - strqt->ss_params.ss.fb.rounds -= subtract; - if (strqt->ss_params.ss.fb.rounds < 0) - strqt->ss_params.ss.fb.rounds = 0; - } - if (TAILQ_FIRST(&strq->outqueue)) { - strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; - } else { - strq->ss_params.ss.fb.rounds = -1; - } - asoc->ss_data.last_out_stream = strq; - return; -} - -/* - * First-come, first-serve algorithm. - * Maintains the order provided by the application. - */ -static void -sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq SCTP_UNUSED, - struct sctp_stream_queue_pending *sp); - -static void -sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc) -{ - uint32_t x, n = 0, add_more = 1; - struct sctp_stream_queue_pending *sp; - uint16_t i; - - SCTP_TCB_LOCK_ASSERT(stcb); - - TAILQ_INIT(&asoc->ss_data.out.list); - /* - * If there is data in the stream queues already, - * the scheduler of an existing association has - * been changed. We can only cycle through the - * stream queues and add everything to the FCFS - * queue. - */ - while (add_more) { - add_more = 0; - for (i = 0; i < asoc->streamoutcnt; i++) { - sp = TAILQ_FIRST(&asoc->strmout[i].outqueue); - x = 0; - /* Find n. message in current stream queue */ - while (sp != NULL && x < n) { - sp = TAILQ_NEXT(sp, next); - x++; - } - if (sp != NULL) { - sctp_ss_fcfs_add(stcb, asoc, &asoc->strmout[i], sp); - add_more = 1; - } - } - n++; - } - return; -} - -static void -sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, - bool clear_values SCTP_UNUSED) -{ - struct sctp_stream_queue_pending *sp; - - SCTP_TCB_LOCK_ASSERT(stcb); - - while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) { - sp = TAILQ_FIRST(&asoc->ss_data.out.list); - KASSERT(sp->scheduled, ("sp %p not scheduled", (void *)sp)); - TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); - sp->scheduled = false; - } - asoc->ss_data.last_out_stream = NULL; - return; -} - -static void -sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (with_strq != NULL) { - if (stcb->asoc.ss_data.locked_on_sending == with_strq) { - stcb->asoc.ss_data.locked_on_sending = strq; - } - if (stcb->asoc.ss_data.last_out_stream == with_strq) { - stcb->asoc.ss_data.last_out_stream = strq; - } - } - strq->ss_params.scheduled = false; - return; -} - -static void -sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (!sp->scheduled) { - TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next); - sp->scheduled = true; - } - return; -} - -static bool -sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - return (TAILQ_EMPTY(&asoc->ss_data.out.list)); -} - -static void -sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp) -{ - SCTP_TCB_LOCK_ASSERT(stcb); - - if (sp->scheduled) { - TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); - sp->scheduled = false; - } - return; -} - -static struct sctp_stream_out * -sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, - struct sctp_association *asoc) -{ - struct sctp_stream_out *strq; - struct sctp_stream_queue_pending *sp; - - SCTP_TCB_LOCK_ASSERT(stcb); - - if (asoc->ss_data.locked_on_sending) { - return (asoc->ss_data.locked_on_sending); - } - sp = TAILQ_FIRST(&asoc->ss_data.out.list); -default_again: - if (sp != NULL) { - strq = &asoc->strmout[sp->sid]; - } else { - strq = NULL; - } - - /* - * If CMT is off, we must validate that - * the stream in question has the first - * item pointed towards are network destination - * requested by the caller. Note that if we - * turn out to be locked to a stream (assigning - * TSN's then we must stop, since we cannot - * look for another stream with data to send - * to that destination). In CMT's case, by - * skipping this check, we will send one - * data packet towards the requested net. - */ - if (net != NULL && strq != NULL && - SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { - if (TAILQ_FIRST(&strq->outqueue) && - TAILQ_FIRST(&strq->outqueue)->net != NULL && - TAILQ_FIRST(&strq->outqueue)->net != net) { - sp = TAILQ_NEXT(sp, ss_next); - goto default_again; - } - } - return (strq); -} - -static void -sctp_ss_fcfs_scheduled(struct sctp_tcb *stcb, - struct sctp_nets *net SCTP_UNUSED, - struct sctp_association *asoc, - struct sctp_stream_out *strq, - int moved_how_much SCTP_UNUSED) -{ - struct sctp_stream_queue_pending *sp; - - KASSERT(strq != NULL, ("strq is NULL")); - asoc->ss_data.last_out_stream = strq; - if (asoc->idata_supported == 0) { - sp = TAILQ_FIRST(&strq->outqueue); - if ((sp != NULL) && (sp->some_taken == 1)) { - asoc->ss_data.locked_on_sending = strq; - } else { - asoc->ss_data.locked_on_sending = NULL; - } - } else { - asoc->ss_data.locked_on_sending = NULL; - } - return; -} - -const struct sctp_ss_functions sctp_ss_functions[] = { -/* SCTP_SS_DEFAULT */ -{ -#if defined(_WIN32) - sctp_ss_default_init, - sctp_ss_default_clear, - sctp_ss_default_init_stream, - sctp_ss_default_add, - sctp_ss_default_is_empty, - sctp_ss_default_remove, - sctp_ss_default_select, - sctp_ss_default_scheduled, - sctp_ss_default_packet_done, - sctp_ss_default_get_value, - sctp_ss_default_set_value, - sctp_ss_default_is_user_msgs_incomplete -#else - .sctp_ss_init = sctp_ss_default_init, - .sctp_ss_clear = sctp_ss_default_clear, - .sctp_ss_init_stream = sctp_ss_default_init_stream, - .sctp_ss_add_to_stream = sctp_ss_default_add, - .sctp_ss_is_empty = sctp_ss_default_is_empty, - .sctp_ss_remove_from_stream = sctp_ss_default_remove, - .sctp_ss_select_stream = sctp_ss_default_select, - .sctp_ss_scheduled = sctp_ss_default_scheduled, - .sctp_ss_packet_done = sctp_ss_default_packet_done, - .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value, - .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete -#endif -}, -/* SCTP_SS_RR */ -{ -#if defined(_WIN32) - sctp_ss_default_init, - sctp_ss_default_clear, - sctp_ss_default_init_stream, - sctp_ss_rr_add, - sctp_ss_default_is_empty, - sctp_ss_default_remove, - sctp_ss_default_select, - sctp_ss_default_scheduled, - sctp_ss_default_packet_done, - sctp_ss_default_get_value, - sctp_ss_default_set_value, - sctp_ss_default_is_user_msgs_incomplete -#else - .sctp_ss_init = sctp_ss_default_init, - .sctp_ss_clear = sctp_ss_default_clear, - .sctp_ss_init_stream = sctp_ss_default_init_stream, - .sctp_ss_add_to_stream = sctp_ss_rr_add, - .sctp_ss_is_empty = sctp_ss_default_is_empty, - .sctp_ss_remove_from_stream = sctp_ss_default_remove, - .sctp_ss_select_stream = sctp_ss_default_select, - .sctp_ss_scheduled = sctp_ss_default_scheduled, - .sctp_ss_packet_done = sctp_ss_default_packet_done, - .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value, - .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete -#endif -}, -/* SCTP_SS_RR_PKT */ -{ -#if defined(_WIN32) - sctp_ss_default_init, - sctp_ss_default_clear, - sctp_ss_default_init_stream, - sctp_ss_rr_add, - sctp_ss_default_is_empty, - sctp_ss_default_remove, - sctp_ss_rrp_select, - sctp_ss_default_scheduled, - sctp_ss_rrp_packet_done, - sctp_ss_default_get_value, - sctp_ss_default_set_value, - sctp_ss_default_is_user_msgs_incomplete -#else - .sctp_ss_init = sctp_ss_default_init, - .sctp_ss_clear = sctp_ss_default_clear, - .sctp_ss_init_stream = sctp_ss_default_init_stream, - .sctp_ss_add_to_stream = sctp_ss_rr_add, - .sctp_ss_is_empty = sctp_ss_default_is_empty, - .sctp_ss_remove_from_stream = sctp_ss_default_remove, - .sctp_ss_select_stream = sctp_ss_rrp_select, - .sctp_ss_scheduled = sctp_ss_default_scheduled, - .sctp_ss_packet_done = sctp_ss_rrp_packet_done, - .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value, - .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete -#endif -}, -/* SCTP_SS_PRIO */ -{ -#if defined(_WIN32) - sctp_ss_default_init, - sctp_ss_prio_clear, - sctp_ss_prio_init_stream, - sctp_ss_prio_add, - sctp_ss_default_is_empty, - sctp_ss_prio_remove, - sctp_ss_prio_select, - sctp_ss_default_scheduled, - sctp_ss_default_packet_done, - sctp_ss_prio_get_value, - sctp_ss_prio_set_value, - sctp_ss_default_is_user_msgs_incomplete -#else - .sctp_ss_init = sctp_ss_default_init, - .sctp_ss_clear = sctp_ss_prio_clear, - .sctp_ss_init_stream = sctp_ss_prio_init_stream, - .sctp_ss_add_to_stream = sctp_ss_prio_add, - .sctp_ss_is_empty = sctp_ss_default_is_empty, - .sctp_ss_remove_from_stream = sctp_ss_prio_remove, - .sctp_ss_select_stream = sctp_ss_prio_select, - .sctp_ss_scheduled = sctp_ss_default_scheduled, - .sctp_ss_packet_done = sctp_ss_default_packet_done, - .sctp_ss_get_value = sctp_ss_prio_get_value, - .sctp_ss_set_value = sctp_ss_prio_set_value, - .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete -#endif -}, -/* SCTP_SS_FB */ -{ -#if defined(_WIN32) - sctp_ss_default_init, - sctp_ss_fb_clear, - sctp_ss_fb_init_stream, - sctp_ss_fb_add, - sctp_ss_default_is_empty, - sctp_ss_fb_remove, - sctp_ss_fb_select, - sctp_ss_fb_scheduled, - sctp_ss_default_packet_done, - sctp_ss_default_get_value, - sctp_ss_default_set_value, - sctp_ss_default_is_user_msgs_incomplete -#else - .sctp_ss_init = sctp_ss_default_init, - .sctp_ss_clear = sctp_ss_fb_clear, - .sctp_ss_init_stream = sctp_ss_fb_init_stream, - .sctp_ss_add_to_stream = sctp_ss_fb_add, - .sctp_ss_is_empty = sctp_ss_default_is_empty, - .sctp_ss_remove_from_stream = sctp_ss_fb_remove, - .sctp_ss_select_stream = sctp_ss_fb_select, - .sctp_ss_scheduled = sctp_ss_fb_scheduled, - .sctp_ss_packet_done = sctp_ss_default_packet_done, - .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value, - .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete -#endif -}, -/* SCTP_SS_FCFS */ -{ -#if defined(_WIN32) - sctp_ss_fcfs_init, - sctp_ss_fcfs_clear, - sctp_ss_fcfs_init_stream, - sctp_ss_fcfs_add, - sctp_ss_fcfs_is_empty, - sctp_ss_fcfs_remove, - sctp_ss_fcfs_select, - sctp_ss_fcfs_scheduled, - sctp_ss_default_packet_done, - sctp_ss_default_get_value, - sctp_ss_default_set_value, - sctp_ss_default_is_user_msgs_incomplete -#else - .sctp_ss_init = sctp_ss_fcfs_init, - .sctp_ss_clear = sctp_ss_fcfs_clear, - .sctp_ss_init_stream = sctp_ss_fcfs_init_stream, - .sctp_ss_add_to_stream = sctp_ss_fcfs_add, - .sctp_ss_is_empty = sctp_ss_fcfs_is_empty, - .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove, - .sctp_ss_select_stream = sctp_ss_fcfs_select, - .sctp_ss_scheduled = sctp_ss_fcfs_scheduled, - .sctp_ss_packet_done = sctp_ss_default_packet_done, - .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value, - .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete -#endif -} -}; diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_structs.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_structs.h deleted file mode 100644 index 35e66ba4..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_structs.h +++ /dev/null @@ -1,1296 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_STRUCTS_H_ -#define _NETINET_SCTP_STRUCTS_H_ - -#include -#include -#include - -struct sctp_timer { - sctp_os_timer_t timer; - - int type; - /* - * Depending on the timer type these will be setup and cast with the - * appropriate entity. - */ - void *ep; - void *tcb; - void *net; -#if defined(__FreeBSD__) && !defined(__Userspace__) - void *vnet; -#endif - - /* for sanity checking */ - void *self; - uint32_t ticks; - uint32_t stopped_from; -}; - -struct sctp_foo_stuff { - struct sctp_inpcb *inp; - uint32_t lineno; - uint32_t ticks; - int updown; -}; - -/* - * This is the information we track on each interface that we know about from - * the distant end. - */ -TAILQ_HEAD(sctpnetlisthead, sctp_nets); - -struct sctp_stream_reset_list { - TAILQ_ENTRY(sctp_stream_reset_list) next_resp; - uint32_t seq; - uint32_t tsn; - uint32_t number_entries; - uint16_t list_of_streams[]; -}; - -TAILQ_HEAD(sctp_resethead, sctp_stream_reset_list); - -/* - * Users of the iterator need to malloc a iterator with a call to - * sctp_initiate_iterator(inp_func, assoc_func, inp_func, pcb_flags, pcb_features, - * asoc_state, void-ptr-arg, uint32-arg, end_func, inp); - * - * Use the following two defines if you don't care what pcb flags are on the EP - * and/or you don't care what state the association is in. - * - * Note that if you specify an INP as the last argument then ONLY each - * association of that single INP will be executed upon. Note that the pcb - * flags STILL apply so if the inp you specify has different pcb_flags then - * what you put in pcb_flags nothing will happen. use SCTP_PCB_ANY_FLAGS to - * assure the inp you specify gets treated. - */ -#define SCTP_PCB_ANY_FLAGS 0x00000000 -#define SCTP_PCB_ANY_FEATURES 0x00000000 -#define SCTP_ASOC_ANY_STATE 0x00000000 - -typedef void (*asoc_func) (struct sctp_inpcb *, struct sctp_tcb *, void *ptr, - uint32_t val); -typedef int (*inp_func) (struct sctp_inpcb *, void *ptr, uint32_t val); -typedef void (*end_func) (void *ptr, uint32_t val); - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SCTP_MCORE_INPUT) && defined(SMP) -/* whats on the mcore control struct */ -struct sctp_mcore_queue { - TAILQ_ENTRY(sctp_mcore_queue) next; - struct vnet *vn; - struct mbuf *m; - int off; - int v6; -}; - -TAILQ_HEAD(sctp_mcore_qhead, sctp_mcore_queue); - -struct sctp_mcore_ctrl { - SCTP_PROCESS_STRUCT thread_proc; - struct sctp_mcore_qhead que; - struct mtx core_mtx; - struct mtx que_mtx; - int running; - int cpuid; -}; -#endif -#endif - -/* This struct is here to cut out the compatiabilty - * pad that bulks up both the inp and stcb. The non - * pad portion MUST stay in complete sync with - * sctp_sndrcvinfo... i.e. if sinfo_xxxx is added - * this must be done here too. - */ -struct sctp_nonpad_sndrcvinfo { - uint16_t sinfo_stream; - uint16_t sinfo_ssn; - uint16_t sinfo_flags; - uint32_t sinfo_ppid; - uint32_t sinfo_context; - uint32_t sinfo_timetolive; - uint32_t sinfo_tsn; - uint32_t sinfo_cumtsn; - sctp_assoc_t sinfo_assoc_id; - uint16_t sinfo_keynumber; - uint16_t sinfo_keynumber_valid; -}; - -struct sctp_iterator { - TAILQ_ENTRY(sctp_iterator) sctp_nxt_itr; -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct vnet *vn; -#endif - struct sctp_timer tmr; - struct sctp_inpcb *inp; /* current endpoint */ - struct sctp_tcb *stcb; /* current* assoc */ - struct sctp_inpcb *next_inp; /* special hook to skip to */ - asoc_func function_assoc; /* per assoc function */ - inp_func function_inp; /* per endpoint function */ - inp_func function_inp_end; /* end INP function */ - end_func function_atend; /* iterator completion function */ - void *pointer; /* pointer for apply func to use */ - uint32_t val; /* value for apply func to use */ - uint32_t pcb_flags; /* endpoint flags being checked */ - uint32_t pcb_features; /* endpoint features being checked */ - uint32_t asoc_state; /* assoc state being checked */ - uint32_t iterator_flags; - uint8_t no_chunk_output; - uint8_t done_current_ep; -}; -/* iterator_flags values */ -#define SCTP_ITERATOR_DO_ALL_INP 0x00000001 -#define SCTP_ITERATOR_DO_SINGLE_INP 0x00000002 - -TAILQ_HEAD(sctpiterators, sctp_iterator); - -struct sctp_copy_all { - struct sctp_inpcb *inp; /* ep */ - struct mbuf *m; - struct sctp_nonpad_sndrcvinfo sndrcv; - ssize_t sndlen; - int cnt_sent; - int cnt_failed; -}; - -struct sctp_asconf_iterator { - struct sctpladdr list_of_work; - int cnt; -}; - -struct iterator_control { -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct mtx ipi_iterator_wq_mtx; - struct mtx it_mtx; -#elif defined(__APPLE__) && !defined(__Userspace__) - lck_mtx_t *ipi_iterator_wq_mtx; - lck_mtx_t *it_mtx; -#elif defined(SCTP_PROCESS_LEVEL_LOCKS) -#if defined(__Userspace__) - userland_mutex_t ipi_iterator_wq_mtx; - userland_mutex_t it_mtx; - userland_cond_t iterator_wakeup; -#else - pthread_mutex_t ipi_iterator_wq_mtx; - pthread_mutex_t it_mtx; - pthread_cond_t iterator_wakeup; -#endif -#elif defined(_WIN32) && !defined(__Userspace__) - struct spinlock it_lock; - struct spinlock ipi_iterator_wq_lock; - KEVENT iterator_wakeup[2]; - PFILE_OBJECT iterator_thread_obj; -#else - void *it_mtx; -#endif -#if !(defined(_WIN32) && !defined(__Userspace__)) -#if !defined(__Userspace__) - SCTP_PROCESS_STRUCT thread_proc; -#else - userland_thread_t thread_proc; -#endif -#endif - struct sctpiterators iteratorhead; - struct sctp_iterator *cur_it; - uint32_t iterator_running; - uint32_t iterator_flags; -}; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) -#define SCTP_ITERATOR_MUST_EXIT 0x00000001 -#define SCTP_ITERATOR_EXITED 0x00000002 -#endif -#define SCTP_ITERATOR_STOP_CUR_IT 0x00000004 -#define SCTP_ITERATOR_STOP_CUR_INP 0x00000008 - -struct sctp_net_route { -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct nhop_object *ro_nh; - struct llentry *ro_lle; - char *ro_prepend; - uint16_t ro_plen; - uint16_t ro_flags; - uint16_t ro_mtu; - uint16_t spare; -#else - sctp_rtentry_t *ro_rt; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN) - struct llentry *ro_lle; -#endif -#if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) - struct ifaddr *ro_srcia; -#endif -#if !defined(APPLE_LEOPARD) - uint32_t ro_flags; -#endif -#endif - union sctp_sockstore _l_addr; /* remote peer addr */ - struct sctp_ifa *_s_addr; /* our selected src addr */ -}; - -struct htcp { - uint16_t alpha; /* Fixed point arith, << 7 */ - uint8_t beta; /* Fixed point arith, << 7 */ - uint8_t modeswitch; /* Delay modeswitch until we had at least one congestion event */ - uint32_t last_cong; /* Time since last congestion event end */ - uint32_t undo_last_cong; - uint16_t bytes_acked; - uint32_t bytecount; - uint32_t minRTT; - uint32_t maxRTT; - - uint32_t undo_maxRTT; - uint32_t undo_old_maxB; - - /* Bandwidth estimation */ - uint32_t minB; - uint32_t maxB; - uint32_t old_maxB; - uint32_t Bi; - uint32_t lasttime; -}; - -struct rtcc_cc { - struct timeval tls; /* The time we started the sending */ - uint64_t lbw; /* Our last estimated bw */ - uint64_t lbw_rtt; /* RTT at bw estimate */ - uint64_t bw_bytes; /* The total bytes since this sending began */ - uint64_t bw_tot_time; /* The total time since sending began */ - uint64_t new_tot_time; /* temp holding the new value */ - uint64_t bw_bytes_at_last_rttc; /* What bw_bytes was at last rtt calc */ - uint32_t cwnd_at_bw_set; /* Cwnd at last bw saved - lbw */ - uint32_t vol_reduce; /* cnt of voluntary reductions */ - uint16_t steady_step; /* The number required to be in steady state*/ - uint16_t step_cnt; /* The current number */ - uint8_t ret_from_eq; /* When all things are equal what do I return 0/1 - 1 no cc advance */ - uint8_t use_dccc_ecn; /* Flag to enable DCCC ECN */ - uint8_t tls_needs_set; /* Flag to indicate we need to set tls 0 or 1 means set at send 2 not */ - uint8_t last_step_state; /* Last state if steady state stepdown is on */ - uint8_t rtt_set_this_sack; /* Flag saying this sack had RTT calc on it */ - uint8_t last_inst_ind; /* Last saved inst indication */ -}; - -struct sctp_nets { - TAILQ_ENTRY(sctp_nets) sctp_next; /* next link */ - - /* - * Things on the top half may be able to be split into a common - * structure shared by all. - */ - struct sctp_timer pmtu_timer; - struct sctp_timer hb_timer; - - /* - * The following two in combination equate to a route entry for v6 - * or v4. - */ - struct sctp_net_route ro; - - /* mtu discovered so far */ - uint32_t mtu; - uint32_t ssthresh; /* not sure about this one for split */ - uint32_t last_cwr_tsn; - uint32_t cwr_window_tsn; - uint32_t ecn_ce_pkt_cnt; - uint32_t lost_cnt; - /* smoothed average things for RTT and RTO itself */ - int lastsa; - int lastsv; - uint64_t rtt; /* last measured rtt value in us */ - uint32_t RTO; - - /* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */ - struct sctp_timer rxt_timer; - - /* last time in seconds I sent to it */ - struct timeval last_sent_time; - union cc_control_data { - struct htcp htcp_ca; /* JRS - struct used in HTCP algorithm */ - struct rtcc_cc rtcc; /* rtcc module cc stuff */ - } cc_mod; - int ref_count; - - /* Congestion stats per destination */ - /* - * flight size variables and such, sorry Vern, I could not avoid - * this if I wanted performance :> - */ - uint32_t flight_size; - uint32_t cwnd; /* actual cwnd */ - uint32_t prev_cwnd; /* cwnd before any processing */ - uint32_t ecn_prev_cwnd; /* ECN prev cwnd at first ecn_echo seen in new window */ - uint32_t partial_bytes_acked; /* in CA tracks when to incr a MTU */ - /* tracking variables to avoid the aloc/free in sack processing */ - unsigned int net_ack; - unsigned int net_ack2; - - /* - * JRS - 5/8/07 - Variable to track last time - * a destination was active for CMT PF - */ - uint32_t last_active; - - /* - * CMT variables (iyengar@cis.udel.edu) - */ - uint32_t this_sack_highest_newack; /* tracks highest TSN newly - * acked for a given dest in - * the current SACK. Used in - * SFR and HTNA algos */ - uint32_t pseudo_cumack; /* CMT CUC algorithm. Maintains next expected - * pseudo-cumack for this destination */ - uint32_t rtx_pseudo_cumack; /* CMT CUC algorithm. Maintains next - * expected pseudo-cumack for this - * destination */ - - /* CMT fast recovery variables */ - uint32_t fast_recovery_tsn; - uint32_t heartbeat_random1; - uint32_t heartbeat_random2; -#ifdef INET6 - uint32_t flowlabel; -#endif - uint8_t dscp; - - struct timeval start_time; /* time when this net was created */ - uint32_t marked_retrans; /* number or DATA chunks marked for - timer based retransmissions */ - uint32_t marked_fastretrans; - uint32_t heart_beat_delay; /* Heart Beat delay in ms */ - - /* if this guy is ok or not ... status */ - uint16_t dest_state; - /* number of timeouts to consider the destination unreachable */ - uint16_t failure_threshold; - /* number of timeouts to consider the destination potentially failed */ - uint16_t pf_threshold; - /* error stats on the destination */ - uint16_t error_count; - /* UDP port number in case of UDP tunneling */ - uint16_t port; - - uint8_t fast_retran_loss_recovery; - uint8_t will_exit_fast_recovery; - /* Flags that probably can be combined into dest_state */ - uint8_t fast_retran_ip; /* fast retransmit in progress */ - uint8_t hb_responded; - uint8_t saw_newack; /* CMT's SFR algorithm flag */ - uint8_t src_addr_selected; /* if we split we move */ - uint8_t indx_of_eligible_next_to_use; - uint8_t addr_is_local; /* its a local address (if known) could move - * in split */ - - /* - * CMT variables (iyengar@cis.udel.edu) - */ - uint8_t find_pseudo_cumack; /* CMT CUC algorithm. Flag used to - * find a new pseudocumack. This flag - * is set after a new pseudo-cumack - * has been received and indicates - * that the sender should find the - * next pseudo-cumack expected for - * this destination */ - uint8_t find_rtx_pseudo_cumack; /* CMT CUCv2 algorithm. Flag used to - * find a new rtx-pseudocumack. This - * flag is set after a new - * rtx-pseudo-cumack has been received - * and indicates that the sender - * should find the next - * rtx-pseudo-cumack expected for this - * destination */ - uint8_t new_pseudo_cumack; /* CMT CUC algorithm. Flag used to - * indicate if a new pseudo-cumack or - * rtx-pseudo-cumack has been received */ - uint8_t window_probe; /* Doing a window probe? */ - uint8_t RTO_measured; /* Have we done the first measure */ - uint8_t last_hs_used; /* index into the last HS table entry we used */ - uint8_t lan_type; - uint8_t rto_needed; -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint32_t flowid; - uint8_t flowtype; -#endif -}; - -struct sctp_data_chunkrec { - uint32_t tsn; /* the TSN of this transmit */ - uint32_t mid; /* the message identifier of this transmit */ - uint16_t sid; /* the stream number of this guy */ - uint32_t ppid; - uint32_t context; /* from send */ - uint32_t cwnd_at_send; - /* - * part of the Highest sacked algorithm to be able to stroke counts - * on ones that are FR'd. - */ - uint32_t fast_retran_tsn; /* sending_seq at the time of FR */ - struct timeval timetodrop; /* time we drop it from queue */ - uint32_t fsn; /* Fragment Sequence Number */ - uint8_t doing_fast_retransmit; - uint8_t rcv_flags; /* flags pulled from data chunk on inbound for - * outbound holds sending flags for PR-SCTP. - */ - uint8_t state_flags; - uint8_t chunk_was_revoked; - uint8_t fwd_tsn_cnt; -}; - -TAILQ_HEAD(sctpchunk_listhead, sctp_tmit_chunk); - -/* The lower byte is used to enumerate PR_SCTP policies */ -#define CHUNK_FLAGS_PR_SCTP_TTL SCTP_PR_SCTP_TTL -#define CHUNK_FLAGS_PR_SCTP_BUF SCTP_PR_SCTP_BUF -#define CHUNK_FLAGS_PR_SCTP_RTX SCTP_PR_SCTP_RTX - -/* The upper byte is used as a bit mask */ -#define CHUNK_FLAGS_FRAGMENT_OK 0x0100 - -struct chk_id { - uint8_t id; - uint8_t can_take_data; -}; - -struct sctp_tmit_chunk { - union { - struct sctp_data_chunkrec data; - struct chk_id chunk_id; - } rec; - struct sctp_association *asoc; /* bp to asoc this belongs to */ - struct timeval sent_rcv_time; /* filled in if RTT being calculated */ - struct mbuf *data; /* pointer to mbuf chain of data */ - struct mbuf *last_mbuf; /* pointer to last mbuf in chain */ - struct sctp_nets *whoTo; - TAILQ_ENTRY(sctp_tmit_chunk) sctp_next; /* next link */ - int32_t sent; /* the send status */ - uint16_t snd_count; /* number of times I sent */ - uint16_t flags; /* flags, such as FRAGMENT_OK */ - uint16_t send_size; - uint16_t book_size; - uint16_t mbcnt; - uint16_t auth_keyid; - uint8_t holds_key_ref; /* flag if auth keyid refcount is held */ - uint8_t pad_inplace; - uint8_t do_rtt; - uint8_t book_size_scale; - uint8_t no_fr_allowed; - uint8_t copy_by_ref; - uint8_t window_probe; -}; - -struct sctp_queued_to_read { /* sinfo structure Pluse more */ - uint16_t sinfo_stream; /* off the wire */ - uint16_t sinfo_flags; /* SCTP_UNORDERED from wire use SCTP_EOF for - * EOR */ - uint32_t sinfo_ppid; /* off the wire */ - uint32_t sinfo_context; /* pick this up from assoc def context? */ - uint32_t sinfo_timetolive; /* not used by kernel */ - uint32_t sinfo_tsn; /* Use this in reassembly as first TSN */ - uint32_t sinfo_cumtsn; /* Use this in reassembly as last TSN */ - sctp_assoc_t sinfo_assoc_id; /* our assoc id */ - /* Non sinfo stuff */ - uint32_t mid; /* Fragment Index */ - uint32_t length; /* length of data */ - uint32_t held_length; /* length held in sb */ - uint32_t top_fsn; /* Highest FSN in queue */ - uint32_t fsn_included; /* Highest FSN in *data portion */ - struct sctp_nets *whoFrom; /* where it came from */ - struct mbuf *data; /* front of the mbuf chain of data with - * PKT_HDR */ - struct mbuf *tail_mbuf; /* used for multi-part data */ - struct mbuf *aux_data; /* used to hold/cache control if o/s does not take it from us */ - struct sctp_tcb *stcb; /* assoc, used for window update */ - TAILQ_ENTRY(sctp_queued_to_read) next; - TAILQ_ENTRY(sctp_queued_to_read) next_instrm; - struct sctpchunk_listhead reasm; - uint16_t port_from; - uint16_t spec_flags; /* Flags to hold the notification field */ - uint8_t do_not_ref_stcb; - uint8_t end_added; - uint8_t pdapi_aborted; - uint8_t pdapi_started; - uint8_t some_taken; - uint8_t last_frag_seen; - uint8_t first_frag_seen; - uint8_t on_read_q; - uint8_t on_strm_q; -}; - -#define SCTP_ON_ORDERED 1 -#define SCTP_ON_UNORDERED 2 - -/* This data structure will be on the outbound - * stream queues. Data will be pulled off from - * the front of the mbuf data and chunk-ified - * by the output routines. We will custom - * fit every chunk we pull to the send/sent - * queue to make up the next full packet - * if we can. An entry cannot be removed - * from the stream_out queue until - * the msg_is_complete flag is set. This - * means at times data/tail_mbuf MIGHT - * be NULL.. If that occurs it happens - * for one of two reasons. Either the user - * is blocked on a send() call and has not - * awoken to copy more data down... OR - * the user is in the explict MSG_EOR mode - * and wrote some data, but has not completed - * sending. - * ss_next and scheduled are only used by the FCFS stream scheduler. - */ -struct sctp_stream_queue_pending { - struct mbuf *data; - struct mbuf *tail_mbuf; - struct timeval ts; - struct sctp_nets *net; - TAILQ_ENTRY (sctp_stream_queue_pending) next; - TAILQ_ENTRY (sctp_stream_queue_pending) ss_next; - uint32_t fsn; - uint32_t length; - uint32_t timetolive; - uint32_t ppid; - uint32_t context; - uint16_t sinfo_flags; - uint16_t sid; - uint16_t act_flags; - uint16_t auth_keyid; - uint8_t holds_key_ref; - uint8_t msg_is_complete; - uint8_t some_taken; - uint8_t sender_all_done; - uint8_t put_last_out; - uint8_t discard_rest; - uint8_t processing; - bool scheduled; -}; - -/* - * this struct contains info that is used to track inbound stream data and - * help with ordering. - */ -TAILQ_HEAD(sctpwheelunrel_listhead, sctp_stream_in); -struct sctp_stream_in { - struct sctp_readhead inqueue; - struct sctp_readhead uno_inqueue; - uint32_t last_mid_delivered; /* used for re-order */ - uint16_t sid; - uint8_t delivery_started; - uint8_t pd_api_started; -}; - -TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out); -TAILQ_HEAD(sctplist_listhead, sctp_stream_queue_pending); - -/* - * This union holds all data necessary for - * different stream schedulers. - */ -struct scheduling_data { - struct sctp_stream_out *locked_on_sending; - /* circular looking for output selection */ - struct sctp_stream_out *last_out_stream; - union { - struct sctpwheel_listhead wheel; - struct sctplist_listhead list; - } out; -}; - -/* Round-robin schedulers */ -struct ss_rr { - /* next link in wheel */ - TAILQ_ENTRY(sctp_stream_out) next_spoke; -}; - -/* Priority scheduler */ -struct ss_prio { - /* next link in wheel */ - TAILQ_ENTRY(sctp_stream_out) next_spoke; - /* priority id */ - uint16_t priority; -}; - -/* Fair Bandwidth scheduler */ -struct ss_fb { - /* next link in wheel */ - TAILQ_ENTRY(sctp_stream_out) next_spoke; - /* stores message size */ - int32_t rounds; -}; - -/* - * This union holds all parameters per stream - * necessary for different stream schedulers. - */ -struct scheduling_parameters { - union { - struct ss_rr rr; - struct ss_prio prio; - struct ss_fb fb; - } ss; - bool scheduled; -}; - -/* States for outgoing streams */ -#define SCTP_STREAM_CLOSED 0x00 -#define SCTP_STREAM_OPENING 0x01 -#define SCTP_STREAM_OPEN 0x02 -#define SCTP_STREAM_RESET_PENDING 0x03 -#define SCTP_STREAM_RESET_IN_FLIGHT 0x04 - -/* This struct is used to track the traffic on outbound streams */ -struct sctp_stream_out { - struct sctp_streamhead outqueue; - struct scheduling_parameters ss_params; - uint32_t chunks_on_queues; /* send queue and sent queue */ -#if defined(SCTP_DETAILED_STR_STATS) - uint32_t abandoned_unsent[SCTP_PR_SCTP_MAX + 1]; - uint32_t abandoned_sent[SCTP_PR_SCTP_MAX + 1]; -#else - /* Only the aggregation */ - uint32_t abandoned_unsent[1]; - uint32_t abandoned_sent[1]; -#endif - /* For associations using DATA chunks, the lower 16-bit of - * next_mid_ordered are used as the next SSN. - */ - uint32_t next_mid_ordered; - uint32_t next_mid_unordered; - uint16_t sid; - uint8_t last_msg_incomplete; - uint8_t state; -}; - -#define SCTP_MAX_STREAMS_AT_ONCE_RESET 200 - -/* used to keep track of the addresses yet to try to add/delete */ -TAILQ_HEAD(sctp_asconf_addrhead, sctp_asconf_addr); -struct sctp_asconf_addr { - TAILQ_ENTRY(sctp_asconf_addr) next; - struct sctp_asconf_addr_param ap; - struct sctp_ifa *ifa; /* save the ifa for add/del ip */ - uint8_t sent; /* has this been sent yet? */ - uint8_t special_del; /* not to be used in lookup */ -}; - -struct sctp_scoping { - uint8_t ipv4_addr_legal; - uint8_t ipv6_addr_legal; -#if defined(__Userspace__) - uint8_t conn_addr_legal; -#endif - uint8_t loopback_scope; - uint8_t ipv4_local_scope; - uint8_t local_scope; - uint8_t site_scope; -}; - -#define SCTP_TSN_LOG_SIZE 40 - -struct sctp_tsn_log { - void *stcb; - uint32_t tsn; - uint32_t seq; - uint16_t strm; - uint16_t sz; - uint16_t flgs; - uint16_t in_pos; - uint16_t in_out; - uint16_t resv; -}; - -#define SCTP_FS_SPEC_LOG_SIZE 200 -struct sctp_fs_spec_log { - uint32_t sent; - uint32_t total_flight; - uint32_t tsn; - uint16_t book; - uint8_t incr; - uint8_t decr; -}; - -/* - * JRS - Structure to hold function pointers to the functions responsible - * for congestion control. - */ - -struct sctp_cc_functions { - void (*sctp_set_initial_cc_param)(struct sctp_tcb *stcb, struct sctp_nets *net); - void (*sctp_cwnd_update_after_sack)(struct sctp_tcb *stcb, - struct sctp_association *asoc, - int accum_moved ,int reneged_all, int will_exit); - void (*sctp_cwnd_update_exit_pf)(struct sctp_tcb *stcb, struct sctp_nets *net); - void (*sctp_cwnd_update_after_fr)(struct sctp_tcb *stcb, - struct sctp_association *asoc); - void (*sctp_cwnd_update_after_timeout)(struct sctp_tcb *stcb, - struct sctp_nets *net); - void (*sctp_cwnd_update_after_ecn_echo)(struct sctp_tcb *stcb, - struct sctp_nets *net, int in_window, int num_pkt_lost); - void (*sctp_cwnd_update_after_packet_dropped)(struct sctp_tcb *stcb, - struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, - uint32_t *bottle_bw, uint32_t *on_queue); - void (*sctp_cwnd_update_after_output)(struct sctp_tcb *stcb, - struct sctp_nets *net, int burst_limit); - void (*sctp_cwnd_update_packet_transmitted)(struct sctp_tcb *stcb, - struct sctp_nets *net); - void (*sctp_cwnd_update_tsn_acknowledged)(struct sctp_nets *net, - struct sctp_tmit_chunk *); - void (*sctp_cwnd_new_transmission_begins)(struct sctp_tcb *stcb, - struct sctp_nets *net); - void (*sctp_cwnd_prepare_net_for_sack)(struct sctp_tcb *stcb, - struct sctp_nets *net); - int (*sctp_cwnd_socket_option)(struct sctp_tcb *stcb, int set, struct sctp_cc_option *); - void (*sctp_rtt_calculated)(struct sctp_tcb *, struct sctp_nets *, struct timeval *); -}; - -/* - * RS - Structure to hold function pointers to the functions responsible - * for stream scheduling. - */ -struct sctp_ss_functions { - void (*sctp_ss_init)(struct sctp_tcb *stcb, struct sctp_association *asoc); - void (*sctp_ss_clear)(struct sctp_tcb *stcb, struct sctp_association *asoc, - bool clear_values); - void (*sctp_ss_init_stream)(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq); - void (*sctp_ss_add_to_stream)(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp); - bool (*sctp_ss_is_empty)(struct sctp_tcb *stcb, struct sctp_association *asoc); - void (*sctp_ss_remove_from_stream)(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp); - struct sctp_stream_out* (*sctp_ss_select_stream)(struct sctp_tcb *stcb, - struct sctp_nets *net, struct sctp_association *asoc); - void (*sctp_ss_scheduled)(struct sctp_tcb *stcb, struct sctp_nets *net, - struct sctp_association *asoc, struct sctp_stream_out *strq, int moved_how_much); - void (*sctp_ss_packet_done)(struct sctp_tcb *stcb, struct sctp_nets *net, - struct sctp_association *asoc); - int (*sctp_ss_get_value)(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, uint16_t *value); - int (*sctp_ss_set_value)(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, uint16_t value); - bool (*sctp_ss_is_user_msgs_incomplete)(struct sctp_tcb *stcb, struct sctp_association *asoc); -}; - -/* used to save ASCONF chunks for retransmission */ -TAILQ_HEAD(sctp_asconf_head, sctp_asconf); -struct sctp_asconf { - TAILQ_ENTRY(sctp_asconf) next; - uint32_t serial_number; - uint16_t snd_count; - struct mbuf *data; - uint16_t len; -}; - -/* used to save ASCONF-ACK chunks for retransmission */ -TAILQ_HEAD(sctp_asconf_ackhead, sctp_asconf_ack); -struct sctp_asconf_ack { - TAILQ_ENTRY(sctp_asconf_ack) next; - uint32_t serial_number; - struct sctp_nets *last_sent_to; - struct mbuf *data; - uint16_t len; -}; - -/* - * Here we have information about each individual association that we track. - * We probably in production would be more dynamic. But for ease of - * implementation we will have a fixed array that we hunt for in a linear - * fashion. - */ -struct sctp_association { - /* association state */ - int state; - - /* queue of pending addrs to add/delete */ - struct sctp_asconf_addrhead asconf_queue; - - struct timeval time_entered; /* time we entered state */ - struct timeval time_last_rcvd; - struct timeval time_last_sent; - struct timeval time_last_sat_advance; - struct sctp_nonpad_sndrcvinfo def_send; - - /* timers and such */ - struct sctp_timer dack_timer; /* Delayed ack timer */ - struct sctp_timer asconf_timer; /* asconf */ - struct sctp_timer strreset_timer; /* stream reset */ - struct sctp_timer shut_guard_timer; /* shutdown guard */ - struct sctp_timer autoclose_timer; /* automatic close timer */ - struct sctp_timer delete_prim_timer; /* deleting primary dst */ - - /* list of restricted local addresses */ - struct sctpladdr sctp_restricted_addrs; - - /* last local address pending deletion (waiting for an address add) */ - struct sctp_ifa *asconf_addr_del_pending; - /* Deleted primary destination (used to stop timer) */ - struct sctp_nets *deleted_primary; - - struct sctpnetlisthead nets; /* remote address list */ - - /* Free chunk list */ - struct sctpchunk_listhead free_chunks; - - /* Control chunk queue */ - struct sctpchunk_listhead control_send_queue; - - /* ASCONF chunk queue */ - struct sctpchunk_listhead asconf_send_queue; - - /* - * Once a TSN hits the wire it is moved to the sent_queue. We - * maintain two counts here (don't know if any but retran_cnt is - * needed). The idea is that the sent_queue_retran_cnt reflects how - * many chunks have been marked for retranmission by either T3-rxt - * or FR. - */ - struct sctpchunk_listhead sent_queue; - struct sctpchunk_listhead send_queue; - - /* Scheduling queues */ - struct scheduling_data ss_data; - - /* If an iterator is looking at me, this is it */ - struct sctp_iterator *stcb_starting_point_for_iterator; - - /* ASCONF save the last ASCONF-ACK so we can resend it if necessary */ - struct sctp_asconf_ackhead asconf_ack_sent; - - /* - * pointer to last stream reset queued to control queue by us with - * requests. - */ - struct sctp_tmit_chunk *str_reset; - /* - * if Source Address Selection happening, this will rotate through - * the link list. - */ - struct sctp_laddr *last_used_address; - - /* stream arrays */ - struct sctp_stream_in *strmin; - struct sctp_stream_out *strmout; - uint8_t *mapping_array; - /* primary destination to use */ - struct sctp_nets *primary_destination; - struct sctp_nets *alternate; /* If primary is down or PF */ - /* For CMT */ - struct sctp_nets *last_net_cmt_send_started; - /* last place I got a data chunk from */ - struct sctp_nets *last_data_chunk_from; - /* last place I got a control from */ - struct sctp_nets *last_control_chunk_from; - - /* - * wait to the point the cum-ack passes req->send_reset_at_tsn for - * any req on the list. - */ - struct sctp_resethead resetHead; - - /* queue of chunks waiting to be sent into the local stack */ - struct sctp_readhead pending_reply_queue; - - /* JRS - the congestion control functions are in this struct */ - struct sctp_cc_functions cc_functions; - /* JRS - value to store the currently loaded congestion control module */ - uint32_t congestion_control_module; - /* RS - the stream scheduling functions are in this struct */ - struct sctp_ss_functions ss_functions; - /* RS - value to store the currently loaded stream scheduling module */ - uint32_t stream_scheduling_module; - - uint32_t vrf_id; - uint32_t cookie_preserve_req; - /* ASCONF next seq I am sending out, inits at init-tsn */ - uint32_t asconf_seq_out; - uint32_t asconf_seq_out_acked; - /* ASCONF last received ASCONF from peer, starts at peer's TSN-1 */ - uint32_t asconf_seq_in; - - /* next seq I am sending in str reset messages */ - uint32_t str_reset_seq_out; - /* next seq I am expecting in str reset messages */ - uint32_t str_reset_seq_in; - - /* various verification tag information */ - uint32_t my_vtag; /* The tag to be used. if assoc is re-initited - * by remote end, and I have unlocked this - * will be regenerated to a new random value. */ - uint32_t peer_vtag; /* The peers last tag */ - - uint32_t my_vtag_nonce; - uint32_t peer_vtag_nonce; - - uint32_t assoc_id; - - /* This is the SCTP fragmentation threshold */ - uint32_t smallest_mtu; - - /* - * Special hook for Fast retransmit, allows us to track the highest - * TSN that is NEW in this SACK if gap ack blocks are present. - */ - uint32_t this_sack_highest_gap; - - /* - * The highest consecutive TSN that has been acked by peer on my - * sends - */ - uint32_t last_acked_seq; - - /* The next TSN that I will use in sending. */ - uint32_t sending_seq; - - /* Original seq number I used ??questionable to keep?? */ - uint32_t init_seq_number; - - /* The Advanced Peer Ack Point, as required by the PR-SCTP */ - /* (A1 in Section 4.2) */ - uint32_t advanced_peer_ack_point; - - /* - * The highest consequetive TSN at the bottom of the mapping array - * (for his sends). - */ - uint32_t cumulative_tsn; - /* - * Used to track the mapping array and its offset bits. This MAY be - * lower then cumulative_tsn. - */ - uint32_t mapping_array_base_tsn; - /* - * used to track highest TSN we have received and is listed in the - * mapping array. - */ - uint32_t highest_tsn_inside_map; - - /* EY - new NR variables used for nr_sack based on mapping_array*/ - uint8_t *nr_mapping_array; - uint32_t highest_tsn_inside_nr_map; - - uint32_t fast_recovery_tsn; - uint32_t sat_t3_recovery_tsn; - uint32_t tsn_last_delivered; - /* - * For the pd-api we should re-write this a bit more efficient. We - * could have multiple sctp_queued_to_read's that we are building at - * once. Now we only do this when we get ready to deliver to the - * socket buffer. Note that we depend on the fact that the struct is - * "stuck" on the read queue until we finish all the pd-api. - */ - struct sctp_queued_to_read *control_pdapi; - - uint32_t tsn_of_pdapi_last_delivered; - uint32_t pdapi_ppid; - uint32_t context; - uint32_t last_reset_action[SCTP_MAX_RESET_PARAMS]; - uint32_t last_sending_seq[SCTP_MAX_RESET_PARAMS]; - uint32_t last_base_tsnsent[SCTP_MAX_RESET_PARAMS]; -#ifdef SCTP_ASOCLOG_OF_TSNS - /* - * special log - This adds considerable size - * to the asoc, but provides a log that you - * can use to detect problems via kgdb. - */ - struct sctp_tsn_log in_tsnlog[SCTP_TSN_LOG_SIZE]; - struct sctp_tsn_log out_tsnlog[SCTP_TSN_LOG_SIZE]; - uint32_t cumack_log[SCTP_TSN_LOG_SIZE]; - uint32_t cumack_logsnt[SCTP_TSN_LOG_SIZE]; - uint16_t tsn_in_at; - uint16_t tsn_out_at; - uint16_t tsn_in_wrapped; - uint16_t tsn_out_wrapped; - uint16_t cumack_log_at; - uint16_t cumack_log_atsnt; -#endif /* SCTP_ASOCLOG_OF_TSNS */ -#ifdef SCTP_FS_SPEC_LOG - struct sctp_fs_spec_log fslog[SCTP_FS_SPEC_LOG_SIZE]; - uint16_t fs_index; -#endif - - /* - * window state information and smallest MTU that I use to bound - * segmentation - */ - uint32_t peers_rwnd; - uint32_t my_rwnd; - uint32_t my_last_reported_rwnd; - uint32_t sctp_frag_point; - - uint32_t total_output_queue_size; - - uint32_t sb_cc; /* shadow of sb_cc */ - uint32_t sb_send_resv; /* amount reserved on a send */ - uint32_t my_rwnd_control_len; /* shadow of sb_mbcnt used for rwnd control */ -#ifdef INET6 - uint32_t default_flowlabel; -#endif - uint32_t pr_sctp_cnt; - int ctrl_queue_cnt; /* could be removed REM - NO IT CAN'T!! RRS */ - /* - * All outbound datagrams queue into this list from the individual - * stream queue. Here they get assigned a TSN and then await - * sending. The stream seq comes when it is first put in the - * individual str queue - */ - unsigned int stream_queue_cnt; - unsigned int send_queue_cnt; - unsigned int sent_queue_cnt; - unsigned int sent_queue_cnt_removeable; - /* - * Number on sent queue that are marked for retran until this value - * is 0 we only send one packet of retran'ed data. - */ - unsigned int sent_queue_retran_cnt; - - unsigned int size_on_reasm_queue; - unsigned int cnt_on_reasm_queue; - unsigned int fwd_tsn_cnt; - /* amount of data (bytes) currently in flight (on all destinations) */ - unsigned int total_flight; - /* Total book size in flight */ - unsigned int total_flight_count; /* count of chunks used with - * book total */ - /* count of destinaton nets and list of destination nets */ - unsigned int numnets; - - /* Total error count on this association */ - unsigned int overall_error_count; - - unsigned int cnt_msg_on_sb; - - /* All stream count of chunks for delivery */ - unsigned int size_on_all_streams; - unsigned int cnt_on_all_streams; - - /* Heart Beat delay in ms */ - uint32_t heart_beat_delay; - - /* autoclose */ - uint32_t sctp_autoclose_ticks; - - /* how many preopen streams we have */ - unsigned int pre_open_streams; - - /* How many streams I support coming into me */ - unsigned int max_inbound_streams; - - /* the cookie life I award for any cookie, in seconds */ - uint32_t cookie_life; - /* time to delay acks for */ - unsigned int delayed_ack; - unsigned int old_delayed_ack; - unsigned int sack_freq; - unsigned int data_pkts_seen; - - unsigned int numduptsns; - int dup_tsns[SCTP_MAX_DUP_TSNS]; - uint32_t initial_init_rto_max; /* initial RTO for INIT's */ - uint32_t initial_rto; /* initial send RTO */ - uint32_t minrto; /* per assoc RTO-MIN */ - uint32_t maxrto; /* per assoc RTO-MAX */ - - /* authentication fields */ - sctp_auth_chklist_t *local_auth_chunks; - sctp_auth_chklist_t *peer_auth_chunks; - sctp_hmaclist_t *local_hmacs; /* local HMACs supported */ - sctp_hmaclist_t *peer_hmacs; /* peer HMACs supported */ - struct sctp_keyhead shared_keys; /* assoc's shared keys */ - sctp_authinfo_t authinfo; /* randoms, cached keys */ - /* - * refcnt to block freeing when a sender or receiver is off coping - * user data in. - */ - uint32_t refcnt; - uint32_t chunks_on_out_queue; /* total chunks floating around, - * locked by send socket buffer */ - uint32_t peers_adaptation; - uint32_t default_mtu; - uint16_t peer_hmac_id; /* peer HMAC id to send */ - - /* - * Being that we have no bag to collect stale cookies, and that we - * really would not want to anyway.. we will count them in this - * counter. We of course feed them to the pigeons right away (I have - * always thought of pigeons as flying rats). - */ - uint16_t stale_cookie_count; - - /* - * For the partial delivery API, if up, invoked this is what last - * TSN I delivered - */ - uint16_t str_of_pdapi; - uint16_t ssn_of_pdapi; - - /* counts of actual built streams. Allocation may be more however */ - /* could re-arrange to optimize space here. */ - uint16_t streamincnt; - uint16_t streamoutcnt; - uint16_t strm_realoutsize; - uint16_t strm_pending_add_size; - /* my maximum number of retrans of INIT and SEND */ - /* copied from SCTP but should be individually setable */ - uint16_t max_init_times; - uint16_t max_send_times; - - uint16_t def_net_failure; - - uint16_t def_net_pf_threshold; - - /* - * lock flag: 0 is ok to send, 1+ (duals as a retran count) is - * awaiting ACK - */ - uint16_t mapping_array_size; - - uint16_t last_strm_seq_delivered; - uint16_t last_strm_no_delivered; - - uint16_t last_revoke_count; - int16_t num_send_timers_up; - - uint16_t stream_locked_on; - uint16_t ecn_echo_cnt_onq; - - uint16_t free_chunk_cnt; - uint8_t stream_locked; - uint8_t authenticated; /* packet authenticated ok */ - /* - * This flag indicates that a SACK need to be sent. - * Initially this is 1 to send the first sACK immediately. - */ - uint8_t send_sack; - - /* max burst of new packets into the network */ - uint32_t max_burst; - /* max burst of fast retransmit packets */ - uint32_t fr_max_burst; - - uint8_t sat_network; /* RTT is in range of sat net or greater */ - uint8_t sat_network_lockout; /* lockout code */ - uint8_t burst_limit_applied; /* Burst limit in effect at last send? */ - /* flag goes on when we are doing a partial delivery api */ - uint8_t hb_random_values[4]; - uint8_t fragmented_delivery_inprogress; - uint8_t fragment_flags; - uint8_t last_flags_delivered; - uint8_t hb_ect_randombit; - uint8_t hb_random_idx; - uint8_t default_dscp; - uint8_t asconf_del_pending; /* asconf delete last addr pending */ - uint8_t trigger_reset; - /* - * This value, plus all other ack'd but above cum-ack is added - * together to cross check against the bit that we have yet to - * define (probably in the SACK). When the cum-ack is updated, this - * sum is updated as well. - */ - - /* Flags whether an extension is supported or not */ - uint8_t ecn_supported; - uint8_t prsctp_supported; - uint8_t auth_supported; - uint8_t asconf_supported; - uint8_t reconfig_supported; - uint8_t nrsack_supported; - uint8_t pktdrop_supported; - uint8_t idata_supported; - - /* Zero checksum supported information */ - uint8_t rcv_edmid; - uint8_t snd_edmid; - - /* Did the peer make the stream config (add out) request */ - uint8_t peer_req_out; - - uint8_t local_strreset_support; - uint8_t peer_supports_nat; - - struct sctp_scoping scope; - /* flags to handle send alternate net tracking */ - uint8_t used_alt_asconfack; - uint8_t fast_retran_loss_recovery; - uint8_t sat_t3_loss_recovery; - uint8_t dropped_special_cnt; - uint8_t seen_a_sack_this_pkt; - uint8_t stream_reset_outstanding; - uint8_t stream_reset_out_is_outstanding; - uint8_t delayed_connection; - uint8_t ifp_had_enobuf; - uint8_t saw_sack_with_frags; - uint8_t saw_sack_with_nr_frags; - uint8_t in_asocid_hash; - uint8_t assoc_up_sent; - uint8_t adaptation_needed; - uint8_t adaptation_sent; - /* CMT variables */ - uint8_t cmt_dac_pkts_rcvd; - uint8_t sctp_cmt_on_off; - uint8_t iam_blocking; - uint8_t cookie_how[8]; - /* JRS 5/21/07 - CMT PF variable */ - uint8_t sctp_cmt_pf; - uint8_t use_precise_time; - uint64_t sctp_features; - uint32_t max_cwnd; - uint16_t port; /* remote UDP encapsulation port */ - /* - * The mapping array is used to track out of order sequences above - * last_acked_seq. 0 indicates packet missing 1 indicates packet - * rec'd. We slide it up every time we raise last_acked_seq and 0 - * trailing locactions out. If I get a TSN above the array - * mappingArraySz, I discard the datagram and let retransmit happen. - */ - uint32_t marked_retrans; - uint32_t timoinit; - uint32_t timodata; - uint32_t timosack; - uint32_t timoshutdown; - uint32_t timoheartbeat; - uint32_t timocookie; - uint32_t timoshutdownack; - struct timeval start_time; - struct timeval discontinuity_time; - uint64_t abandoned_unsent[SCTP_PR_SCTP_MAX + 1]; - uint64_t abandoned_sent[SCTP_PR_SCTP_MAX + 1]; -}; - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.c deleted file mode 100644 index ffbe49e0..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.c +++ /dev/null @@ -1,1669 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#include -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -#include -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -FEATURE(sctp, "Stream Control Transmission Protocol"); -#endif - -/* - * sysctl tunable variables - */ - -void -sctp_init_sysctls(void) -{ - SCTP_BASE_SYSCTL(sctp_sendspace) = SCTPCTL_MAXDGRAM_DEFAULT; - SCTP_BASE_SYSCTL(sctp_recvspace) = SCTPCTL_RECVSPACE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_auto_asconf) = SCTPCTL_AUTOASCONF_DEFAULT; - SCTP_BASE_SYSCTL(sctp_multiple_asconfs) = SCTPCTL_MULTIPLEASCONFS_DEFAULT; - SCTP_BASE_SYSCTL(sctp_ecn_enable) = SCTPCTL_ECN_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_pr_enable) = SCTPCTL_PR_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_auth_enable) = SCTPCTL_AUTH_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_asconf_enable) = SCTPCTL_ASCONF_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_reconfig_enable) = SCTPCTL_RECONFIG_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_nrsack_enable) = SCTPCTL_NRSACK_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_pktdrop_enable) = SCTPCTL_PKTDROP_ENABLE_DEFAULT; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) = SCTPCTL_LOOPBACK_NOCSUM_DEFAULT; -#endif - SCTP_BASE_SYSCTL(sctp_peer_chunk_oh) = SCTPCTL_PEER_CHKOH_DEFAULT; - SCTP_BASE_SYSCTL(sctp_max_burst_default) = SCTPCTL_MAXBURST_DEFAULT; - SCTP_BASE_SYSCTL(sctp_fr_max_burst_default) = SCTPCTL_FRMAXBURST_DEFAULT; - SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = SCTPCTL_MAXCHUNKS_DEFAULT; -#if defined(__Userspace__) - if (SCTP_BASE_SYSCTL(sctp_hashtblsize) == 0) { - SCTP_BASE_SYSCTL(sctp_hashtblsize) = SCTPCTL_TCBHASHSIZE_DEFAULT; - } -#else - SCTP_BASE_SYSCTL(sctp_hashtblsize) = SCTPCTL_TCBHASHSIZE_DEFAULT; -#endif -#if defined(__Userspace__) - if (SCTP_BASE_SYSCTL(sctp_pcbtblsize) == 0) { - SCTP_BASE_SYSCTL(sctp_pcbtblsize) = SCTPCTL_PCBHASHSIZE_DEFAULT; - } -#else - SCTP_BASE_SYSCTL(sctp_pcbtblsize) = SCTPCTL_PCBHASHSIZE_DEFAULT; -#endif - SCTP_BASE_SYSCTL(sctp_min_split_point) = SCTPCTL_MIN_SPLIT_POINT_DEFAULT; -#if defined(__Userspace__) - if (SCTP_BASE_SYSCTL(sctp_chunkscale) == 0) { - SCTP_BASE_SYSCTL(sctp_chunkscale) = SCTPCTL_CHUNKSCALE_DEFAULT; - } -#else - SCTP_BASE_SYSCTL(sctp_chunkscale) = SCTPCTL_CHUNKSCALE_DEFAULT; -#endif - SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default) = SCTPCTL_DELAYED_SACK_TIME_DEFAULT; - SCTP_BASE_SYSCTL(sctp_sack_freq_default) = SCTPCTL_SACK_FREQ_DEFAULT; - SCTP_BASE_SYSCTL(sctp_system_free_resc_limit) = SCTPCTL_SYS_RESOURCE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_asoc_free_resc_limit) = SCTPCTL_ASOC_RESOURCE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default) = SCTPCTL_HEARTBEAT_INTERVAL_DEFAULT; - SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default) = SCTPCTL_PMTU_RAISE_TIME_DEFAULT; - SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default) = SCTPCTL_SHUTDOWN_GUARD_TIME_DEFAULT; - SCTP_BASE_SYSCTL(sctp_secret_lifetime_default) = SCTPCTL_SECRET_LIFETIME_DEFAULT; - SCTP_BASE_SYSCTL(sctp_rto_max_default) = SCTPCTL_RTO_MAX_DEFAULT; - SCTP_BASE_SYSCTL(sctp_rto_min_default) = SCTPCTL_RTO_MIN_DEFAULT; - SCTP_BASE_SYSCTL(sctp_rto_initial_default) = SCTPCTL_RTO_INITIAL_DEFAULT; - SCTP_BASE_SYSCTL(sctp_init_rto_max_default) = SCTPCTL_INIT_RTO_MAX_DEFAULT; - SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default) = SCTPCTL_VALID_COOKIE_LIFE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_init_rtx_max_default) = SCTPCTL_INIT_RTX_MAX_DEFAULT; - SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default) = SCTPCTL_ASSOC_RTX_MAX_DEFAULT; - SCTP_BASE_SYSCTL(sctp_path_rtx_max_default) = SCTPCTL_PATH_RTX_MAX_DEFAULT; - SCTP_BASE_SYSCTL(sctp_path_pf_threshold) = SCTPCTL_PATH_PF_THRESHOLD_DEFAULT; - SCTP_BASE_SYSCTL(sctp_add_more_threshold) = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_nr_incoming_streams_default) = SCTPCTL_INCOMING_STREAMS_DEFAULT; - SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default) = SCTPCTL_OUTGOING_STREAMS_DEFAULT; - SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT; - SCTP_BASE_SYSCTL(sctp_cmt_use_dac) = SCTPCTL_CMT_USE_DAC_DEFAULT; - SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) = SCTPCTL_CWND_MAXBURST_DEFAULT; - SCTP_BASE_SYSCTL(sctp_nat_friendly) = SCTPCTL_NAT_FRIENDLY_DEFAULT; - SCTP_BASE_SYSCTL(sctp_L2_abc_variable) = SCTPCTL_ABC_L_VAR_DEFAULT; - SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count) = SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT; - SCTP_BASE_SYSCTL(sctp_do_drain) = SCTPCTL_DO_SCTP_DRAIN_DEFAULT; - SCTP_BASE_SYSCTL(sctp_hb_maxburst) = SCTPCTL_HB_MAX_BURST_DEFAULT; - SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit) = SCTPCTL_ABORT_AT_LIMIT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_min_residual) = SCTPCTL_MIN_RESIDUAL_DEFAULT; - SCTP_BASE_SYSCTL(sctp_max_retran_chunk) = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT; - SCTP_BASE_SYSCTL(sctp_logging_level) = SCTPCTL_LOGGING_LEVEL_DEFAULT; - SCTP_BASE_SYSCTL(sctp_default_cc_module) = SCTPCTL_DEFAULT_CC_MODULE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_default_ss_module) = SCTPCTL_DEFAULT_SS_MODULE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_default_frag_interleave) = SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_mobility_base) = SCTPCTL_MOBILITY_BASE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff) = SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT; - SCTP_BASE_SYSCTL(sctp_vtag_time_wait) = SCTPCTL_TIME_WAIT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_buffer_splitting) = SCTPCTL_BUFFER_SPLITTING_DEFAULT; - SCTP_BASE_SYSCTL(sctp_initial_cwnd) = SCTPCTL_INITIAL_CWND_DEFAULT; - SCTP_BASE_SYSCTL(sctp_rttvar_bw) = SCTPCTL_RTTVAR_BW_DEFAULT; - SCTP_BASE_SYSCTL(sctp_rttvar_rtt) = SCTPCTL_RTTVAR_RTT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_rttvar_eqret) = SCTPCTL_RTTVAR_EQRET_DEFAULT; - SCTP_BASE_SYSCTL(sctp_steady_step) = SCTPCTL_RTTVAR_STEADYS_DEFAULT; - SCTP_BASE_SYSCTL(sctp_use_dccc_ecn) = SCTPCTL_RTTVAR_DCCCECN_DEFAULT; - SCTP_BASE_SYSCTL(sctp_blackhole) = SCTPCTL_BLACKHOLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_sendall_limit) = SCTPCTL_SENDALL_LIMIT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_diag_info_code) = SCTPCTL_DIAG_INFO_CODE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum) = SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT; -#if defined(SCTP_LOCAL_TRACE_BUF) -#if defined(_WIN32) && !defined(__Userspace__) - /* On Windows, the resource for global variables is limited. */ - MALLOC(SCTP_BASE_SYSCTL(sctp_log), struct sctp_log *, sizeof(struct sctp_log), M_SYSCTL, M_ZERO); -#else - memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); -#endif -#endif - SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = SCTPCTL_UDP_TUNNELING_PORT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) = SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly) = SCTPCTL_NAT_FRIENDLY_INITS_DEFAULT; -#if defined(SCTP_DEBUG) - SCTP_BASE_SYSCTL(sctp_debug_on) = SCTPCTL_DEBUG_DEFAULT; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_BASE_SYSCTL(sctp_ignore_vmware_interfaces) = SCTPCTL_IGNORE_VMWARE_INTERFACES_DEFAULT; - SCTP_BASE_SYSCTL(sctp_main_timer) = SCTPCTL_MAIN_TIMER_DEFAULT; - SCTP_BASE_SYSCTL(sctp_addr_watchdog_limit) = SCTPCTL_ADDR_WATCHDOG_LIMIT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_vtag_watchdog_limit) = SCTPCTL_VTAG_WATCHDOG_LIMIT_DEFAULT; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_BASE_SYSCTL(sctp_output_unlocked) = SCTPCTL_OUTPUT_UNLOCKED_DEFAULT; -#endif -} -#if defined(_WIN32) && !defined(__Userspace__) - -void -sctp_finish_sysctls() -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - if (SCTP_BASE_SYSCTL(sctp_log) != NULL) { - FREE(SCTP_BASE_SYSCTL(sctp_log), M_SYSCTL); - SCTP_BASE_SYSCTL(sctp_log) = NULL; - } -#endif -} -#endif - -#if !defined(__Userspace__) -/* It returns an upper limit. No filtering is done here */ -static unsigned int -sctp_sysctl_number_of_addresses(struct sctp_inpcb *inp) -{ - unsigned int cnt; - struct sctp_vrf *vrf; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - struct sctp_laddr *laddr; - - cnt = 0; - /* neither Mac OS X nor FreeBSD support multiple routing functions */ - if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) { - return (0); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: -#endif -#ifdef INET6 - case AF_INET6: -#endif - cnt++; - break; - default: - break; - } - } - } - } else { - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - switch (laddr->ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: -#endif -#ifdef INET6 - case AF_INET6: -#endif - cnt++; - break; - default: - break; - } - } - } - return (cnt); -} - -static int -sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sysctl_req *req) -{ - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - int loopback_scope; -#ifdef INET - int ipv4_local_scope; - int ipv4_addr_legal; -#endif -#ifdef INET6 - int local_scope, site_scope; - int ipv6_addr_legal; -#endif -#if defined(__Userspace__) - int conn_addr_legal; -#endif - struct sctp_vrf *vrf; - struct xsctp_laddr xladdr; - struct sctp_laddr *laddr; - int error; - - /* Turn on all the appropriate scope */ - if (stcb != NULL) { - /* use association specific values */ - loopback_scope = stcb->asoc.scope.loopback_scope; -#ifdef INET - ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; - ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; -#endif -#ifdef INET6 - local_scope = stcb->asoc.scope.local_scope; - site_scope = stcb->asoc.scope.site_scope; - ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; -#endif -#if defined(__Userspace__) - conn_addr_legal = stcb->asoc.scope.conn_addr_legal; -#endif - } else { - /* Use generic values for endpoints. */ - loopback_scope = 1; -#ifdef INET - ipv4_local_scope = 1; -#endif -#ifdef INET6 - local_scope = 1; - site_scope = 1; -#endif - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { -#ifdef INET6 - ipv6_addr_legal = 1; -#endif -#ifdef INET - if (SCTP_IPV6_V6ONLY(inp)) { - ipv4_addr_legal = 0; - } else { - ipv4_addr_legal = 1; - } -#endif -#if defined(__Userspace__) - conn_addr_legal = 0; -#endif - } else { -#ifdef INET6 - ipv6_addr_legal = 0; -#endif -#if defined(__Userspace__) - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - conn_addr_legal = 1; -#ifdef INET - ipv4_addr_legal = 0; -#endif - } else { - conn_addr_legal = 0; -#ifdef INET - ipv4_addr_legal = 1; -#endif - } -#else -#ifdef INET - ipv4_addr_legal = 1; -#endif -#endif - } - } - - /* Neither Mac OS X nor FreeBSD support multiple routing functions. */ - if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) { - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - return (ENOENT); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if ((loopback_scope == 0) && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* Skip loopback if loopback_scope not set. */ - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (stcb != NULL) { - /* - * Ignore if blacklisted at - * association level. - */ - if (sctp_is_addr_restricted(stcb, sctp_ifa)) { - continue; - } - } - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (ipv4_addr_legal) { - struct sockaddr_in *sin; - - sin = &sctp_ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if ((ipv4_local_scope == 0) && (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { - continue; - } - } else { - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (ipv6_addr_legal) { - struct sockaddr_in6 *sin6; - - sin6 = &sctp_ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (local_scope == 0) { - continue; - } - } - if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - continue; - } - } else { - continue; - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (!conn_addr_legal) { - continue; - } - break; -#endif - default: - continue; - } - memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); - memcpy((void *)&xladdr.address, (const void *)&sctp_ifa->address, sizeof(union sctp_sockstore)); - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error != 0) { - return (error); - } else { - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - } - } - } - } else { - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - /* ignore if blacklisted at association level */ - if (stcb != NULL && sctp_is_addr_restricted(stcb, laddr->ifa)) - continue; - memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); - memcpy((void *)&xladdr.address, (const void *)&laddr->ifa->address, sizeof(union sctp_sockstore)); - xladdr.start_time.tv_sec = (uint32_t)laddr->start_time.tv_sec; - xladdr.start_time.tv_usec = (uint32_t)laddr->start_time.tv_usec; - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error != 0) { - return (error); - } else { - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - } - } - } - memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); - xladdr.last = 1; - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - - if (error != 0) { - return (error); - } else { - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - return (0); - } -} - -/* - * sysctl functions - */ -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_assoclist SYSCTL_HANDLER_ARGS -{ -#pragma unused(oidp, arg1, arg2) -#else -static int -sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS) -{ -#endif - unsigned int number_of_endpoints; - unsigned int number_of_local_addresses; - unsigned int number_of_associations; - unsigned int number_of_remote_addresses; - unsigned int n; - int error; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct xsctp_inpcb xinpcb; - struct xsctp_tcb xstcb; - struct xsctp_raddr xraddr; - struct socket *so; - - number_of_endpoints = 0; - number_of_local_addresses = 0; - number_of_associations = 0; - number_of_remote_addresses = 0; - - SCTP_INP_INFO_RLOCK(); -#if defined(__APPLE__) && !defined(__Userspace__) - if (req->oldptr == USER_ADDR_NULL) { -#else - if (req->oldptr == NULL) { -#endif - LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) { - SCTP_INP_RLOCK(inp); - number_of_endpoints++; - number_of_local_addresses += sctp_sysctl_number_of_addresses(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - number_of_associations++; - number_of_local_addresses += sctp_sysctl_number_of_addresses(inp); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - number_of_remote_addresses++; - } - } - SCTP_INP_RUNLOCK(inp); - } - SCTP_INP_INFO_RUNLOCK(); - n = (number_of_endpoints + 1) * sizeof(struct xsctp_inpcb) + - (number_of_local_addresses + number_of_endpoints + number_of_associations) * sizeof(struct xsctp_laddr) + - (number_of_associations + number_of_endpoints) * sizeof(struct xsctp_tcb) + - (number_of_remote_addresses + number_of_associations) * sizeof(struct xsctp_raddr); - - /* request some more memory than needed */ -#if !(defined(_WIN32) && !defined(__Userspace__)) - req->oldidx = (n + n / 8); -#else - req->dataidx = (n + n / 8); -#endif - return (0); - } -#if defined(__APPLE__) && !defined(__Userspace__) - if (req->newptr != USER_ADDR_NULL) { -#else - if (req->newptr != NULL) { -#endif - SCTP_INP_INFO_RUNLOCK(); - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_SYSCTL, EPERM); - return (EPERM); - } - memset(&xinpcb, 0, sizeof(xinpcb)); - memset(&xstcb, 0, sizeof(xstcb)); - memset(&xraddr, 0, sizeof(xraddr)); - LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) { - SCTP_INP_RLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - /* if its allgone it is being freed - skip it */ - goto skip; - } - xinpcb.last = 0; - xinpcb.local_port = ntohs(inp->sctp_lport); - xinpcb.flags = inp->sctp_flags; - xinpcb.features = inp->sctp_features; - xinpcb.total_sends = inp->total_sends; - xinpcb.total_recvs = inp->total_recvs; - xinpcb.total_nospaces = inp->total_nospaces; - xinpcb.fragmentation_point = inp->sctp_frag_point; -#if defined(__FreeBSD__) && !defined(__Userspace__) - xinpcb.socket = (uintptr_t)inp->sctp_socket; -#else - xinpcb.socket = inp->sctp_socket; -#endif - so = inp->sctp_socket; - if ((so == NULL) || - (!SCTP_IS_LISTENING(inp)) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { - xinpcb.qlen = 0; - xinpcb.maxqlen = 0; - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - xinpcb.qlen = so->sol_qlen; - xinpcb.qlen_old = so->sol_qlen > USHRT_MAX ? - USHRT_MAX : (uint16_t) so->sol_qlen; - xinpcb.maxqlen = so->sol_qlimit; - xinpcb.maxqlen_old = so->sol_qlimit > USHRT_MAX ? - USHRT_MAX : (uint16_t) so->sol_qlimit; -#else - xinpcb.qlen = so->so_qlen; - xinpcb.maxqlen = so->so_qlimit; -#endif - } - SCTP_INP_INCR_REF(inp); - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb)); - if (error) { - SCTP_INP_DECR_REF(inp); - return (error); - } - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - error = sctp_sysctl_copy_out_local_addresses(inp, NULL, req); - if (error) { - SCTP_INP_DECR_REF(inp); - return (error); - } - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - xstcb.last = 0; - xstcb.local_port = ntohs(inp->sctp_lport); - xstcb.remote_port = ntohs(stcb->rport); - if (stcb->asoc.primary_destination != NULL) - xstcb.primary_addr = stcb->asoc.primary_destination->ro._l_addr; - xstcb.heartbeat_interval = stcb->asoc.heart_beat_delay; - xstcb.state = (uint32_t)sctp_map_assoc_state(stcb->asoc.state); - xstcb.assoc_id = sctp_get_associd(stcb); - xstcb.peers_rwnd = stcb->asoc.peers_rwnd; - xstcb.in_streams = stcb->asoc.streamincnt; - xstcb.out_streams = stcb->asoc.streamoutcnt; - xstcb.max_nr_retrans = stcb->asoc.overall_error_count; - xstcb.primary_process = 0; /* not really supported yet */ - xstcb.T1_expireries = stcb->asoc.timoinit + stcb->asoc.timocookie; - xstcb.T2_expireries = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack; - xstcb.retransmitted_tsns = stcb->asoc.marked_retrans; - xstcb.start_time.tv_sec = (uint32_t)stcb->asoc.start_time.tv_sec; - xstcb.start_time.tv_usec = (uint32_t)stcb->asoc.start_time.tv_usec; - xstcb.discontinuity_time.tv_sec = (uint32_t)stcb->asoc.discontinuity_time.tv_sec; - xstcb.discontinuity_time.tv_usec = (uint32_t)stcb->asoc.discontinuity_time.tv_usec; - xstcb.total_sends = stcb->total_sends; - xstcb.total_recvs = stcb->total_recvs; - xstcb.local_tag = stcb->asoc.my_vtag; - xstcb.remote_tag = stcb->asoc.peer_vtag; - xstcb.initial_tsn = stcb->asoc.init_seq_number; - xstcb.highest_tsn = stcb->asoc.sending_seq - 1; - xstcb.cumulative_tsn = stcb->asoc.last_acked_seq; - xstcb.cumulative_tsn_ack = stcb->asoc.cumulative_tsn; - xstcb.mtu = stcb->asoc.smallest_mtu; - xstcb.refcnt = stcb->asoc.refcnt; - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb)); - if (error) { - SCTP_INP_DECR_REF(inp); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return (error); - } - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - error = sctp_sysctl_copy_out_local_addresses(inp, stcb, req); - if (error) { - SCTP_INP_DECR_REF(inp); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return (error); - } - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - xraddr.last = 0; - xraddr.address = net->ro._l_addr; - xraddr.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE); - xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0); - xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 0); - xraddr.potentially_failed = ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF); - xraddr.rto = net->RTO; - xraddr.max_path_rtx = net->failure_threshold; - xraddr.rtx = net->marked_retrans; - xraddr.error_counter = net->error_count; - xraddr.cwnd = net->cwnd; - xraddr.flight_size = net->flight_size; - xraddr.mtu = net->mtu; - xraddr.rtt = net->rtt / 1000; - xraddr.heartbeat_interval = net->heart_beat_delay; - xraddr.ssthresh = net->ssthresh; - xraddr.encaps_port = net->port; - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { - xraddr.state = SCTP_UNCONFIRMED; - } else if (net->dest_state & SCTP_ADDR_REACHABLE) { - xraddr.state = SCTP_ACTIVE; - } else { - xraddr.state = SCTP_INACTIVE; - } - xraddr.start_time.tv_sec = (uint32_t)net->start_time.tv_sec; - xraddr.start_time.tv_usec = (uint32_t)net->start_time.tv_usec; - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr)); - if (error) { - SCTP_INP_DECR_REF(inp); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return (error); - } - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - } - atomic_subtract_int(&stcb->asoc.refcnt, 1); - memset((void *)&xraddr, 0, sizeof(struct xsctp_raddr)); - xraddr.last = 1; - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr)); - if (error) { - SCTP_INP_DECR_REF(inp); - return (error); - } - SCTP_INP_INFO_RLOCK(); - SCTP_INP_RLOCK(inp); - } - SCTP_INP_DECR_REF(inp); - SCTP_INP_RUNLOCK(inp); - SCTP_INP_INFO_RUNLOCK(); - memset((void *)&xstcb, 0, sizeof(struct xsctp_tcb)); - xstcb.last = 1; - error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb)); - if (error) { - return (error); - } -skip: - SCTP_INP_INFO_RLOCK(); - } - SCTP_INP_INFO_RUNLOCK(); - - memset((void *)&xinpcb, 0, sizeof(struct xsctp_inpcb)); - xinpcb.last = 1; - error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb)); - return (error); -} - -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_udp_tunneling SYSCTL_HANDLER_ARGS -{ -#pragma unused(arg1, arg2) -#else -static int -sctp_sysctl_handle_udp_tunneling(SYSCTL_HANDLER_ARGS) -{ -#endif - int error; - uint32_t old, new; - - SCTP_INP_INFO_RLOCK(); - old = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); - SCTP_INP_INFO_RUNLOCK(); - new = old; - error = sysctl_handle_int(oidp, &new, 0, req); - if ((error == 0) && -#if defined(__APPLE__) && !defined(__Userspace__) - (req->newptr != USER_ADDR_NULL)) { -#else - (req->newptr != NULL)) { -#endif -#if defined(_WIN32) && !defined(__Userspace__) - SCTP_INP_INFO_WLOCK(); - sctp_over_udp_restart(); - SCTP_INP_INFO_WUNLOCK(); -#else -#if (SCTPCTL_UDP_TUNNELING_PORT_MIN == 0) - if (new > SCTPCTL_UDP_TUNNELING_PORT_MAX) { -#else - if ((new < SCTPCTL_UDP_TUNNELING_PORT_MIN) || - (new > SCTPCTL_UDP_TUNNELING_PORT_MAX)) { -#endif - error = EINVAL; - } else { - SCTP_INP_INFO_WLOCK(); - SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = new; - if (old != 0) { - sctp_over_udp_stop(); - } - if (new != 0) { - error = sctp_over_udp_start(); - } - SCTP_INP_INFO_WUNLOCK(); - } -#endif - } - return (error); -} -#if defined(__APPLE__) && !defined(__Userspace__) - -int sctp_is_vmware_interface(struct ifnet *); - -static int -sctp_sysctl_handle_vmware_interfaces SYSCTL_HANDLER_ARGS -{ -#pragma unused(arg1, arg2) - int error; - uint32_t old, new; - - old = SCTP_BASE_SYSCTL(sctp_ignore_vmware_interfaces); - new = old; - error = sysctl_handle_int(oidp, &new, 0, req); - if ((error == 0) && (req->newptr != USER_ADDR_NULL)) { - if ((new < SCTPCTL_IGNORE_VMWARE_INTERFACES_MIN) || - (new > SCTPCTL_IGNORE_VMWARE_INTERFACES_MAX)) { - error = EINVAL; - } else { - if ((old == 1) && (new == 0)) { - sctp_add_or_del_interfaces(sctp_is_vmware_interface, 1); - } - if ((old == 0) && (new == 1)) { - sctp_add_or_del_interfaces(sctp_is_vmware_interface, 0); - } - if (old != new) { - SCTP_BASE_SYSCTL(sctp_ignore_vmware_interfaces) = new; - } - } - } - return (error); -} -#endif - -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_auth SYSCTL_HANDLER_ARGS -{ -#pragma unused(arg1, arg2) -#else -static int -sctp_sysctl_handle_auth(SYSCTL_HANDLER_ARGS) -{ -#endif - int error; - uint32_t new; - - new = SCTP_BASE_SYSCTL(sctp_auth_enable); - error = sysctl_handle_int(oidp, &new, 0, req); - if ((error == 0) && -#if defined(__APPLE__) && !defined(__Userspace__) - (req->newptr != USER_ADDR_NULL)) { -#else - (req->newptr != NULL)) { -#endif -#if (SCTPCTL_AUTH_ENABLE_MIN == 0) - if ((new > SCTPCTL_AUTH_ENABLE_MAX) || - ((new == 0) && (SCTP_BASE_SYSCTL(sctp_asconf_enable) == 1))) { -#else - if ((new < SCTPCTL_AUTH_ENABLE_MIN) || - (new > SCTPCTL_AUTH_ENABLE_MAX) || - ((new == 0) && (SCTP_BASE_SYSCTL(sctp_asconf_enable) == 1))) { -#endif - error = EINVAL; - } else { - SCTP_BASE_SYSCTL(sctp_auth_enable) = new; - } - } - return (error); -} - -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_asconf SYSCTL_HANDLER_ARGS -{ -#pragma unused(arg1, arg2) -#else -static int -sctp_sysctl_handle_asconf(SYSCTL_HANDLER_ARGS) -{ -#endif - int error; - uint32_t new; - - new = SCTP_BASE_SYSCTL(sctp_asconf_enable); - error = sysctl_handle_int(oidp, &new, 0, req); - if ((error == 0) && -#if defined(__APPLE__) && !defined(__Userspace__) - (req->newptr != USER_ADDR_NULL)) { -#else - (req->newptr != NULL)) { -#endif -#if (SCTPCTL_ASCONF_ENABLE_MIN == 0) - if ((new > SCTPCTL_ASCONF_ENABLE_MAX) || - ((new == 1) && (SCTP_BASE_SYSCTL(sctp_auth_enable) == 0))) { -#else - if ((new < SCTPCTL_ASCONF_ENABLE_MIN) || - (new > SCTPCTL_ASCONF_ENABLE_MAX) || - ((new == 1) && (SCTP_BASE_SYSCTL(sctp_auth_enable) == 0))) { -#endif - error = EINVAL; - } else { - SCTP_BASE_SYSCTL(sctp_asconf_enable) = new; - } - } - return (error); -} - -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_stats SYSCTL_HANDLER_ARGS -{ -#pragma unused(oidp, arg1, arg2) -#else -static int -sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS) -{ -#endif - int error; -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) - struct sctpstat *sarry; - struct sctpstat sb; - int cpu; -#endif - struct sctpstat sb_temp; -#endif - -#if defined(__APPLE__) && !defined(__Userspace__) - if ((req->newptr != USER_ADDR_NULL) && -#else - if ((req->newptr != NULL) && -#endif - (req->newlen != sizeof(struct sctpstat))) { - return (EINVAL); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - memset(&sb_temp, 0, sizeof(struct sctpstat)); - - if (req->newptr != NULL) { - error = SYSCTL_IN(req, &sb_temp, sizeof(struct sctpstat)); - if (error != 0) { - return (error); - } - } -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) - memset(&sb, 0, sizeof(sb)); - for (cpu = 0; cpu < mp_maxid; cpu++) { - sarry = &SCTP_BASE_STATS[cpu]; - if (sarry->sctps_discontinuitytime.tv_sec > sb.sctps_discontinuitytime.tv_sec) { - sb.sctps_discontinuitytime.tv_sec = sarry->sctps_discontinuitytime.tv_sec; - sb.sctps_discontinuitytime.tv_usec = sarry->sctps_discontinuitytime.tv_usec; - } - sb.sctps_currestab += sarry->sctps_currestab; - sb.sctps_activeestab += sarry->sctps_activeestab; - sb.sctps_restartestab += sarry->sctps_restartestab; - sb.sctps_collisionestab += sarry->sctps_collisionestab; - sb.sctps_passiveestab += sarry->sctps_passiveestab; - sb.sctps_aborted += sarry->sctps_aborted; - sb.sctps_shutdown += sarry->sctps_shutdown; - sb.sctps_outoftheblue += sarry->sctps_outoftheblue; - sb.sctps_checksumerrors += sarry->sctps_checksumerrors; - sb.sctps_outcontrolchunks += sarry->sctps_outcontrolchunks; - sb.sctps_outorderchunks += sarry->sctps_outorderchunks; - sb.sctps_outunorderchunks += sarry->sctps_outunorderchunks; - sb.sctps_incontrolchunks += sarry->sctps_incontrolchunks; - sb.sctps_inorderchunks += sarry->sctps_inorderchunks; - sb.sctps_inunorderchunks += sarry->sctps_inunorderchunks; - sb.sctps_fragusrmsgs += sarry->sctps_fragusrmsgs; - sb.sctps_reasmusrmsgs += sarry->sctps_reasmusrmsgs; - sb.sctps_outpackets += sarry->sctps_outpackets; - sb.sctps_inpackets += sarry->sctps_inpackets; - sb.sctps_recvpackets += sarry->sctps_recvpackets; - sb.sctps_recvdatagrams += sarry->sctps_recvdatagrams; - sb.sctps_recvpktwithdata += sarry->sctps_recvpktwithdata; - sb.sctps_recvsacks += sarry->sctps_recvsacks; - sb.sctps_recvdata += sarry->sctps_recvdata; - sb.sctps_recvdupdata += sarry->sctps_recvdupdata; - sb.sctps_recvheartbeat += sarry->sctps_recvheartbeat; - sb.sctps_recvheartbeatack += sarry->sctps_recvheartbeatack; - sb.sctps_recvecne += sarry->sctps_recvecne; - sb.sctps_recvauth += sarry->sctps_recvauth; - sb.sctps_recvauthmissing += sarry->sctps_recvauthmissing; - sb.sctps_recvivalhmacid += sarry->sctps_recvivalhmacid; - sb.sctps_recvivalkeyid += sarry->sctps_recvivalkeyid; - sb.sctps_recvauthfailed += sarry->sctps_recvauthfailed; - sb.sctps_recvexpress += sarry->sctps_recvexpress; - sb.sctps_recvexpressm += sarry->sctps_recvexpressm; - sb.sctps_recvswcrc += sarry->sctps_recvswcrc; - sb.sctps_recvhwcrc += sarry->sctps_recvhwcrc; - sb.sctps_sendpackets += sarry->sctps_sendpackets; - sb.sctps_sendsacks += sarry->sctps_sendsacks; - sb.sctps_senddata += sarry->sctps_senddata; - sb.sctps_sendretransdata += sarry->sctps_sendretransdata; - sb.sctps_sendfastretrans += sarry->sctps_sendfastretrans; - sb.sctps_sendmultfastretrans += sarry->sctps_sendmultfastretrans; - sb.sctps_sendheartbeat += sarry->sctps_sendheartbeat; - sb.sctps_sendecne += sarry->sctps_sendecne; - sb.sctps_sendauth += sarry->sctps_sendauth; - sb.sctps_senderrors += sarry->sctps_senderrors; - sb.sctps_sendswcrc += sarry->sctps_sendswcrc; - sb.sctps_sendhwcrc += sarry->sctps_sendhwcrc; - sb.sctps_pdrpfmbox += sarry->sctps_pdrpfmbox; - sb.sctps_pdrpfehos += sarry->sctps_pdrpfehos; - sb.sctps_pdrpmbda += sarry->sctps_pdrpmbda; - sb.sctps_pdrpmbct += sarry->sctps_pdrpmbct; - sb.sctps_pdrpbwrpt += sarry->sctps_pdrpbwrpt; - sb.sctps_pdrpcrupt += sarry->sctps_pdrpcrupt; - sb.sctps_pdrpnedat += sarry->sctps_pdrpnedat; - sb.sctps_pdrppdbrk += sarry->sctps_pdrppdbrk; - sb.sctps_pdrptsnnf += sarry->sctps_pdrptsnnf; - sb.sctps_pdrpdnfnd += sarry->sctps_pdrpdnfnd; - sb.sctps_pdrpdiwnp += sarry->sctps_pdrpdiwnp; - sb.sctps_pdrpdizrw += sarry->sctps_pdrpdizrw; - sb.sctps_pdrpbadd += sarry->sctps_pdrpbadd; - sb.sctps_pdrpmark += sarry->sctps_pdrpmark; - sb.sctps_timoiterator += sarry->sctps_timoiterator; - sb.sctps_timodata += sarry->sctps_timodata; - sb.sctps_timowindowprobe += sarry->sctps_timowindowprobe; - sb.sctps_timoinit += sarry->sctps_timoinit; - sb.sctps_timosack += sarry->sctps_timosack; - sb.sctps_timoshutdown += sarry->sctps_timoshutdown; - sb.sctps_timoheartbeat += sarry->sctps_timoheartbeat; - sb.sctps_timocookie += sarry->sctps_timocookie; - sb.sctps_timosecret += sarry->sctps_timosecret; - sb.sctps_timopathmtu += sarry->sctps_timopathmtu; - sb.sctps_timoshutdownack += sarry->sctps_timoshutdownack; - sb.sctps_timoshutdownguard += sarry->sctps_timoshutdownguard; - sb.sctps_timostrmrst += sarry->sctps_timostrmrst; - sb.sctps_timoearlyfr += sarry->sctps_timoearlyfr; - sb.sctps_timoasconf += sarry->sctps_timoasconf; - sb.sctps_timodelprim += sarry->sctps_timodelprim; - sb.sctps_timoautoclose += sarry->sctps_timoautoclose; - sb.sctps_timoassockill += sarry->sctps_timoassockill; - sb.sctps_timoinpkill += sarry->sctps_timoinpkill; - sb.sctps_hdrops += sarry->sctps_hdrops; - sb.sctps_badsum += sarry->sctps_badsum; - sb.sctps_noport += sarry->sctps_noport; - sb.sctps_badvtag += sarry->sctps_badvtag; - sb.sctps_badsid += sarry->sctps_badsid; - sb.sctps_nomem += sarry->sctps_nomem; - sb.sctps_fastretransinrtt += sarry->sctps_fastretransinrtt; - sb.sctps_markedretrans += sarry->sctps_markedretrans; - sb.sctps_naglesent += sarry->sctps_naglesent; - sb.sctps_naglequeued += sarry->sctps_naglequeued; - sb.sctps_maxburstqueued += sarry->sctps_maxburstqueued; - sb.sctps_ifnomemqueued += sarry->sctps_ifnomemqueued; - sb.sctps_windowprobed += sarry->sctps_windowprobed; - sb.sctps_lowlevelerr += sarry->sctps_lowlevelerr; - sb.sctps_lowlevelerrusr += sarry->sctps_lowlevelerrusr; - sb.sctps_datadropchklmt += sarry->sctps_datadropchklmt; - sb.sctps_datadroprwnd += sarry->sctps_datadroprwnd; - sb.sctps_ecnereducedcwnd += sarry->sctps_ecnereducedcwnd; - sb.sctps_vtagexpress += sarry->sctps_vtagexpress; - sb.sctps_vtagbogus += sarry->sctps_vtagbogus; - sb.sctps_primary_randry += sarry->sctps_primary_randry; - sb.sctps_cmt_randry += sarry->sctps_cmt_randry; - sb.sctps_slowpath_sack += sarry->sctps_slowpath_sack; - sb.sctps_wu_sacks_sent += sarry->sctps_wu_sacks_sent; - sb.sctps_sends_with_flags += sarry->sctps_sends_with_flags; - sb.sctps_sends_with_unord += sarry->sctps_sends_with_unord; - sb.sctps_sends_with_eof += sarry->sctps_sends_with_eof; - sb.sctps_sends_with_abort += sarry->sctps_sends_with_abort; - sb.sctps_protocol_drain_calls += sarry->sctps_protocol_drain_calls; - sb.sctps_protocol_drains_done += sarry->sctps_protocol_drains_done; - sb.sctps_read_peeks += sarry->sctps_read_peeks; - sb.sctps_cached_chk += sarry->sctps_cached_chk; - sb.sctps_cached_strmoq += sarry->sctps_cached_strmoq; - sb.sctps_left_abandon += sarry->sctps_left_abandon; - sb.sctps_send_burst_avoid += sarry->sctps_send_burst_avoid; - sb.sctps_send_cwnd_avoid += sarry->sctps_send_cwnd_avoid; - sb.sctps_fwdtsn_map_over += sarry->sctps_fwdtsn_map_over; - sb.sctps_queue_upd_ecne += sarry->sctps_queue_upd_ecne; - sb.sctps_recvzerocrc += sarry->sctps_recvzerocrc; - sb.sctps_sendzerocrc += sarry->sctps_sendzerocrc; - if (req->newptr != NULL) { - memcpy(sarry, &sb_temp, sizeof(struct sctpstat)); - } - } - error = SYSCTL_OUT(req, &sb, sizeof(struct sctpstat)); -#else - error = SYSCTL_OUT(req, &SCTP_BASE_STATS, sizeof(struct sctpstat)); - if (error != 0) { - return (error); - } - if (req->newptr != NULL) { - memcpy(&SCTP_BASE_STATS, &sb_temp, sizeof(struct sctpstat)); - } -#endif -#else - error = SYSCTL_OUT(req, &SCTP_BASE_STATS, sizeof(struct sctpstat)); -#endif - return (error); -} - -#if defined(SCTP_LOCAL_TRACE_BUF) -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_trace_log SYSCTL_HANDLER_ARGS -{ -#pragma unused(arg1, arg2, oidp) -#else -static int -sctp_sysctl_handle_trace_log(SYSCTL_HANDLER_ARGS) -{ -#endif - int error; - -#if defined(_WIN32) && !defined(__Userspace__) - error = SYSCTL_OUT(req, SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log)); -#else - error = SYSCTL_OUT(req, &SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log)); -#endif - return (error); -} - -#if defined(__APPLE__) && !defined(__Userspace__) -static int -sctp_sysctl_handle_trace_log_clear SYSCTL_HANDLER_ARGS -{ -#pragma unused(arg1, arg2, req, oidp) -#else -static int -sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS) -{ -#endif - int error = 0; -#if defined(_WIN32) && !defined(__Userspace__) - int value = 0; - - if (req->new_data == NULL) { - return (error); - } - error = SYSCTL_IN(req, &value, sizeof(int)); - if (error == 0 && value != 0 && SCTP_BASE_SYSCTL(sctp_log) != NULL) { - memset(SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); - } -#else - - memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); -#endif - return (error); -} -#endif - -#if (defined(__APPLE__) || defined(__FreeBSD__)) && !defined(__Userspace__) -#if defined(__FreeBSD__) -#define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \ - static int \ - sctp_sysctl_handle_##mib_name(SYSCTL_HANDLER_ARGS) \ - { \ - int error; \ - uint32_t new; \ - \ - new = SCTP_BASE_SYSCTL(var_name); \ - error = sysctl_handle_int(oidp, &new, 0, req); \ - if ((error == 0) && (req->newptr != NULL)) { \ - if ((new < prefix##_MIN) || \ - (new > prefix##_MAX)) { \ - error = EINVAL; \ - } else { \ - SCTP_BASE_SYSCTL(var_name) = new; \ - } \ - } \ - return (error); \ - } \ - SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \ - CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, \ - sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC); -#else -#define SCTP_UINT_SYSCTL(mib_name, var_name, prefix) \ - static int \ - sctp_sysctl_handle_##mib_name(struct sysctl_oid *oidp, \ - void *arg1 __attribute__((unused)), \ - int arg2 __attribute__((unused)), \ - struct sysctl_req *req) \ - { \ - int error; \ - uint32_t new; \ - \ - new = SCTP_BASE_SYSCTL(var_name); \ - error = sysctl_handle_int(oidp, &new, 0, req); \ - if ((error == 0) && (req->newptr != USER_ADDR_NULL)) { \ - if ((new < prefix##_MIN) || \ - (new > prefix##_MAX)) { \ - error = EINVAL; \ - } else { \ - SCTP_BASE_SYSCTL(var_name) = new; \ - } \ - } \ - return (error); \ - } \ - SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \ - CTLTYPE_INT | CTLFLAG_RW, NULL, 0, \ - sctp_sysctl_handle_##mib_name, "I", prefix##_DESC); -#define CTLTYPE_UINT CTLTYPE_INT -#define CTLFLAG_VNET 0 -#endif - -/* - * sysctl definitions - */ - -SCTP_UINT_SYSCTL(sendspace, sctp_sendspace, SCTPCTL_MAXDGRAM) -SCTP_UINT_SYSCTL(recvspace, sctp_recvspace, SCTPCTL_RECVSPACE) -SCTP_UINT_SYSCTL(auto_asconf, sctp_auto_asconf, SCTPCTL_AUTOASCONF) -SCTP_UINT_SYSCTL(ecn_enable, sctp_ecn_enable, SCTPCTL_ECN_ENABLE) -SCTP_UINT_SYSCTL(pr_enable, sctp_pr_enable, SCTPCTL_PR_ENABLE) -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auth_enable, CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, - NULL, 0, sctp_sysctl_handle_auth, "IU", SCTPCTL_AUTH_ENABLE_DESC); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, - NULL, 0, sctp_sysctl_handle_asconf, "IU", SCTPCTL_ASCONF_ENABLE_DESC); -SCTP_UINT_SYSCTL(reconfig_enable, sctp_reconfig_enable, SCTPCTL_RECONFIG_ENABLE) -SCTP_UINT_SYSCTL(nrsack_enable, sctp_nrsack_enable, SCTPCTL_NRSACK_ENABLE) -SCTP_UINT_SYSCTL(pktdrop_enable, sctp_pktdrop_enable, SCTPCTL_PKTDROP_ENABLE) -#if defined(__APPLE__) && !defined(__Userspace__) -SCTP_UINT_SYSCTL(loopback_nocsum, sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM) -#endif -SCTP_UINT_SYSCTL(peer_chkoh, sctp_peer_chunk_oh, SCTPCTL_PEER_CHKOH) -SCTP_UINT_SYSCTL(maxburst, sctp_max_burst_default, SCTPCTL_MAXBURST) -SCTP_UINT_SYSCTL(fr_maxburst, sctp_fr_max_burst_default, SCTPCTL_FRMAXBURST) -SCTP_UINT_SYSCTL(maxchunks, sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS) -SCTP_UINT_SYSCTL(tcbhashsize, sctp_hashtblsize, SCTPCTL_TCBHASHSIZE) -SCTP_UINT_SYSCTL(pcbhashsize, sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE) -SCTP_UINT_SYSCTL(min_split_point, sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT) -SCTP_UINT_SYSCTL(chunkscale, sctp_chunkscale, SCTPCTL_CHUNKSCALE) -SCTP_UINT_SYSCTL(delayed_sack_time, sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME) -SCTP_UINT_SYSCTL(sack_freq, sctp_sack_freq_default, SCTPCTL_SACK_FREQ) -SCTP_UINT_SYSCTL(sys_resource, sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE) -SCTP_UINT_SYSCTL(asoc_resource, sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE) -SCTP_UINT_SYSCTL(heartbeat_interval, sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL) -SCTP_UINT_SYSCTL(pmtu_raise_time, sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME) -SCTP_UINT_SYSCTL(shutdown_guard_time, sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME) -SCTP_UINT_SYSCTL(secret_lifetime, sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME) -SCTP_UINT_SYSCTL(rto_max, sctp_rto_max_default, SCTPCTL_RTO_MAX) -SCTP_UINT_SYSCTL(rto_min, sctp_rto_min_default, SCTPCTL_RTO_MIN) -SCTP_UINT_SYSCTL(rto_initial, sctp_rto_initial_default, SCTPCTL_RTO_INITIAL) -SCTP_UINT_SYSCTL(init_rto_max, sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX) -SCTP_UINT_SYSCTL(valid_cookie_life, sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE) -SCTP_UINT_SYSCTL(init_rtx_max, sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX) -SCTP_UINT_SYSCTL(assoc_rtx_max, sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX) -SCTP_UINT_SYSCTL(path_rtx_max, sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX) -SCTP_UINT_SYSCTL(path_pf_threshold, sctp_path_pf_threshold, SCTPCTL_PATH_PF_THRESHOLD) -SCTP_UINT_SYSCTL(add_more_on_output, sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT) -SCTP_UINT_SYSCTL(incoming_streams, sctp_nr_incoming_streams_default, SCTPCTL_INCOMING_STREAMS) -SCTP_UINT_SYSCTL(outgoing_streams, sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS) -SCTP_UINT_SYSCTL(cmt_on_off, sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF) -SCTP_UINT_SYSCTL(cmt_use_dac, sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC) -SCTP_UINT_SYSCTL(cwnd_maxburst, sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST) -SCTP_UINT_SYSCTL(nat_friendly, sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY) -SCTP_UINT_SYSCTL(abc_l_var, sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR) -SCTP_UINT_SYSCTL(max_chained_mbufs, sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS) -SCTP_UINT_SYSCTL(do_sctp_drain, sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN) -SCTP_UINT_SYSCTL(hb_max_burst, sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST) -SCTP_UINT_SYSCTL(abort_at_limit, sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT) -SCTP_UINT_SYSCTL(min_residual, sctp_min_residual, SCTPCTL_MIN_RESIDUAL) -SCTP_UINT_SYSCTL(max_retran_chunk, sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK) -SCTP_UINT_SYSCTL(log_level, sctp_logging_level, SCTPCTL_LOGGING_LEVEL) -SCTP_UINT_SYSCTL(default_cc_module, sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE) -SCTP_UINT_SYSCTL(default_ss_module, sctp_default_ss_module, SCTPCTL_DEFAULT_SS_MODULE) -SCTP_UINT_SYSCTL(default_frag_interleave, sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE) -SCTP_UINT_SYSCTL(mobility_base, sctp_mobility_base, SCTPCTL_MOBILITY_BASE) -SCTP_UINT_SYSCTL(mobility_fasthandoff, sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF) -#if defined(SCTP_LOCAL_TRACE_BUF) -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, log, CTLFLAG_VNET|CTLTYPE_STRUCT|CTLFLAG_RD, - NULL, 0, sctp_sysctl_handle_trace_log, "S,sctplog", "SCTP logging (struct sctp_log)"); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, clear_trace, CTLFLAG_VNET|CTLTYPE_UINT | CTLFLAG_RW, - NULL, 0, sctp_sysctl_handle_trace_log_clear, "IU", "Clear SCTP Logging buffer"); -#endif -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_port, CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, - NULL, 0, sctp_sysctl_handle_udp_tunneling, "IU", SCTPCTL_UDP_TUNNELING_PORT_DESC); -SCTP_UINT_SYSCTL(enable_sack_immediately, sctp_enable_sack_immediately, SCTPCTL_SACK_IMMEDIATELY_ENABLE) -SCTP_UINT_SYSCTL(nat_friendly_init, sctp_inits_include_nat_friendly, SCTPCTL_NAT_FRIENDLY_INITS) -SCTP_UINT_SYSCTL(vtag_time_wait, sctp_vtag_time_wait, SCTPCTL_TIME_WAIT) -SCTP_UINT_SYSCTL(buffer_splitting, sctp_buffer_splitting, SCTPCTL_BUFFER_SPLITTING) -SCTP_UINT_SYSCTL(initial_cwnd, sctp_initial_cwnd, SCTPCTL_INITIAL_CWND) -SCTP_UINT_SYSCTL(rttvar_bw, sctp_rttvar_bw, SCTPCTL_RTTVAR_BW) -SCTP_UINT_SYSCTL(rttvar_rtt, sctp_rttvar_rtt, SCTPCTL_RTTVAR_RTT) -SCTP_UINT_SYSCTL(rttvar_eqret, sctp_rttvar_eqret, SCTPCTL_RTTVAR_EQRET) -SCTP_UINT_SYSCTL(rttvar_steady_step, sctp_steady_step, SCTPCTL_RTTVAR_STEADYS) -SCTP_UINT_SYSCTL(use_dcccecn, sctp_use_dccc_ecn, SCTPCTL_RTTVAR_DCCCECN) -SCTP_UINT_SYSCTL(blackhole, sctp_blackhole, SCTPCTL_BLACKHOLE) -SCTP_UINT_SYSCTL(sendall_limit, sctp_sendall_limit, SCTPCTL_SENDALL_LIMIT) -SCTP_UINT_SYSCTL(diag_info_code, sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE) -SCTP_UINT_SYSCTL(ootb_with_zero_cksum, sctp_ootb_with_zero_cksum, SCTPCTL_OOTB_WITH_ZERO_CKSUM) -#ifdef SCTP_DEBUG -SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG) -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -SCTP_UINT_SYSCTL(main_timer, sctp_main_timer, SCTPCTL_MAIN_TIMER) -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, ignore_vmware_interfaces, CTLTYPE_UINT|CTLFLAG_RW, - NULL, 0, sctp_sysctl_handle_vmware_interfaces, "IU", SCTPCTL_IGNORE_VMWARE_INTERFACES_DESC); -SCTP_UINT_SYSCTL(addr_watchdog_limit, sctp_addr_watchdog_limit, SCTPCTL_ADDR_WATCHDOG_LIMIT) -SCTP_UINT_SYSCTL(vtag_watchdog_limit, sctp_vtag_watchdog_limit, SCTPCTL_VTAG_WATCHDOG_LIMIT) -#endif -#if defined(__APPLE__) && !defined(__Userspace__) -SCTP_UINT_SYSCTL(output_unlocked, sctp_output_unlocked, SCTPCTL_OUTPUT_UNLOCKED) -#endif -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_VNET|CTLTYPE_STRUCT|CTLFLAG_RW, - NULL, 0, sctp_sysctl_handle_stats, "S,sctpstat", "SCTP statistics (struct sctp_stat)"); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_VNET|CTLTYPE_OPAQUE|CTLFLAG_RD, - NULL, 0, sctp_sysctl_handle_assoclist, "S,xassoc", "List of active SCTP associations"); - -#elif defined(_WIN32) && !defined(__Userspace__) - -#define RANGECHK(var, min, max) \ - if ((var) < (min)) { (var) = (min); } \ - else if ((var) > (max)) { (var) = (max); } - -static int -sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS) -{ - int error; - - error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); - if (error == 0) { - RANGECHK(SCTP_BASE_SYSCTL(sctp_sendspace), SCTPCTL_MAXDGRAM_MIN, SCTPCTL_MAXDGRAM_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_recvspace), SCTPCTL_RECVSPACE_MIN, SCTPCTL_RECVSPACE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_auto_asconf), SCTPCTL_AUTOASCONF_MIN, SCTPCTL_AUTOASCONF_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_auto_asconf), SCTPCTL_AUTOASCONF_MIN, SCTPCTL_AUTOASCONF_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_ecn_enable), SCTPCTL_ECN_ENABLE_MIN, SCTPCTL_ECN_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_pr_enable), SCTPCTL_PR_ENABLE_MIN, SCTPCTL_PR_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_reconfig_enable), SCTPCTL_RECONFIG_ENABLE_MIN, SCTPCTL_RECONFIG_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_nrsack_enable), SCTPCTL_NRSACK_ENABLE_MIN, SCTPCTL_NRSACK_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_pktdrop_enable), SCTPCTL_PKTDROP_ENABLE_MIN, SCTPCTL_PKTDROP_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), SCTPCTL_LOOPBACK_NOCSUM_MIN, SCTPCTL_LOOPBACK_NOCSUM_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_peer_chunk_oh), SCTPCTL_PEER_CHKOH_MIN, SCTPCTL_PEER_CHKOH_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_max_burst_default), SCTPCTL_MAXBURST_MIN, SCTPCTL_MAXBURST_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_fr_max_burst_default), SCTPCTL_FRMAXBURST_MIN, SCTPCTL_FRMAXBURST_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue), SCTPCTL_MAXCHUNKS_MIN, SCTPCTL_MAXCHUNKS_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_hashtblsize), SCTPCTL_TCBHASHSIZE_MIN, SCTPCTL_TCBHASHSIZE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_pcbtblsize), SCTPCTL_PCBHASHSIZE_MIN, SCTPCTL_PCBHASHSIZE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_min_split_point), SCTPCTL_MIN_SPLIT_POINT_MIN, SCTPCTL_MIN_SPLIT_POINT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_chunkscale), SCTPCTL_CHUNKSCALE_MIN, SCTPCTL_CHUNKSCALE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default), SCTPCTL_DELAYED_SACK_TIME_MIN, SCTPCTL_DELAYED_SACK_TIME_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_sack_freq_default), SCTPCTL_SACK_FREQ_MIN, SCTPCTL_SACK_FREQ_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_system_free_resc_limit), SCTPCTL_SYS_RESOURCE_MIN, SCTPCTL_SYS_RESOURCE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_asoc_free_resc_limit), SCTPCTL_ASOC_RESOURCE_MIN, SCTPCTL_ASOC_RESOURCE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default), SCTPCTL_HEARTBEAT_INTERVAL_MIN, SCTPCTL_HEARTBEAT_INTERVAL_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default), SCTPCTL_PMTU_RAISE_TIME_MIN, SCTPCTL_PMTU_RAISE_TIME_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default), SCTPCTL_SHUTDOWN_GUARD_TIME_MIN, SCTPCTL_SHUTDOWN_GUARD_TIME_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_secret_lifetime_default), SCTPCTL_SECRET_LIFETIME_MIN, SCTPCTL_SECRET_LIFETIME_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_rto_max_default), SCTPCTL_RTO_MAX_MIN, SCTPCTL_RTO_MAX_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_rto_min_default), SCTPCTL_RTO_MIN_MIN, SCTPCTL_RTO_MIN_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_rto_initial_default), SCTPCTL_RTO_INITIAL_MIN, SCTPCTL_RTO_INITIAL_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_init_rto_max_default), SCTPCTL_INIT_RTO_MAX_MIN, SCTPCTL_INIT_RTO_MAX_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default), SCTPCTL_VALID_COOKIE_LIFE_MIN, SCTPCTL_VALID_COOKIE_LIFE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), SCTPCTL_INIT_RTX_MAX_MIN, SCTPCTL_INIT_RTX_MAX_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), SCTPCTL_ASSOC_RTX_MAX_MIN, SCTPCTL_ASSOC_RTX_MAX_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), SCTPCTL_PATH_RTX_MAX_MIN, SCTPCTL_PATH_RTX_MAX_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_path_pf_threshold), SCTPCTL_PATH_PF_THRESHOLD_MIN, SCTPCTL_PATH_PF_THRESHOLD_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_incoming_streams_default), SCTPCTL_INCOMING_STREAMS_MIN, SCTPCTL_INCOMING_STREAMS_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_use_dac), SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_nat_friendly), SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_L2_abc_variable), SCTPCTL_ABC_L_VAR_MIN, SCTPCTL_ABC_L_VAR_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count), SCTPCTL_MAX_CHAINED_MBUFS_MIN, SCTPCTL_MAX_CHAINED_MBUFS_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_do_drain), SCTPCTL_DO_SCTP_DRAIN_MIN, SCTPCTL_DO_SCTP_DRAIN_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_hb_maxburst), SCTPCTL_HB_MAX_BURST_MIN, SCTPCTL_HB_MAX_BURST_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), SCTPCTL_ABORT_AT_LIMIT_MIN, SCTPCTL_ABORT_AT_LIMIT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_min_residual), SCTPCTL_MIN_RESIDUAL_MIN, SCTPCTL_MIN_RESIDUAL_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_max_retran_chunk), SCTPCTL_MAX_RETRAN_CHUNK_MIN, SCTPCTL_MAX_RETRAN_CHUNK_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_logging_level), SCTPCTL_LOGGING_LEVEL_MIN, SCTPCTL_LOGGING_LEVEL_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_default_cc_module), SCTPCTL_DEFAULT_CC_MODULE_MIN, SCTPCTL_DEFAULT_CC_MODULE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_default_ss_module), SCTPCTL_DEFAULT_SS_MODULE_MIN, SCTPCTL_DEFAULT_SS_MODULE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_default_frag_interleave), SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN, SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_vtag_time_wait), SCTPCTL_TIME_WAIT_MIN, SCTPCTL_TIME_WAIT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_buffer_splitting), SCTPCTL_BUFFER_SPLITTING_MIN, SCTPCTL_BUFFER_SPLITTING_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_initial_cwnd), SCTPCTL_INITIAL_CWND_MIN, SCTPCTL_INITIAL_CWND_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_rttvar_bw), SCTPCTL_RTTVAR_BW_MIN, SCTPCTL_RTTVAR_BW_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_rttvar_rtt), SCTPCTL_RTTVAR_RTT_MIN, SCTPCTL_RTTVAR_RTT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_rttvar_eqret), SCTPCTL_RTTVAR_EQRET_MIN, SCTPCTL_RTTVAR_EQRET_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_steady_step), SCTPCTL_RTTVAR_STEADYS_MIN, SCTPCTL_RTTVAR_STEADYS_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_use_dccc_ecn), SCTPCTL_RTTVAR_DCCCECN_MIN, SCTPCTL_RTTVAR_DCCCECN_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_base), SCTPCTL_MOBILITY_BASE_MIN, SCTPCTL_MOBILITY_BASE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN, SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), SCTPCTL_NAT_FRIENDLY_INITS_MIN, SCTPCTL_NAT_FRIENDLY_INITS_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_blackhole), SCTPCTL_BLACKHOLE_MIN, SCTPCTL_BLACKHOLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_sendall_limit), SCTPCTL_SENDALL_LIMIT_MIN, SCTPCTL_SENDALL_LIMIT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_diag_info_code), SCTPCTL_DIAG_INFO_CODE_MIN, SCTPCTL_DIAG_INFO_CODE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum), SCTPCTL_OOTB_WITH_ZERO_CKSUM_MIN, SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX); -#ifdef SCTP_DEBUG - RANGECHK(SCTP_BASE_SYSCTL(sctp_debug_on), SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX); -#endif - } - return (error); -} - -void -sysctl_setup_sctp(void) -{ - sysctl_add_oid(&sysctl_oid_top, "sendspace", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_sendspace), 0, sctp_sysctl_handle_int, - SCTPCTL_MAXDGRAM_DESC); - - sysctl_add_oid(&sysctl_oid_top, "recvspace", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_recvspace), 0, sctp_sysctl_handle_int, - SCTPCTL_RECVSPACE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "auto_asconf", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_auto_asconf), 0, sctp_sysctl_handle_int, - SCTPCTL_AUTOASCONF_DESC); - - sysctl_add_oid(&sysctl_oid_top, "ecn_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_ecn_enable), 0, sctp_sysctl_handle_int, - SCTPCTL_ECN_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "pr_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_pr_enable), 0, sctp_sysctl_handle_int, - SCTPCTL_PR_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "auth_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_auth_enable), 0, sctp_sysctl_handle_auth, - SCTPCTL_AUTH_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "asconf_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_asconf_enable), 0, sctp_sysctl_handle_asconf, - SCTPCTL_ASCONF_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "reconfig_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_reconfig_enable), 0, sctp_sysctl_handle_int, - SCTPCTL_RECONFIG_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "nrsack_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_nrsack_enable), 0, sctp_sysctl_handle_int, - SCTPCTL_NRSACK_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "pktdrop_enable", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_pktdrop_enable), 0, sctp_sysctl_handle_int, - SCTPCTL_PKTDROP_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "loopback_nocsum", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), 0, sctp_sysctl_handle_int, - SCTPCTL_LOOPBACK_NOCSUM_DESC); - - sysctl_add_oid(&sysctl_oid_top, "peer_chkoh", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_peer_chunk_oh), 0, sctp_sysctl_handle_int, - SCTPCTL_PEER_CHKOH_DESC); - - sysctl_add_oid(&sysctl_oid_top, "maxburst", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_max_burst_default), 0, sctp_sysctl_handle_int, - SCTPCTL_MAXBURST_DESC); - - sysctl_add_oid(&sysctl_oid_top, "fr_maxburst", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_fr_max_burst_default), 0, sctp_sysctl_handle_int, - SCTPCTL_FRMAXBURST_DESC); - - sysctl_add_oid(&sysctl_oid_top, "maxchunks", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue), 0, sctp_sysctl_handle_int, - SCTPCTL_MAXCHUNKS_DESC); - - sysctl_add_oid(&sysctl_oid_top, "tcbhashsize", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_hashtblsize), 0, sctp_sysctl_handle_int, - SCTPCTL_TCBHASHSIZE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "pcbhashsize", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_pcbtblsize), 0, sctp_sysctl_handle_int, - SCTPCTL_PCBHASHSIZE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "min_split_point", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_min_split_point), 0, sctp_sysctl_handle_int, - SCTPCTL_MIN_SPLIT_POINT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "chunkscale", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_chunkscale), 0, sctp_sysctl_handle_int, - SCTPCTL_CHUNKSCALE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "delayed_sack_time", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_delayed_sack_time_default), 0, sctp_sysctl_handle_int, - SCTPCTL_DELAYED_SACK_TIME_DESC); - - sysctl_add_oid(&sysctl_oid_top, "sack_freq", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_sack_freq_default), 0, sctp_sysctl_handle_int, - SCTPCTL_SACK_FREQ_DESC); - - sysctl_add_oid(&sysctl_oid_top, "sys_resource", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_system_free_resc_limit), 0, sctp_sysctl_handle_int, - SCTPCTL_SYS_RESOURCE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "asoc_resource", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_asoc_free_resc_limit), 0, sctp_sysctl_handle_int, - SCTPCTL_ASOC_RESOURCE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "heartbeat_interval", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_heartbeat_interval_default), 0, sctp_sysctl_handle_int, - SCTPCTL_HEARTBEAT_INTERVAL_DESC); - - sysctl_add_oid(&sysctl_oid_top, "pmtu_raise_time", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_pmtu_raise_time_default), 0, sctp_sysctl_handle_int, - SCTPCTL_PMTU_RAISE_TIME_DESC); - - sysctl_add_oid(&sysctl_oid_top, "shutdown_guard_time", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_shutdown_guard_time_default), 0, sctp_sysctl_handle_int, - SCTPCTL_SHUTDOWN_GUARD_TIME_DESC); - - sysctl_add_oid(&sysctl_oid_top, "secret_lifetime", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_secret_lifetime_default), 0, sctp_sysctl_handle_int, - SCTPCTL_SECRET_LIFETIME_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rto_max", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_rto_max_default), 0, sctp_sysctl_handle_int, - SCTPCTL_RTO_MAX_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rto_min", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_rto_min_default), 0, sctp_sysctl_handle_int, - SCTPCTL_RTO_MIN_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rto_initial", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_rto_initial_default), 0, sctp_sysctl_handle_int, - SCTPCTL_RTO_INITIAL_DESC); - - sysctl_add_oid(&sysctl_oid_top, "init_rto_max", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_init_rto_max_default), 0, sctp_sysctl_handle_int, - SCTPCTL_INIT_RTO_MAX_DESC); - - sysctl_add_oid(&sysctl_oid_top, "valid_cookie_life", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_valid_cookie_life_default), 0, sctp_sysctl_handle_int, - SCTPCTL_VALID_COOKIE_LIFE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "init_rtx_max", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), 0, sctp_sysctl_handle_int, - SCTPCTL_INIT_RTX_MAX_DESC); - - sysctl_add_oid(&sysctl_oid_top, "assoc_rtx_max", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), 0, sctp_sysctl_handle_int, - SCTPCTL_ASSOC_RTX_MAX_DESC); - - sysctl_add_oid(&sysctl_oid_top, "path_rtx_max", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sctp_sysctl_handle_int, - SCTPCTL_PATH_RTX_MAX_DESC); - - sysctl_add_oid(&sysctl_oid_top, "path_pf_threshold", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_path_pf_threshold), 0, sctp_sysctl_handle_int, - SCTPCTL_PATH_PF_THRESHOLD_DESC); - - sysctl_add_oid(&sysctl_oid_top, "add_more_on_output", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sctp_sysctl_handle_int, - SCTPCTL_ADD_MORE_ON_OUTPUT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "incoming_streams", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_nr_incoming_streams_default), 0, sctp_sysctl_handle_int, - SCTPCTL_INCOMING_STREAMS_DESC); - - sysctl_add_oid(&sysctl_oid_top, "outgoing_streams", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), 0, sctp_sysctl_handle_int, - SCTPCTL_OUTGOING_STREAMS_DESC); - - sysctl_add_oid(&sysctl_oid_top, "cmt_on_off", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_cmt_on_off), 0, sctp_sysctl_handle_int, - SCTPCTL_CMT_ON_OFF_DESC); - - sysctl_add_oid(&sysctl_oid_top, "cmt_use_dac", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sctp_sysctl_handle_int, - SCTPCTL_CMT_USE_DAC_DESC); - - sysctl_add_oid(&sysctl_oid_top, "cwnd_maxburst", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sctp_sysctl_handle_int, - SCTPCTL_CWND_MAXBURST_DESC); - - sysctl_add_oid(&sysctl_oid_top, "nat_friendly", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_nat_friendly), 0, sctp_sysctl_handle_int, - SCTPCTL_NAT_FRIENDLY_DESC); - - sysctl_add_oid(&sysctl_oid_top, "abc_l_var", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_L2_abc_variable), 0, sctp_sysctl_handle_int, - SCTPCTL_ABC_L_VAR_DESC); - - sysctl_add_oid(&sysctl_oid_top, "max_chained_mbufs", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count), 0, sctp_sysctl_handle_int, - SCTPCTL_MAX_CHAINED_MBUFS_DESC); - - sysctl_add_oid(&sysctl_oid_top, "do_sctp_drain", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_do_drain), 0, sctp_sysctl_handle_int, - SCTPCTL_DO_SCTP_DRAIN_DESC); - - sysctl_add_oid(&sysctl_oid_top, "hb_max_burst", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_hb_maxburst), 0, sctp_sysctl_handle_int, - SCTPCTL_HB_MAX_BURST_DESC); - - sysctl_add_oid(&sysctl_oid_top, "abort_at_limit", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), 0, sctp_sysctl_handle_int, - SCTPCTL_ABORT_AT_LIMIT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "min_residual", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_min_residual), 0, sctp_sysctl_handle_int, - SCTPCTL_MIN_RESIDUAL_DESC); - - sysctl_add_oid(&sysctl_oid_top, "max_retran_chunk", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_max_retran_chunk), 0, sctp_sysctl_handle_int, - SCTPCTL_MAX_RETRAN_CHUNK_DESC); - - sysctl_add_oid(&sysctl_oid_top, "log_level", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_logging_level), 0, sctp_sysctl_handle_int, - SCTPCTL_LOGGING_LEVEL_DESC); - - sysctl_add_oid(&sysctl_oid_top, "default_cc_module", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_default_cc_module), 0, sctp_sysctl_handle_int, - SCTPCTL_DEFAULT_CC_MODULE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "default_ss_module", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_default_ss_module), 0, sctp_sysctl_handle_int, - SCTPCTL_DEFAULT_SS_MODULE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "default_frag_interleave", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_default_frag_interleave), 0, sctp_sysctl_handle_int, - SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "mobility_base", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_mobility_base), 0, sctp_sysctl_handle_int, - SCTPCTL_MOBILITY_BASE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "mobility_fasthandoff", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), 0, sctp_sysctl_handle_int, - SCTPCTL_MOBILITY_FASTHANDOFF_DESC); - -#if defined(SCTP_LOCAL_TRACE_BUF) - sysctl_add_oid(&sysctl_oid_top, "sctp_log", CTLTYPE_STRUCT|CTLFLAG_RD, - SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log), NULL, - "SCTP logging (struct sctp_log)"); - - sysctl_add_oid(&sysctl_oid_top, "clear_trace", CTLTYPE_INT|CTLFLAG_WR, - NULL, 0, sctp_sysctl_handle_trace_log_clear, - "Clear SCTP Logging buffer"); -#endif - - sysctl_add_oid(&sysctl_oid_top, "udp_tunneling_port", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_udp_tunneling_port), 0, sctp_sysctl_handle_udp_tunneling, - SCTPCTL_UDP_TUNNELING_PORT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "enable_sack_immediately", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), 0, sctp_sysctl_handle_int, - SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "nat_friendly_init", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), 0, sctp_sysctl_handle_int, - SCTPCTL_NAT_FRIENDLY_DESC); - - sysctl_add_oid(&sysctl_oid_top, "vtag_time_wait", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_vtag_time_wait), 0, sctp_sysctl_handle_int, - SCTPCTL_TIME_WAIT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "buffer_splitting", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_buffer_splitting), 0, sctp_sysctl_handle_int, - SCTPCTL_BUFFER_SPLITTING_DESC); - - sysctl_add_oid(&sysctl_oid_top, "initial_cwnd", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_initial_cwnd), 0, sctp_sysctl_handle_int, - SCTPCTL_INITIAL_CWND_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rttvar_bw", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_rttvar_bw), 0, sctp_sysctl_handle_int, - SCTPCTL_RTTVAR_BW_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rttvar_rtt", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_rttvar_rtt), 0, sctp_sysctl_handle_int, - SCTPCTL_RTTVAR_RTT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rttvar_eqret", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_rttvar_eqret), 0, sctp_sysctl_handle_int, - SCTPCTL_RTTVAR_EQRET_DESC); - - sysctl_add_oid(&sysctl_oid_top, "rttvar_steady_step", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_steady_step), 0, sctp_sysctl_handle_int, - SCTPCTL_RTTVAR_STEADYS_DESC); - - sysctl_add_oid(&sysctl_oid_top, "use_dcccecn", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_use_dccc_ecn), 0, sctp_sysctl_handle_int, - SCTPCTL_RTTVAR_DCCCECN_DESC); - - sysctl_add_oid(&sysctl_oid_top, "blackhole", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_blackhole), 0, sctp_sysctl_handle_int, - SCTPCTL_BLACKHOLE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "sendall_limit", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_sendall_limit), 0, sctp_sysctl_handle_int, - SCTPCTL_SENDALL_LIMIT_DESC); - - sysctl_add_oid(&sysctl_oid_top, "diag_info_code", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_diag_info_code), 0, sctp_sysctl_handle_int, - SCTPCTL_DIAG_INFO_CODE_DESC); - - sysctl_add_oid(&sysctl_oid_top, "ootb_with_zero_cksum", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum), 0, sctp_sysctl_handle_int, - SCTPCTL_OOTB_WITH_ZERO_CKSUM_DESC); - -#ifdef SCTP_DEBUG - sysctl_add_oid(&sysctl_oid_top, "debug", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_debug_on), 0, sctp_sysctl_handle_int, - SCTPCTL_DEBUG_DESC); -#endif - - sysctl_add_oid(&sysctl_oid_top, "stats", CTLTYPE_STRUCT|CTLFLAG_RW, - &SCTP_BASE_STATS, sizeof(SCTP_BASE_STATS), NULL, - "SCTP statistics (struct sctp_stat)"); - - sysctl_add_oid(&sysctl_oid_top, "assoclist", CTLTYPE_STRUCT|CTLFLAG_RD, - NULL, 0, sctp_assoclist, - "List of active SCTP associations"); -} -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.h deleted file mode 100644 index 9dc40c80..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_sysctl.h +++ /dev/null @@ -1,633 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_SYSCTL_H_ -#define _NETINET_SCTP_SYSCTL_H_ - -#include -#include - -struct sctp_sysctl { - uint32_t sctp_sendspace; - uint32_t sctp_recvspace; - uint32_t sctp_auto_asconf; - uint32_t sctp_multiple_asconfs; - uint32_t sctp_ecn_enable; - uint32_t sctp_pr_enable; - uint32_t sctp_auth_enable; - uint32_t sctp_asconf_enable; - uint32_t sctp_reconfig_enable; - uint32_t sctp_nrsack_enable; - uint32_t sctp_pktdrop_enable; - uint32_t sctp_fr_max_burst_default; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - uint32_t sctp_no_csum_on_loopback; -#endif - uint32_t sctp_peer_chunk_oh; - uint32_t sctp_max_burst_default; - uint32_t sctp_max_chunks_on_queue; - uint32_t sctp_hashtblsize; - uint32_t sctp_pcbtblsize; - uint32_t sctp_min_split_point; - uint32_t sctp_chunkscale; - uint32_t sctp_delayed_sack_time_default; - uint32_t sctp_sack_freq_default; - uint32_t sctp_system_free_resc_limit; - uint32_t sctp_asoc_free_resc_limit; - uint32_t sctp_heartbeat_interval_default; - uint32_t sctp_pmtu_raise_time_default; - uint32_t sctp_shutdown_guard_time_default; - uint32_t sctp_secret_lifetime_default; - uint32_t sctp_rto_max_default; - uint32_t sctp_rto_min_default; - uint32_t sctp_rto_initial_default; - uint32_t sctp_init_rto_max_default; - uint32_t sctp_valid_cookie_life_default; - uint32_t sctp_init_rtx_max_default; - uint32_t sctp_assoc_rtx_max_default; - uint32_t sctp_path_rtx_max_default; - uint32_t sctp_path_pf_threshold; - uint32_t sctp_add_more_threshold; - uint32_t sctp_nr_incoming_streams_default; - uint32_t sctp_nr_outgoing_streams_default; - uint32_t sctp_cmt_on_off; - uint32_t sctp_cmt_use_dac; - uint32_t sctp_use_cwnd_based_maxburst; - uint32_t sctp_nat_friendly; - uint32_t sctp_L2_abc_variable; - uint32_t sctp_mbuf_threshold_count; - uint32_t sctp_do_drain; - uint32_t sctp_hb_maxburst; - uint32_t sctp_abort_if_one_2_one_hits_limit; - uint32_t sctp_min_residual; - uint32_t sctp_max_retran_chunk; - uint32_t sctp_logging_level; - /* JRS - Variable for default congestion control module */ - uint32_t sctp_default_cc_module; - /* RS - Variable for default stream scheduling module */ - uint32_t sctp_default_ss_module; - uint32_t sctp_default_frag_interleave; - uint32_t sctp_mobility_base; - uint32_t sctp_mobility_fasthandoff; - uint32_t sctp_inits_include_nat_friendly; - uint32_t sctp_rttvar_bw; - uint32_t sctp_rttvar_rtt; - uint32_t sctp_rttvar_eqret; - uint32_t sctp_steady_step; - uint32_t sctp_use_dccc_ecn; -#if defined(SCTP_LOCAL_TRACE_BUF) -#if defined(_WIN32) && !defined(__Userspace__) - struct sctp_log *sctp_log; -#else - struct sctp_log sctp_log; -#endif -#endif - uint32_t sctp_udp_tunneling_port; - uint32_t sctp_enable_sack_immediately; - uint32_t sctp_vtag_time_wait; - uint32_t sctp_buffer_splitting; - uint32_t sctp_initial_cwnd; - uint32_t sctp_blackhole; - uint32_t sctp_sendall_limit; - uint32_t sctp_diag_info_code; - uint32_t sctp_ootb_with_zero_cksum; -#if defined(SCTP_DEBUG) - uint32_t sctp_debug_on; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - uint32_t sctp_ignore_vmware_interfaces; - uint32_t sctp_main_timer; - uint32_t sctp_addr_watchdog_limit; - uint32_t sctp_vtag_watchdog_limit; -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - uint32_t sctp_output_unlocked; -#endif -}; - -/* - * limits for the sysctl variables - */ -/* maxdgram: Maximum outgoing SCTP buffer size */ -#define SCTPCTL_MAXDGRAM_DESC "Maximum outgoing SCTP buffer size" -#define SCTPCTL_MAXDGRAM_MIN 0 -#define SCTPCTL_MAXDGRAM_MAX 0xFFFFFFFF -#if defined(__Userspace__) -#define SCTPCTL_MAXDGRAM_DEFAULT SB_MAX -#else -#define SCTPCTL_MAXDGRAM_DEFAULT 262144 /* 256k */ -#endif - -/* recvspace: Maximum incoming SCTP buffer size */ -#define SCTPCTL_RECVSPACE_DESC "Maximum incoming SCTP buffer size" -#define SCTPCTL_RECVSPACE_MIN 0 -#define SCTPCTL_RECVSPACE_MAX 0xFFFFFFFF -#if defined(__Userspace__) -#define SCTPCTL_RECVSPACE_DEFAULT SB_RAW -#else -#define SCTPCTL_RECVSPACE_DEFAULT 262144 /* 256k */ -#endif - -/* autoasconf: Enable SCTP Auto-ASCONF */ -#define SCTPCTL_AUTOASCONF_DESC "Enable SCTP Auto-ASCONF" -#define SCTPCTL_AUTOASCONF_MIN 0 -#define SCTPCTL_AUTOASCONF_MAX 1 -#define SCTPCTL_AUTOASCONF_DEFAULT 1 - -/* autoasconf: Enable SCTP Auto-ASCONF */ -#define SCTPCTL_MULTIPLEASCONFS_DESC "Enable SCTP Multiple-ASCONFs" -#define SCTPCTL_MULTIPLEASCONFS_MIN 0 -#define SCTPCTL_MULTIPLEASCONFS_MAX 1 -#define SCTPCTL_MULTIPLEASCONFS_DEFAULT SCTP_DEFAULT_MULTIPLE_ASCONFS - -/* ecn_enable: Enable SCTP ECN */ -#define SCTPCTL_ECN_ENABLE_DESC "Enable SCTP ECN" -#define SCTPCTL_ECN_ENABLE_MIN 0 -#define SCTPCTL_ECN_ENABLE_MAX 1 -#define SCTPCTL_ECN_ENABLE_DEFAULT 1 - -/* pr_enable: Enable PR-SCTP */ -#define SCTPCTL_PR_ENABLE_DESC "Enable PR-SCTP" -#define SCTPCTL_PR_ENABLE_MIN 0 -#define SCTPCTL_PR_ENABLE_MAX 1 -#define SCTPCTL_PR_ENABLE_DEFAULT 1 - -/* auth_enable: Enable SCTP AUTH function */ -#define SCTPCTL_AUTH_ENABLE_DESC "Enable SCTP AUTH function" -#define SCTPCTL_AUTH_ENABLE_MIN 0 -#define SCTPCTL_AUTH_ENABLE_MAX 1 -#define SCTPCTL_AUTH_ENABLE_DEFAULT 1 - -/* asconf_enable: Enable SCTP ASCONF */ -#define SCTPCTL_ASCONF_ENABLE_DESC "Enable SCTP ASCONF" -#define SCTPCTL_ASCONF_ENABLE_MIN 0 -#define SCTPCTL_ASCONF_ENABLE_MAX 1 -#define SCTPCTL_ASCONF_ENABLE_DEFAULT 1 - -/* reconfig_enable: Enable SCTP RE-CONFIG */ -#define SCTPCTL_RECONFIG_ENABLE_DESC "Enable SCTP RE-CONFIG" -#define SCTPCTL_RECONFIG_ENABLE_MIN 0 -#define SCTPCTL_RECONFIG_ENABLE_MAX 1 -#define SCTPCTL_RECONFIG_ENABLE_DEFAULT 1 - -/* nrsack_enable: Enable NR_SACK */ -#define SCTPCTL_NRSACK_ENABLE_DESC "Enable SCTP NR-SACK" -#define SCTPCTL_NRSACK_ENABLE_MIN 0 -#define SCTPCTL_NRSACK_ENABLE_MAX 1 -#define SCTPCTL_NRSACK_ENABLE_DEFAULT 0 - -/* pktdrop_enable: Enable SCTP Packet Drop Reports */ -#define SCTPCTL_PKTDROP_ENABLE_DESC "Enable SCTP PKTDROP" -#define SCTPCTL_PKTDROP_ENABLE_MIN 0 -#define SCTPCTL_PKTDROP_ENABLE_MAX 1 -#define SCTPCTL_PKTDROP_ENABLE_DEFAULT 0 - -/* loopback_nocsum: Enable NO Csum on packets sent on loopback */ -#define SCTPCTL_LOOPBACK_NOCSUM_DESC "Enable NO Csum on packets sent on loopback" -#define SCTPCTL_LOOPBACK_NOCSUM_MIN 0 -#define SCTPCTL_LOOPBACK_NOCSUM_MAX 1 -#define SCTPCTL_LOOPBACK_NOCSUM_DEFAULT 1 - -/* peer_chkoh: Amount to debit peers rwnd per chunk sent */ -#define SCTPCTL_PEER_CHKOH_DESC "Amount to debit peers rwnd per chunk sent" -#define SCTPCTL_PEER_CHKOH_MIN 0 -#define SCTPCTL_PEER_CHKOH_MAX 0xFFFFFFFF -#define SCTPCTL_PEER_CHKOH_DEFAULT 256 - -/* maxburst: Default max burst for sctp endpoints */ -#define SCTPCTL_MAXBURST_DESC "Default max burst for sctp endpoints" -#define SCTPCTL_MAXBURST_MIN 0 -#define SCTPCTL_MAXBURST_MAX 0xFFFFFFFF -#define SCTPCTL_MAXBURST_DEFAULT SCTP_DEF_MAX_BURST - -/* fr_maxburst: Default max burst for sctp endpoints when fast retransmitting */ -#define SCTPCTL_FRMAXBURST_DESC "Default max burst for SCTP endpoints when fast retransmitting" -#define SCTPCTL_FRMAXBURST_MIN 0 -#define SCTPCTL_FRMAXBURST_MAX 0xFFFFFFFF -#define SCTPCTL_FRMAXBURST_DEFAULT SCTP_DEF_FRMAX_BURST - -/* maxchunks: Default max chunks on queue per asoc */ -#define SCTPCTL_MAXCHUNKS_DESC "Default max chunks on queue per asoc" -#define SCTPCTL_MAXCHUNKS_MIN 0 -#define SCTPCTL_MAXCHUNKS_MAX 0xFFFFFFFF -#define SCTPCTL_MAXCHUNKS_DEFAULT SCTP_ASOC_MAX_CHUNKS_ON_QUEUE - -/* tcbhashsize: Tunable for Hash table sizes */ -#define SCTPCTL_TCBHASHSIZE_DESC "Tunable for TCB hash table sizes" -#define SCTPCTL_TCBHASHSIZE_MIN 1 -#define SCTPCTL_TCBHASHSIZE_MAX 0xFFFFFFFF -#define SCTPCTL_TCBHASHSIZE_DEFAULT SCTP_TCBHASHSIZE - -/* pcbhashsize: Tunable for PCB Hash table sizes */ -#define SCTPCTL_PCBHASHSIZE_DESC "Tunable for PCB hash table sizes" -#define SCTPCTL_PCBHASHSIZE_MIN 1 -#define SCTPCTL_PCBHASHSIZE_MAX 0xFFFFFFFF -#define SCTPCTL_PCBHASHSIZE_DEFAULT SCTP_PCBHASHSIZE - -/* min_split_point: Minimum size when splitting a chunk */ -#define SCTPCTL_MIN_SPLIT_POINT_DESC "Minimum size when splitting a chunk" -#define SCTPCTL_MIN_SPLIT_POINT_MIN 0 -#define SCTPCTL_MIN_SPLIT_POINT_MAX 0xFFFFFFFF -#define SCTPCTL_MIN_SPLIT_POINT_DEFAULT SCTP_DEFAULT_SPLIT_POINT_MIN - -/* chunkscale: Tunable for Scaling of number of chunks and messages */ -#define SCTPCTL_CHUNKSCALE_DESC "Tunable for scaling of number of chunks and messages" -#define SCTPCTL_CHUNKSCALE_MIN 1 -#define SCTPCTL_CHUNKSCALE_MAX 0xFFFFFFFF -#define SCTPCTL_CHUNKSCALE_DEFAULT SCTP_CHUNKQUEUE_SCALE - -/* delayed_sack_time: Default delayed SACK timer in ms */ -#define SCTPCTL_DELAYED_SACK_TIME_DESC "Default delayed SACK timer in ms" -#define SCTPCTL_DELAYED_SACK_TIME_MIN 0 -#define SCTPCTL_DELAYED_SACK_TIME_MAX 0xFFFFFFFF -#define SCTPCTL_DELAYED_SACK_TIME_DEFAULT SCTP_RECV_MSEC - -/* sack_freq: Default SACK frequency */ -#define SCTPCTL_SACK_FREQ_DESC "Default SACK frequency" -#define SCTPCTL_SACK_FREQ_MIN 0 -#define SCTPCTL_SACK_FREQ_MAX 0xFFFFFFFF -#define SCTPCTL_SACK_FREQ_DEFAULT SCTP_DEFAULT_SACK_FREQ - -/* sys_resource: Max number of cached resources in the system */ -#define SCTPCTL_SYS_RESOURCE_DESC "Max number of cached resources in the system" -#define SCTPCTL_SYS_RESOURCE_MIN 0 -#define SCTPCTL_SYS_RESOURCE_MAX 0xFFFFFFFF -#define SCTPCTL_SYS_RESOURCE_DEFAULT SCTP_DEF_SYSTEM_RESC_LIMIT - -/* asoc_resource: Max number of cached resources in an asoc */ -#define SCTPCTL_ASOC_RESOURCE_DESC "Max number of cached resources in an asoc" -#define SCTPCTL_ASOC_RESOURCE_MIN 0 -#define SCTPCTL_ASOC_RESOURCE_MAX 0xFFFFFFFF -#define SCTPCTL_ASOC_RESOURCE_DEFAULT SCTP_DEF_ASOC_RESC_LIMIT - -/* heartbeat_interval: Default heartbeat interval in ms */ -#define SCTPCTL_HEARTBEAT_INTERVAL_DESC "Default heartbeat interval in ms" -#define SCTPCTL_HEARTBEAT_INTERVAL_MIN 0 -#define SCTPCTL_HEARTBEAT_INTERVAL_MAX 0xFFFFFFFF -#define SCTPCTL_HEARTBEAT_INTERVAL_DEFAULT SCTP_HB_DEFAULT_MSEC - -/* pmtu_raise_time: Default PMTU raise timer in seconds */ -#define SCTPCTL_PMTU_RAISE_TIME_DESC "Default PMTU raise timer in seconds" -#define SCTPCTL_PMTU_RAISE_TIME_MIN 0 -#define SCTPCTL_PMTU_RAISE_TIME_MAX 0xFFFFFFFF -#define SCTPCTL_PMTU_RAISE_TIME_DEFAULT SCTP_DEF_PMTU_RAISE_SEC - -/* shutdown_guard_time: Default shutdown guard timer in seconds */ -#define SCTPCTL_SHUTDOWN_GUARD_TIME_DESC "Shutdown guard timer in seconds (0 means 5 times RTO.Max)" -#define SCTPCTL_SHUTDOWN_GUARD_TIME_MIN 0 -#define SCTPCTL_SHUTDOWN_GUARD_TIME_MAX 0xFFFFFFFF -#define SCTPCTL_SHUTDOWN_GUARD_TIME_DEFAULT 0 - -/* secret_lifetime: Default secret lifetime in seconds */ -#define SCTPCTL_SECRET_LIFETIME_DESC "Default secret lifetime in seconds" -#define SCTPCTL_SECRET_LIFETIME_MIN 0 -#define SCTPCTL_SECRET_LIFETIME_MAX 0xFFFFFFFF -#define SCTPCTL_SECRET_LIFETIME_DEFAULT SCTP_DEFAULT_SECRET_LIFE_SEC - -/* rto_max: Default maximum retransmission timeout in ms */ -#define SCTPCTL_RTO_MAX_DESC "Default maximum retransmission timeout in ms" -#define SCTPCTL_RTO_MAX_MIN 0 -#define SCTPCTL_RTO_MAX_MAX 0xFFFFFFFF -#define SCTPCTL_RTO_MAX_DEFAULT SCTP_RTO_UPPER_BOUND - -/* rto_min: Default minimum retransmission timeout in ms */ -#define SCTPCTL_RTO_MIN_DESC "Default minimum retransmission timeout in ms" -#define SCTPCTL_RTO_MIN_MIN 0 -#define SCTPCTL_RTO_MIN_MAX 0xFFFFFFFF -#define SCTPCTL_RTO_MIN_DEFAULT SCTP_RTO_LOWER_BOUND - -/* rto_initial: Default initial retransmission timeout in ms */ -#define SCTPCTL_RTO_INITIAL_DESC "Default initial retransmission timeout in ms" -#define SCTPCTL_RTO_INITIAL_MIN 0 -#define SCTPCTL_RTO_INITIAL_MAX 0xFFFFFFFF -#define SCTPCTL_RTO_INITIAL_DEFAULT SCTP_RTO_INITIAL - -/* init_rto_max: Default maximum retransmission timeout during association setup in ms */ -#define SCTPCTL_INIT_RTO_MAX_DESC "Default maximum retransmission timeout during association setup in ms" -#define SCTPCTL_INIT_RTO_MAX_MIN 0 -#define SCTPCTL_INIT_RTO_MAX_MAX 0xFFFFFFFF -#define SCTPCTL_INIT_RTO_MAX_DEFAULT SCTP_RTO_UPPER_BOUND - -/* valid_cookie_life: Default cookie lifetime in ms */ -#define SCTPCTL_VALID_COOKIE_LIFE_DESC "Default cookie lifetime in ms" -#define SCTPCTL_VALID_COOKIE_LIFE_MIN SCTP_MIN_COOKIE_LIFE -#define SCTPCTL_VALID_COOKIE_LIFE_MAX SCTP_MAX_COOKIE_LIFE -#define SCTPCTL_VALID_COOKIE_LIFE_DEFAULT SCTP_DEFAULT_COOKIE_LIFE - -/* init_rtx_max: Default maximum number of retransmission for INIT chunks */ -#define SCTPCTL_INIT_RTX_MAX_DESC "Default maximum number of retransmissions for INIT chunks" -#define SCTPCTL_INIT_RTX_MAX_MIN 0 -#define SCTPCTL_INIT_RTX_MAX_MAX 0xFFFFFFFF -#define SCTPCTL_INIT_RTX_MAX_DEFAULT SCTP_DEF_MAX_INIT - -/* assoc_rtx_max: Default maximum number of retransmissions per association */ -#define SCTPCTL_ASSOC_RTX_MAX_DESC "Default maximum number of retransmissions per association" -#define SCTPCTL_ASSOC_RTX_MAX_MIN 0 -#define SCTPCTL_ASSOC_RTX_MAX_MAX 0xFFFFFFFF -#define SCTPCTL_ASSOC_RTX_MAX_DEFAULT SCTP_DEF_MAX_SEND - -/* path_rtx_max: Default maximum of retransmissions per path */ -#define SCTPCTL_PATH_RTX_MAX_DESC "Default maximum of retransmissions per path" -#define SCTPCTL_PATH_RTX_MAX_MIN 0 -#define SCTPCTL_PATH_RTX_MAX_MAX 0xFFFFFFFF -#define SCTPCTL_PATH_RTX_MAX_DEFAULT SCTP_DEF_MAX_PATH_RTX - -/* path_pf_threshold: threshold for considering the path potentially failed */ -#define SCTPCTL_PATH_PF_THRESHOLD_DESC "Default potentially failed threshold" -#define SCTPCTL_PATH_PF_THRESHOLD_MIN 0 -#define SCTPCTL_PATH_PF_THRESHOLD_MAX 0xFFFF -#define SCTPCTL_PATH_PF_THRESHOLD_DEFAULT SCTPCTL_PATH_PF_THRESHOLD_MAX - -/* add_more_on_output: When space-wise is it worthwhile to try to add more to a socket send buffer */ -#define SCTPCTL_ADD_MORE_ON_OUTPUT_DESC "When space-wise is it worthwhile to try to add more to a socket send buffer" -#define SCTPCTL_ADD_MORE_ON_OUTPUT_MIN 0 -#define SCTPCTL_ADD_MORE_ON_OUTPUT_MAX 0xFFFFFFFF -#define SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT SCTP_DEFAULT_ADD_MORE - -/* incoming_streams: Default number of incoming streams */ -#define SCTPCTL_INCOMING_STREAMS_DESC "Default number of incoming streams" -#define SCTPCTL_INCOMING_STREAMS_MIN 1 -#define SCTPCTL_INCOMING_STREAMS_MAX 65535 -#define SCTPCTL_INCOMING_STREAMS_DEFAULT SCTP_ISTREAM_INITIAL - -/* outgoing_streams: Default number of outgoing streams */ -#define SCTPCTL_OUTGOING_STREAMS_DESC "Default number of outgoing streams" -#define SCTPCTL_OUTGOING_STREAMS_MIN 1 -#define SCTPCTL_OUTGOING_STREAMS_MAX 65535 -#define SCTPCTL_OUTGOING_STREAMS_DEFAULT SCTP_OSTREAM_INITIAL - -/* cmt_on_off: CMT on/off flag */ -#define SCTPCTL_CMT_ON_OFF_DESC "CMT settings" -#define SCTPCTL_CMT_ON_OFF_MIN SCTP_CMT_OFF -#define SCTPCTL_CMT_ON_OFF_MAX SCTP_CMT_MAX -#define SCTPCTL_CMT_ON_OFF_DEFAULT SCTP_CMT_OFF - -/* cmt_use_dac: CMT DAC on/off flag */ -#define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag" -#define SCTPCTL_CMT_USE_DAC_MIN 0 -#define SCTPCTL_CMT_USE_DAC_MAX 1 -#define SCTPCTL_CMT_USE_DAC_DEFAULT 0 - -/* cwnd_maxburst: Use a CWND adjusting to implement maxburst */ -#define SCTPCTL_CWND_MAXBURST_DESC "Adjust congestion control window to limit maximum burst when sending" -#define SCTPCTL_CWND_MAXBURST_MIN 0 -#define SCTPCTL_CWND_MAXBURST_MAX 1 -#define SCTPCTL_CWND_MAXBURST_DEFAULT 1 - -/* nat_friendly: SCTP NAT friendly operation */ -#define SCTPCTL_NAT_FRIENDLY_DESC "SCTP NAT friendly operation" -#define SCTPCTL_NAT_FRIENDLY_MIN 0 -#define SCTPCTL_NAT_FRIENDLY_MAX 1 -#define SCTPCTL_NAT_FRIENDLY_DEFAULT 1 - -/* abc_l_var: SCTP ABC max increase per SACK (L) */ -#define SCTPCTL_ABC_L_VAR_DESC "SCTP ABC max increase per SACK (L)" -#define SCTPCTL_ABC_L_VAR_MIN 0 -#define SCTPCTL_ABC_L_VAR_MAX 0xFFFFFFFF -#define SCTPCTL_ABC_L_VAR_DEFAULT 2 - -/* max_chained_mbufs: Default max number of small mbufs on a chain */ -#define SCTPCTL_MAX_CHAINED_MBUFS_DESC "Default max number of small mbufs on a chain" -#define SCTPCTL_MAX_CHAINED_MBUFS_MIN 0 -#define SCTPCTL_MAX_CHAINED_MBUFS_MAX 0xFFFFFFFF -#define SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT SCTP_DEFAULT_MBUFS_IN_CHAIN - -/* do_sctp_drain: Should SCTP respond to the drain calls */ -#define SCTPCTL_DO_SCTP_DRAIN_DESC "Should SCTP respond to the drain calls" -#define SCTPCTL_DO_SCTP_DRAIN_MIN 0 -#define SCTPCTL_DO_SCTP_DRAIN_MAX 1 -#define SCTPCTL_DO_SCTP_DRAIN_DEFAULT 1 - -/* hb_max_burst: Confirmation Heartbeat max burst? */ -#define SCTPCTL_HB_MAX_BURST_DESC "Confirmation Heartbeat max burst" -#define SCTPCTL_HB_MAX_BURST_MIN 1 -#define SCTPCTL_HB_MAX_BURST_MAX 0xFFFFFFFF -#define SCTPCTL_HB_MAX_BURST_DEFAULT SCTP_DEF_HBMAX_BURST - -/* abort_at_limit: When one-2-one hits qlimit abort */ -#define SCTPCTL_ABORT_AT_LIMIT_DESC "Abort when one-to-one hits qlimit" -#define SCTPCTL_ABORT_AT_LIMIT_MIN 0 -#define SCTPCTL_ABORT_AT_LIMIT_MAX 1 -#define SCTPCTL_ABORT_AT_LIMIT_DEFAULT 0 - -/* min_residual: min residual in a data fragment leftover */ -#define SCTPCTL_MIN_RESIDUAL_DESC "Minimum residual data chunk in second part of split" -#define SCTPCTL_MIN_RESIDUAL_MIN 20 -#define SCTPCTL_MIN_RESIDUAL_MAX 65535 -#define SCTPCTL_MIN_RESIDUAL_DEFAULT 1452 - -/* max_retran_chunk: max chunk retransmissions */ -#define SCTPCTL_MAX_RETRAN_CHUNK_DESC "Maximum times an unlucky chunk can be retransmitted before assoc abort" -#define SCTPCTL_MAX_RETRAN_CHUNK_MIN 0 -#define SCTPCTL_MAX_RETRAN_CHUNK_MAX 65535 -#define SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT 30 - -/* sctp_logging: This gives us logging when the options are enabled */ -#define SCTPCTL_LOGGING_LEVEL_DESC "Ltrace/KTR trace logging level" -#define SCTPCTL_LOGGING_LEVEL_MIN 0 -#define SCTPCTL_LOGGING_LEVEL_MAX 0xffffffff -#define SCTPCTL_LOGGING_LEVEL_DEFAULT 0 - -/* JRS - default congestion control module sysctl */ -#define SCTPCTL_DEFAULT_CC_MODULE_DESC "Default congestion control module" -#define SCTPCTL_DEFAULT_CC_MODULE_MIN 0 -#define SCTPCTL_DEFAULT_CC_MODULE_MAX 2 -#define SCTPCTL_DEFAULT_CC_MODULE_DEFAULT 0 - -/* RS - default stream scheduling module sysctl */ -#define SCTPCTL_DEFAULT_SS_MODULE_DESC "Default stream scheduling module" -#define SCTPCTL_DEFAULT_SS_MODULE_MIN 0 -#define SCTPCTL_DEFAULT_SS_MODULE_MAX 5 -#define SCTPCTL_DEFAULT_SS_MODULE_DEFAULT 0 - -/* RRS - default fragment interleave */ -#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC "Default fragment interleave level" -#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN 0 -#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX 2 -#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT 1 - -/* mobility_base: Enable SCTP mobility support */ -#define SCTPCTL_MOBILITY_BASE_DESC "Enable SCTP base mobility" -#define SCTPCTL_MOBILITY_BASE_MIN 0 -#define SCTPCTL_MOBILITY_BASE_MAX 1 -#define SCTPCTL_MOBILITY_BASE_DEFAULT 0 - -/* mobility_fasthandoff: Enable SCTP fast handoff support */ -#define SCTPCTL_MOBILITY_FASTHANDOFF_DESC "Enable SCTP fast handoff" -#define SCTPCTL_MOBILITY_FASTHANDOFF_MIN 0 -#define SCTPCTL_MOBILITY_FASTHANDOFF_MAX 1 -#define SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT 0 - -/* Enable SCTP/UDP tunneling port */ -#define SCTPCTL_UDP_TUNNELING_PORT_DESC "Set the SCTP/UDP tunneling port" -#define SCTPCTL_UDP_TUNNELING_PORT_MIN 0 -#define SCTPCTL_UDP_TUNNELING_PORT_MAX 65535 -#if defined(__FreeBSD__) && !defined(__Userspace__) -#define SCTPCTL_UDP_TUNNELING_PORT_DEFAULT 0 -#else -#define SCTPCTL_UDP_TUNNELING_PORT_DEFAULT SCTP_OVER_UDP_TUNNELING_PORT -#endif - -/* Enable sending of the SACK-IMMEDIATELY bit */ -#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC "Enable sending of the SACK-IMMEDIATELY-bit" -#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN 0 -#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX 1 -#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX - -/* Enable sending of the NAT-FRIENDLY message */ -#define SCTPCTL_NAT_FRIENDLY_INITS_DESC "Enable sending of the nat-friendly SCTP option on INITs" -#define SCTPCTL_NAT_FRIENDLY_INITS_MIN 0 -#define SCTPCTL_NAT_FRIENDLY_INITS_MAX 1 -#define SCTPCTL_NAT_FRIENDLY_INITS_DEFAULT SCTPCTL_NAT_FRIENDLY_INITS_MIN - -/* Vtag time wait in seconds */ -#define SCTPCTL_TIME_WAIT_DESC "Vtag time wait time in seconds, 0 disables it" -#define SCTPCTL_TIME_WAIT_MIN 0 -#define SCTPCTL_TIME_WAIT_MAX 0xffffffff -#define SCTPCTL_TIME_WAIT_DEFAULT SCTP_TIME_WAIT - -/* Enable Send/Receive buffer splitting */ -#define SCTPCTL_BUFFER_SPLITTING_DESC "Enable send/receive buffer splitting" -#define SCTPCTL_BUFFER_SPLITTING_MIN 0 -#define SCTPCTL_BUFFER_SPLITTING_MAX 0x3 -#define SCTPCTL_BUFFER_SPLITTING_DEFAULT SCTPCTL_BUFFER_SPLITTING_MIN - -/* Initial congestion window in MTUs */ -#define SCTPCTL_INITIAL_CWND_DESC "Defines the initial congestion window size in MTUs" -#define SCTPCTL_INITIAL_CWND_MIN 0 -#define SCTPCTL_INITIAL_CWND_MAX 0xffffffff -#define SCTPCTL_INITIAL_CWND_DEFAULT 3 - -/* rttvar smooth avg for bw calc */ -#define SCTPCTL_RTTVAR_BW_DESC "Shift amount DCCC uses for bw smoothing on rtt calc" -#define SCTPCTL_RTTVAR_BW_MIN 0 -#define SCTPCTL_RTTVAR_BW_MAX 32 -#define SCTPCTL_RTTVAR_BW_DEFAULT 4 - -/* rttvar smooth avg for bw calc */ -#define SCTPCTL_RTTVAR_RTT_DESC "Shift amount DCCC uses for rtt smoothing on rtt calc" -#define SCTPCTL_RTTVAR_RTT_MIN 0 -#define SCTPCTL_RTTVAR_RTT_MAX 32 -#define SCTPCTL_RTTVAR_RTT_DEFAULT 5 - -#define SCTPCTL_RTTVAR_EQRET_DESC "Whether DCCC increases cwnd when the rtt and bw are unchanged" -#define SCTPCTL_RTTVAR_EQRET_MIN 0 -#define SCTPCTL_RTTVAR_EQRET_MAX 1 -#define SCTPCTL_RTTVAR_EQRET_DEFAULT 0 - -#define SCTPCTL_RTTVAR_STEADYS_DESC "Number of identical bw measurements DCCC takes to try step down of cwnd" -#define SCTPCTL_RTTVAR_STEADYS_MIN 0 -#define SCTPCTL_RTTVAR_STEADYS_MAX 0xFFFF -#define SCTPCTL_RTTVAR_STEADYS_DEFAULT 20 /* 0 means disable feature */ - -#define SCTPCTL_RTTVAR_DCCCECN_DESC "Enable ECN for DCCC." -#define SCTPCTL_RTTVAR_DCCCECN_MIN 0 -#define SCTPCTL_RTTVAR_DCCCECN_MAX 1 -#define SCTPCTL_RTTVAR_DCCCECN_DEFAULT 1 /* 0 means disable feature */ - -#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing, see blackhole(4) for more details" -#define SCTPCTL_BLACKHOLE_MIN 0 -#define SCTPCTL_BLACKHOLE_MAX 2 -#define SCTPCTL_BLACKHOLE_DEFAULT SCTPCTL_BLACKHOLE_MIN - -/* sendall_limit: Maximum message with SCTP_SENDALL */ -#define SCTPCTL_SENDALL_LIMIT_DESC "Maximum size of a message send with SCTP_SENDALL" -#define SCTPCTL_SENDALL_LIMIT_MIN 0 -#define SCTPCTL_SENDALL_LIMIT_MAX 0xFFFFFFFF -#define SCTPCTL_SENDALL_LIMIT_DEFAULT 1432 - -#define SCTPCTL_DIAG_INFO_CODE_DESC "Diagnostic information error cause code" -#define SCTPCTL_DIAG_INFO_CODE_MIN 0 -#define SCTPCTL_DIAG_INFO_CODE_MAX 65535 -#define SCTPCTL_DIAG_INFO_CODE_DEFAULT 0 - -#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DESC "Accept OOTB packets with zero checksum" -#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MIN 0 -#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX 1 -#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT 0 - -#if defined(SCTP_DEBUG) -/* debug: Configure debug output */ -#define SCTPCTL_DEBUG_DESC "Configure debug output" -#define SCTPCTL_DEBUG_MIN 0 -#define SCTPCTL_DEBUG_MAX 0xFFFFFFFF -#define SCTPCTL_DEBUG_DEFAULT 0 -#endif - -#if defined(__APPLE__) && !defined(__Userspace__) -#define SCTPCTL_MAIN_TIMER_DESC "Main timer interval in ms" -#define SCTPCTL_MAIN_TIMER_MIN 1 -#define SCTPCTL_MAIN_TIMER_MAX 0xFFFFFFFF -#define SCTPCTL_MAIN_TIMER_DEFAULT 10 - -#define SCTPCTL_IGNORE_VMWARE_INTERFACES_DESC "Ignore VMware Interfaces" -#define SCTPCTL_IGNORE_VMWARE_INTERFACES_MIN 0 -#define SCTPCTL_IGNORE_VMWARE_INTERFACES_MAX 1 -#define SCTPCTL_IGNORE_VMWARE_INTERFACES_DEFAULT SCTPCTL_IGNORE_VMWARE_INTERFACES_MAX - -#define SCTPCTL_OUTPUT_UNLOCKED_DESC "Unlock socket when sending packets down to IP" -#define SCTPCTL_OUTPUT_UNLOCKED_MIN 0 -#define SCTPCTL_OUTPUT_UNLOCKED_MAX 1 -#define SCTPCTL_OUTPUT_UNLOCKED_DEFAULT SCTPCTL_OUTPUT_UNLOCKED_MIN - -#define SCTPCTL_ADDR_WATCHDOG_LIMIT_DESC "Address watchdog limit" -#define SCTPCTL_ADDR_WATCHDOG_LIMIT_MIN 0 -#define SCTPCTL_ADDR_WATCHDOG_LIMIT_MAX 0xFFFFFFFF -#define SCTPCTL_ADDR_WATCHDOG_LIMIT_DEFAULT SCTPCTL_ADDR_WATCHDOG_LIMIT_MIN - -#define SCTPCTL_VTAG_WATCHDOG_LIMIT_DESC "VTag watchdog limit" -#define SCTPCTL_VTAG_WATCHDOG_LIMIT_MIN 0 -#define SCTPCTL_VTAG_WATCHDOG_LIMIT_MAX 0xFFFFFFFF -#define SCTPCTL_VTAG_WATCHDOG_LIMIT_DEFAULT SCTPCTL_VTAG_WATCHDOG_LIMIT_MIN - -#endif -#if defined(_KERNEL) || defined(__Userspace__) -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) -#if defined(SYSCTL_DECL) -SYSCTL_DECL(_net_inet_sctp); -#endif -#endif - -void sctp_init_sysctls(void); -#if defined(_WIN32) && !defined(__Userspace__) -void sctp_finish_sysctls(void); -#endif - -#endif /* _KERNEL */ -#endif /* __sctp_sysctl_h__ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.c deleted file mode 100644 index aa44dad6..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.c +++ /dev/null @@ -1,1641 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#define _IP_VHL -#include -#include -#ifdef INET6 -#if defined(__FreeBSD__) && defined(__Userspace__) -#include -#endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(INET) || defined(INET6) -#if !(defined(_WIN32) && defined(__Userspace__)) -#include -#endif -#endif - -void -sctp_audit_retranmission_queue(struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *chk; - - SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n", - asoc->sent_queue_retran_cnt, - asoc->sent_queue_cnt); - asoc->sent_queue_retran_cnt = 0; - asoc->sent_queue_cnt = 0; - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - if (chk->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - } - asoc->sent_queue_cnt++; - } - TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { - if (chk->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - } - } - TAILQ_FOREACH(chk, &asoc->asconf_send_queue, sctp_next) { - if (chk->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - } - } - SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n", - asoc->sent_queue_retran_cnt, - asoc->sent_queue_cnt); -} - -static int -sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net, uint16_t threshold) -{ - if (net) { - net->error_count++; - SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", - (void *)net, net->error_count, - net->failure_threshold); - if (net->error_count > net->failure_threshold) { - /* We had a threshold failure */ - if (net->dest_state & SCTP_ADDR_REACHABLE) { - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; - net->dest_state &= ~SCTP_ADDR_PF; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, 0, - (void *)net, SCTP_SO_NOT_LOCKED); - } - } else if ((net->pf_threshold < net->failure_threshold) && - (net->error_count > net->pf_threshold)) { - if ((net->dest_state & SCTP_ADDR_PF) == 0) { - net->dest_state |= SCTP_ADDR_PF; - net->last_active = sctp_get_tick_count(); - sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - inp, stcb, net, - SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); - } - } - } - if (stcb == NULL) - return (0); - - if (net) { - if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_INCR, - stcb->asoc.overall_error_count, - (stcb->asoc.overall_error_count+1), - SCTP_FROM_SCTP_TIMER, - __LINE__); - } - stcb->asoc.overall_error_count++; - } - } else { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { - sctp_misc_ints(SCTP_THRESHOLD_INCR, - stcb->asoc.overall_error_count, - (stcb->asoc.overall_error_count+1), - SCTP_FROM_SCTP_TIMER, - __LINE__); - } - stcb->asoc.overall_error_count++; - } - SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", - (void *)&stcb->asoc, stcb->asoc.overall_error_count, - (uint32_t)threshold, - ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state)); - /* - * We specifically do not do >= to give the assoc one more change - * before we fail it. - */ - if (stcb->asoc.overall_error_count > threshold) { - /* Abort notification sends a ULP notify */ - struct mbuf *op_err; - - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Association error counter exceeded"); - inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_2; - sctp_abort_an_association(inp, stcb, op_err, true, SCTP_SO_NOT_LOCKED); - return (1); - } - return (0); -} - -/* - * sctp_find_alternate_net() returns a non-NULL pointer as long as there - * exists nets, which are not being deleted. - */ -struct sctp_nets * -sctp_find_alternate_net(struct sctp_tcb *stcb, - struct sctp_nets *net, - int mode) -{ - /* Find and return an alternate network if possible */ - struct sctp_nets *alt, *mnet, *min_errors_net = NULL , *max_cwnd_net = NULL; - bool looped; - /* JRS 5/14/07 - Initialize min_errors to an impossible value. */ - int min_errors = -1; - uint32_t max_cwnd = 0; - - if (stcb->asoc.numnets == 1) { - /* No selection can be made. */ - return (TAILQ_FIRST(&stcb->asoc.nets)); - } - /* - * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate net algorithm. - * This algorithm chooses the active destination (not in PF state) with the largest - * cwnd value. If all destinations are in PF state, unreachable, or unconfirmed, choose - * the destination that is in PF state with the lowest error count. In case of a tie, - * choose the destination that was most recently active. - */ - if (mode == 2) { - TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { - /* JRS 5/14/07 - If the destination is unreachable or unconfirmed, skip it. */ - if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || - (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { - continue; - } - /* - * JRS 5/14/07 - If the destination is reachable but in PF state, compare - * the error count of the destination to the minimum error count seen thus far. - * Store the destination with the lower error count. If the error counts are - * equal, store the destination that was most recently active. - */ - if (mnet->dest_state & SCTP_ADDR_PF) { - /* - * JRS 5/14/07 - If the destination under consideration is the current - * destination, work as if the error count is one higher. The - * actual error count will not be incremented until later in the - * t3 handler. - */ - if (mnet == net) { - if (min_errors == -1) { - min_errors = mnet->error_count + 1; - min_errors_net = mnet; - } else if (mnet->error_count + 1 < min_errors) { - min_errors = mnet->error_count + 1; - min_errors_net = mnet; - } else if (mnet->error_count + 1 == min_errors - && mnet->last_active > min_errors_net->last_active) { - min_errors_net = mnet; - min_errors = mnet->error_count + 1; - } - continue; - } else { - if (min_errors == -1) { - min_errors = mnet->error_count; - min_errors_net = mnet; - } else if (mnet->error_count < min_errors) { - min_errors = mnet->error_count; - min_errors_net = mnet; - } else if (mnet->error_count == min_errors - && mnet->last_active > min_errors_net->last_active) { - min_errors_net = mnet; - min_errors = mnet->error_count; - } - continue; - } - } - /* - * JRS 5/14/07 - If the destination is reachable and not in PF state, compare the - * cwnd of the destination to the highest cwnd seen thus far. Store the - * destination with the higher cwnd value. If the cwnd values are equal, - * randomly choose one of the two destinations. - */ - if (max_cwnd < mnet->cwnd) { - max_cwnd_net = mnet; - max_cwnd = mnet->cwnd; - } else if (max_cwnd == mnet->cwnd) { - uint32_t rndval; - uint8_t this_random; - - if (stcb->asoc.hb_random_idx > 3) { - rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); - memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values)); - this_random = stcb->asoc.hb_random_values[0]; - stcb->asoc.hb_random_idx++; - stcb->asoc.hb_ect_randombit = 0; - } else { - this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; - stcb->asoc.hb_random_idx++; - stcb->asoc.hb_ect_randombit = 0; - } - if (this_random % 2 == 1) { - max_cwnd_net = mnet; - max_cwnd = mnet->cwnd; /* Useless? */ - } - } - } - if (max_cwnd_net == NULL) { - if (min_errors_net == NULL) { - return (net); - } - return (min_errors_net); - } else { - return (max_cwnd_net); - } - } /* JRS 5/14/07 - If mode is set to 1, use the CMT policy for choosing an alternate net. */ - else if (mode == 1) { - TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { - if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || - (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { - /* - * will skip ones that are not-reachable or - * unconfirmed - */ - continue; - } - if (max_cwnd < mnet->cwnd) { - max_cwnd_net = mnet; - max_cwnd = mnet->cwnd; - } else if (max_cwnd == mnet->cwnd) { - uint32_t rndval; - uint8_t this_random; - - if (stcb->asoc.hb_random_idx > 3) { - rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); - memcpy(stcb->asoc.hb_random_values, &rndval, - sizeof(stcb->asoc.hb_random_values)); - this_random = stcb->asoc.hb_random_values[0]; - stcb->asoc.hb_random_idx = 0; - stcb->asoc.hb_ect_randombit = 0; - } else { - this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; - stcb->asoc.hb_random_idx++; - stcb->asoc.hb_ect_randombit = 0; - } - if (this_random % 2) { - max_cwnd_net = mnet; - max_cwnd = mnet->cwnd; - } - } - } - if (max_cwnd_net) { - return (max_cwnd_net); - } - } - /* Look for an alternate net, which is active. */ - if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) { - alt = TAILQ_NEXT(net, sctp_next); - } else { - alt = TAILQ_FIRST(&stcb->asoc.nets); - } - looped = false; - for (;;) { - if (alt == NULL) { - if (!looped) { - alt = TAILQ_FIRST(&stcb->asoc.nets); - looped = true; - } - /* Definitely out of candidates. */ - if (alt == NULL) { - break; - } - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (alt->ro.ro_nh == NULL) { -#else - if (alt->ro.ro_rt == NULL) { -#endif - if (alt->ro._s_addr) { - sctp_free_ifa(alt->ro._s_addr); - alt->ro._s_addr = NULL; - } - alt->src_addr_selected = 0; - } - if (((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && -#if defined(__FreeBSD__) && !defined(__Userspace__) - (alt->ro.ro_nh != NULL) && -#else - (alt->ro.ro_rt != NULL) && -#endif - ((alt->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) && - (alt != net)) { - /* Found an alternate net, which is reachable. */ - break; - } - alt = TAILQ_NEXT(alt, sctp_next); - } - - if (alt == NULL) { - /* - * In case no active alternate net has been found, look for - * an alternate net, which is confirmed. - */ - if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) { - alt = TAILQ_NEXT(net, sctp_next); - } else { - alt = TAILQ_FIRST(&stcb->asoc.nets); - } - looped = false; - for (;;) { - if (alt == NULL) { - if (!looped) { - alt = TAILQ_FIRST(&stcb->asoc.nets); - looped = true; - } - /* Definitely out of candidates. */ - if (alt == NULL) { - break; - } - } - if (((alt->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) && - (alt != net)) { - /* Found an alternate net, which is confirmed. */ - break; - } - alt = TAILQ_NEXT(alt, sctp_next); - } - } - if (alt == NULL) { - /* - * In case no confirmed alternate net has been found, just - * return net, if it is not being deleted. In the other case - * just return the first net. - */ - if ((net != NULL) && ((net->dest_state & SCTP_ADDR_BEING_DELETED) == 0)) { - alt = net; - } - if (alt == NULL) { - alt = TAILQ_FIRST(&stcb->asoc.nets); - } - } - return (alt); -} - -static void -sctp_backoff_on_timeout(struct sctp_tcb *stcb, - struct sctp_nets *net, - int win_probe, - int num_marked, int num_abandoned) -{ - if (net->RTO == 0) { - if (net->RTO_measured) { - net->RTO = stcb->asoc.minrto; - } else { - net->RTO = stcb->asoc.initial_rto; - } - } - net->RTO <<= 1; - if (net->RTO > stcb->asoc.maxrto) { - net->RTO = stcb->asoc.maxrto; - } - if ((win_probe == 0) && (num_marked || num_abandoned)) { - /* We don't apply penalty to window probe scenarios */ - /* JRS - Use the congestion control given in the CC module */ - stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); - } -} - -#ifndef INVARIANTS -static void -sctp_recover_sent_list(struct sctp_tcb *stcb) -{ - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_association *asoc; - - asoc = &stcb->asoc; - TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { - if (SCTP_TSN_GE(asoc->last_acked_seq, chk->rec.data.tsn)) { - SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n", - (void *)chk, chk->rec.data.tsn, asoc->last_acked_seq); - if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { - if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[chk->rec.data.sid].chunks_on_queues--; - } - } - if ((asoc->strmout[chk->rec.data.sid].chunks_on_queues == 0) && - (asoc->strmout[chk->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && - TAILQ_EMPTY(&asoc->strmout[chk->rec.data.sid].outqueue)) { - asoc->trigger_reset = 1; - } - TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); - if (PR_SCTP_ENABLED(chk->flags)) { - if (asoc->pr_sctp_cnt != 0) - asoc->pr_sctp_cnt--; - } - if (chk->data) { - /*sa_ignore NO_NULL_CHK*/ - sctp_free_bufspace(stcb, asoc, chk, 1); - sctp_m_freem(chk->data); - chk->data = NULL; - if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(chk->flags)) { - asoc->sent_queue_cnt_removeable--; - } - } - asoc->sent_queue_cnt--; - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - } - SCTP_PRINTF("after recover order is as follows\n"); - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - SCTP_PRINTF("chk:%p TSN:%x\n", (void *)chk, chk->rec.data.tsn); - } -} -#endif - -static int -sctp_mark_all_for_resend(struct sctp_tcb *stcb, - struct sctp_nets *net, - struct sctp_nets *alt, - int window_probe, - int *num_marked, - int *num_abandoned) -{ - - /* - * Mark all chunks (well not all) that were sent to *net for - * retransmission. Move them to alt for there destination as well... - * We only mark chunks that have been outstanding long enough to - * have received feed-back. - */ - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_nets *lnets; - struct timeval now, min_wait, tv; - int cur_rto; - int cnt_abandoned; - int audit_tf, num_mk, fir; - unsigned int cnt_mk; - uint32_t orig_flight, orig_tf; - uint32_t tsnlast, tsnfirst; -#ifndef INVARIANTS - int recovery_cnt = 0; -#endif - - /* none in flight now */ - audit_tf = 0; - fir = 0; - /* - * figure out how long a data chunk must be pending before we can - * mark it .. - */ - (void)SCTP_GETTIME_TIMEVAL(&now); - /* get cur rto in micro-seconds */ - cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - cur_rto *= 1000; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(cur_rto, - stcb->asoc.peers_rwnd, - window_probe, - SCTP_FR_T3_MARK_TIME); - sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT); - sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); - } - tv.tv_sec = cur_rto / 1000000; - tv.tv_usec = cur_rto % 1000000; -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - timersub(&now, &tv, &min_wait); -#else - min_wait = now; - timevalsub(&min_wait, &tv); -#endif - if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { - /* - * if we hit here, we don't have enough seconds on the clock - * to account for the RTO. We just let the lower seconds be - * the bounds and don't worry about it. This may mean we - * will mark a lot more than we should. - */ - min_wait.tv_sec = min_wait.tv_usec = 0; - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(cur_rto, (uint32_t)now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); - sctp_log_fr(0, (uint32_t)min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); - } - /* - * Our rwnd will be incorrect here since we are not adding back the - * cnt * mbuf but we will fix that down below. - */ - orig_flight = net->flight_size; - orig_tf = stcb->asoc.total_flight; - - net->fast_retran_ip = 0; - /* Now on to each chunk */ - cnt_abandoned = 0; - num_mk = cnt_mk = 0; - tsnfirst = tsnlast = 0; -#ifndef INVARIANTS - start_again: -#endif - TAILQ_FOREACH_SAFE(chk, &stcb->asoc.sent_queue, sctp_next, nchk) { - if (SCTP_TSN_GE(stcb->asoc.last_acked_seq, chk->rec.data.tsn)) { - /* Strange case our list got out of order? */ - SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x\n", - (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.tsn); -#ifdef INVARIANTS - panic("last acked >= chk on sent-Q"); -#else - recovery_cnt++; - SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt); - sctp_recover_sent_list(stcb); - if (recovery_cnt < 10) { - goto start_again; - } else { - SCTP_PRINTF("Recovery fails %d times??\n", recovery_cnt); - } -#endif - } - if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) { - /* - * found one to mark: If it is less than - * DATAGRAM_ACKED it MUST not be a skipped or marked - * TSN but instead one that is either already set - * for retransmission OR one that needs - * retransmission. - */ - - /* validate its been outstanding long enough */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(chk->rec.data.tsn, - (uint32_t)chk->sent_rcv_time.tv_sec, - chk->sent_rcv_time.tv_usec, - SCTP_FR_T3_MARK_TIME); - } - if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) { - /* - * we have reached a chunk that was sent - * some seconds past our min.. forget it we - * will find no more to send. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(0, - (uint32_t)chk->sent_rcv_time.tv_sec, - chk->sent_rcv_time.tv_usec, - SCTP_FR_T3_STOPPED); - } - continue; - } else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) && - (window_probe == 0)) { - /* - * we must look at the micro seconds to - * know. - */ - if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { - /* - * ok it was sent after our boundary - * time. - */ - continue; - } - } - if (stcb->asoc.prsctp_supported && PR_SCTP_TTL_ENABLED(chk->flags)) { - /* Is it expired? */ -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (timercmp(&now, &chk->rec.data.timetodrop, >)) { -#else - if (timevalcmp(&now, &chk->rec.data.timetodrop, >)) { -#endif - /* Yes so drop it */ - if (chk->data) { - (void)sctp_release_pr_sctp_chunk(stcb, - chk, - 1, - SCTP_SO_NOT_LOCKED); - cnt_abandoned++; - } - continue; - } - } - if (stcb->asoc.prsctp_supported && PR_SCTP_RTX_ENABLED(chk->flags)) { - /* Has it been retransmitted tv_sec times? */ - if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) { - if (chk->data) { - (void)sctp_release_pr_sctp_chunk(stcb, - chk, - 1, - SCTP_SO_NOT_LOCKED); - cnt_abandoned++; - } - continue; - } - } - if (chk->sent < SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - num_mk++; - if (fir == 0) { - fir = 1; - tsnfirst = chk->rec.data.tsn; - } - tsnlast = chk->rec.data.tsn; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(chk->rec.data.tsn, chk->snd_count, - 0, SCTP_FR_T3_MARKED); - } - - if (chk->rec.data.chunk_was_revoked) { - /* deflate the cwnd */ - chk->whoTo->cwnd -= chk->book_size; - chk->rec.data.chunk_was_revoked = 0; - } - net->marked_retrans++; - stcb->asoc.marked_retrans++; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, - chk->whoTo->flight_size, - chk->book_size, - (uint32_t)(uintptr_t)chk->whoTo, - chk->rec.data.tsn); - } - sctp_flight_size_decrease(chk); - sctp_total_flight_decrease(stcb, chk); - stcb->asoc.peers_rwnd += chk->send_size; - stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); - } - chk->sent = SCTP_DATAGRAM_RESEND; - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - SCTP_STAT_INCR(sctps_markedretrans); - - /* reset the TSN for striking and other FR stuff */ - chk->rec.data.doing_fast_retransmit = 0; - /* Clear any time so NO RTT is being done */ - - if (chk->do_rtt) { - if (chk->whoTo->rto_needed == 0) { - chk->whoTo->rto_needed = 1; - } - } - chk->do_rtt = 0; - if (alt != net) { - sctp_free_remote_addr(chk->whoTo); - chk->no_fr_allowed = 1; - chk->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } else { - chk->no_fr_allowed = 0; - if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { - chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; - } else { - chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.tsn; - } - } - /* CMT: Do not allow FRs on retransmitted TSNs. - */ - if (stcb->asoc.sctp_cmt_on_off > 0) { - chk->no_fr_allowed = 1; - } -#ifdef THIS_SHOULD_NOT_BE_DONE - } else if (chk->sent == SCTP_DATAGRAM_ACKED) { - /* remember highest acked one */ - could_be_sent = chk; -#endif - } - if (chk->sent == SCTP_DATAGRAM_RESEND) { - cnt_mk++; - } - } - if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) { - /* we did not subtract the same things? */ - audit_tf = 1; - } - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); - } -#ifdef SCTP_DEBUG - if (num_mk) { - SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", - tsnlast); - SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%u\n", - num_mk, - stcb->asoc.peers_rwnd); - } -#endif - *num_marked = num_mk; - *num_abandoned = cnt_abandoned; - /* Now check for a ECN Echo that may be stranded And - * include the cnt_mk'd to have all resends in the - * control queue. - */ - TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { - if (chk->sent == SCTP_DATAGRAM_RESEND) { - cnt_mk++; - } - if ((chk->whoTo == net) && - (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = alt; - if (chk->sent != SCTP_DATAGRAM_RESEND) { - chk->sent = SCTP_DATAGRAM_RESEND; - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - cnt_mk++; - } - atomic_add_int(&alt->ref_count, 1); - } - } -#ifdef THIS_SHOULD_NOT_BE_DONE - if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { - /* fix it so we retransmit the highest acked anyway */ - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - cnt_mk++; - could_be_sent->sent = SCTP_DATAGRAM_RESEND; - } -#endif - if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { -#ifdef INVARIANTS - SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", - cnt_mk, stcb->asoc.sent_queue_retran_cnt, num_mk); -#endif -#ifndef SCTP_AUDITING_ENABLED - stcb->asoc.sent_queue_retran_cnt = cnt_mk; -#endif - } - if (audit_tf) { - SCTPDBG(SCTP_DEBUG_TIMER4, - "Audit total flight due to negative value net:%p\n", - (void *)net); - stcb->asoc.total_flight = 0; - stcb->asoc.total_flight_count = 0; - /* Clear all networks flight size */ - TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) { - lnets->flight_size = 0; - SCTPDBG(SCTP_DEBUG_TIMER4, - "Net:%p c-f cwnd:%d ssthresh:%d\n", - (void *)lnets, lnets->cwnd, lnets->ssthresh); - } - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->sent < SCTP_DATAGRAM_RESEND) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_UP, - chk->whoTo->flight_size, - chk->book_size, - (uint32_t)(uintptr_t)chk->whoTo, - chk->rec.data.tsn); - } - - sctp_flight_size_increase(chk); - sctp_total_flight_increase(stcb, chk); - } - } - } - /* We return 1 if we only have a window probe outstanding */ - return (0); -} - -int -sctp_t3rxt_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_nets *alt; - int win_probe, num_mk, num_abandoned; - - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { - sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - struct sctp_nets *lnet; - - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - if (net == lnet) { - sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3); - } else { - sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3); - } - } - } - /* Find an alternate and mark those for retransmission */ - if ((stcb->asoc.peers_rwnd == 0) && - (stcb->asoc.total_flight < net->mtu)) { - SCTP_STAT_INCR(sctps_timowindowprobe); - win_probe = 1; - } else { - win_probe = 0; - } - - if (win_probe == 0) { - /* We don't do normal threshold management on window probes */ - if (sctp_threshold_management(inp, stcb, net, - stcb->asoc.max_send_times)) { - /* Association was destroyed */ - return (1); - } else { - if (net != stcb->asoc.primary_destination) { - /* send a immediate HB if our RTO is stale */ - struct timeval now; - uint32_t ms_goneby; - - (void)SCTP_GETTIME_TIMEVAL(&now); - if (net->last_sent_time.tv_sec) { - ms_goneby = (uint32_t)(now.tv_sec - net->last_sent_time.tv_sec) * 1000; - } else { - ms_goneby = 0; - } - if ((net->dest_state & SCTP_ADDR_PF) == 0) { - if ((ms_goneby > net->RTO) || (net->RTO == 0)) { - /* - * no recent feed back in an RTO or - * more, request a RTT update - */ - sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - } - } - } - } - } else { - /* - * For a window probe we don't penalize the net's but only - * the association. This may fail it if SACKs are not coming - * back. If sack's are coming with rwnd locked at 0, we will - * continue to hold things waiting for rwnd to raise - */ - if (sctp_threshold_management(inp, stcb, NULL, - stcb->asoc.max_send_times)) { - /* Association was destroyed */ - return (1); - } - } - if (stcb->asoc.sctp_cmt_on_off > 0) { - if (net->pf_threshold < net->failure_threshold) { - alt = sctp_find_alternate_net(stcb, net, 2); - } else { - /* - * CMT: Using RTX_SSTHRESH policy for CMT. - * If CMT is being used, then pick dest with - * largest ssthresh for any retransmission. - */ - alt = sctp_find_alternate_net(stcb, net, 1); - /* - * CUCv2: If a different dest is picked for - * the retransmission, then new - * (rtx-)pseudo_cumack needs to be tracked - * for orig dest. Let CUCv2 track new (rtx-) - * pseudo-cumack always. - */ - net->find_pseudo_cumack = 1; - net->find_rtx_pseudo_cumack = 1; - } - } else { - alt = sctp_find_alternate_net(stcb, net, 0); - } - - num_mk = 0; - num_abandoned = 0; - (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, - &num_mk, &num_abandoned); - /* FR Loss recovery just ended with the T3. */ - stcb->asoc.fast_retran_loss_recovery = 0; - - /* CMT FR loss recovery ended with the T3 */ - net->fast_retran_loss_recovery = 0; - if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && - (net->flight_size == 0)) { - (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins)(stcb, net); - } - - /* - * setup the sat loss recovery that prevents satellite cwnd advance. - */ - stcb->asoc.sat_t3_loss_recovery = 1; - stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; - - /* Backoff the timer and cwnd */ - sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); - if (((net->dest_state & SCTP_ADDR_REACHABLE) == 0) || - (net->dest_state & SCTP_ADDR_PF)) { - /* Move all pending over too */ - sctp_move_chunks_from_net(stcb, net); - - /* Get the address that failed, to - * force a new src address selection and - * a route allocation. - */ - if (net->ro._s_addr != NULL) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - } - net->src_addr_selected = 0; - - /* Force a route allocation too */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - RO_NHFREE(&net->ro); -#else - if (net->ro.ro_rt != NULL) { - RTFREE(net->ro.ro_rt); - net->ro.ro_rt = NULL; - } -#endif - - /* Was it our primary? */ - if ((stcb->asoc.primary_destination == net) && (alt != net)) { - /* - * Yes, note it as such and find an alternate note: - * this means HB code must use this to resent the - * primary if it goes active AND if someone does a - * change-primary then this flag must be cleared - * from any net structures. - */ - if (stcb->asoc.alternate != NULL) { - sctp_free_remote_addr(stcb->asoc.alternate); - } - stcb->asoc.alternate = alt; - atomic_add_int(&stcb->asoc.alternate->ref_count, 1); - } - } - /* - * Special case for cookie-echo'ed case, we don't do output but must - * await the COOKIE-ACK before retransmission - */ - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) { - /* - * Here we just reset the timer and start again since we - * have not established the asoc - */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - return (0); - } - if (stcb->asoc.prsctp_supported) { - struct sctp_tmit_chunk *lchk; - - lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc); - /* C3. See if we need to send a Fwd-TSN */ - if (SCTP_TSN_GT(stcb->asoc.advanced_peer_ack_point, stcb->asoc.last_acked_seq)) { - send_forward_tsn(stcb, &stcb->asoc); - for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) { - if (lchk->whoTo != NULL) { - break; - } - } - if (lchk != NULL) { - /* Assure a timer is up */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo); - } - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX); - } - return (0); -} - -int -sctp_t1init_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - /* bump the thresholds */ - if (stcb->asoc.delayed_connection) { - /* - * special hook for delayed connection. The library did NOT - * complete the rest of its sends. - */ - stcb->asoc.delayed_connection = 0; - sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); - return (0); - } - if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) { - return (0); - } - if (sctp_threshold_management(inp, stcb, net, - stcb->asoc.max_init_times)) { - /* Association was destroyed */ - return (1); - } - stcb->asoc.dropped_special_cnt = 0; - sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0); - if (stcb->asoc.initial_init_rto_max < net->RTO) { - net->RTO = stcb->asoc.initial_init_rto_max; - } - if (stcb->asoc.numnets > 1) { - /* If we have more than one addr use it */ - struct sctp_nets *alt; - - alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); - if (alt != stcb->asoc.primary_destination) { - sctp_move_chunks_from_net(stcb, stcb->asoc.primary_destination); - stcb->asoc.primary_destination = alt; - } - } - /* Send out a new init */ - sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); - return (0); -} - -/* - * For cookie and asconf we actually need to find and mark for resend, then - * increment the resend counter (after all the threshold management stuff of - * course). - */ -int -sctp_cookie_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net SCTP_UNUSED) -{ - struct sctp_nets *alt; - struct sctp_tmit_chunk *cookie; - - /* first before all else we must find the cookie */ - TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) { - if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { - break; - } - } - if (cookie == NULL) { - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) { - /* FOOBAR! */ - struct mbuf *op_err; - - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Cookie timer expired, but no cookie"); - inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3; - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_NOT_LOCKED); - } else { -#ifdef INVARIANTS - panic("Cookie timer expires in wrong state?"); -#else - SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(stcb)); - return (0); -#endif - } - return (0); - } - /* Ok we found the cookie, threshold management next */ - if (sctp_threshold_management(inp, stcb, cookie->whoTo, - stcb->asoc.max_init_times)) { - /* Assoc is over */ - return (1); - } - /* - * Cleared threshold management, now lets backoff the address - * and select an alternate - */ - stcb->asoc.dropped_special_cnt = 0; - sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); - alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); - if (alt != cookie->whoTo) { - sctp_free_remote_addr(cookie->whoTo); - cookie->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } - /* Now mark the retran info */ - if (cookie->sent != SCTP_DATAGRAM_RESEND) { - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - } - cookie->sent = SCTP_DATAGRAM_RESEND; - cookie->flags |= CHUNK_FLAGS_FRAGMENT_OK; - /* - * Now call the output routine to kick out the cookie again, Note we - * don't mark any chunks for retran so that FR will need to kick in - * to move these (or a send timer). - */ - return (0); -} - -int -sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb) -{ - struct sctp_nets *alt, *net; - struct sctp_tmit_chunk *strrst = NULL, *chk = NULL; - - if (stcb->asoc.stream_reset_outstanding == 0) { - return (0); - } - /* find the existing STRRESET, we use the seq number we sent out on */ - (void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst); - if (strrst == NULL) { - return (0); - } - net = strrst->whoTo; - /* do threshold management */ - if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { - /* Assoc is over */ - return (1); - } - /* - * Cleared threshold management, now lets backoff the address - * and select an alternate - */ - sctp_backoff_on_timeout(stcb, net, 1, 0, 0); - alt = sctp_find_alternate_net(stcb, net, 0); - strrst->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - - /* See if a ECN Echo is also stranded */ - TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { - if ((chk->whoTo == net) && - (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { - sctp_free_remote_addr(chk->whoTo); - if (chk->sent != SCTP_DATAGRAM_RESEND) { - chk->sent = SCTP_DATAGRAM_RESEND; - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - } - chk->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } - } - if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { - /* - * If the address went un-reachable, we need to move to - * alternates for ALL chk's in queue - */ - sctp_move_chunks_from_net(stcb, net); - } - sctp_free_remote_addr(net); - - /* mark the retran info */ - if (strrst->sent != SCTP_DATAGRAM_RESEND) - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - strrst->sent = SCTP_DATAGRAM_RESEND; - strrst->flags |= CHUNK_FLAGS_FRAGMENT_OK; - - /* restart the timer */ - sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, alt); - return (0); -} - -int -sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_nets *alt; - struct sctp_tmit_chunk *asconf, *chk; - - /* is this a first send, or a retransmission? */ - if (TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) { - /* compose a new ASCONF chunk and send it */ - sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); - } else { - /* - * Retransmission of the existing ASCONF is needed - */ - - /* find the existing ASCONF */ - asconf = TAILQ_FIRST(&stcb->asoc.asconf_send_queue); - if (asconf == NULL) { - return (0); - } - net = asconf->whoTo; - /* do threshold management */ - if (sctp_threshold_management(inp, stcb, net, - stcb->asoc.max_send_times)) { - /* Assoc is over */ - return (1); - } - if (asconf->snd_count > stcb->asoc.max_send_times) { - /* - * Something is rotten: our peer is not responding to - * ASCONFs but apparently is to other chunks. i.e. it - * is not properly handling the chunk type upper bits. - * Mark this peer as ASCONF incapable and cleanup. - */ - SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n"); - sctp_asconf_cleanup(stcb); - return (0); - } - /* - * cleared threshold management, so now backoff the net and - * select an alternate - */ - sctp_backoff_on_timeout(stcb, net, 1, 0, 0); - alt = sctp_find_alternate_net(stcb, net, 0); - if (asconf->whoTo != alt) { - asconf->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } - - /* See if an ECN Echo is also stranded */ - TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { - if ((chk->whoTo == net) && - (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = alt; - if (chk->sent != SCTP_DATAGRAM_RESEND) { - chk->sent = SCTP_DATAGRAM_RESEND; - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - } - atomic_add_int(&alt->ref_count, 1); - } - } - TAILQ_FOREACH(chk, &stcb->asoc.asconf_send_queue, sctp_next) { - if (chk->whoTo != alt) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } - if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT) - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - chk->sent = SCTP_DATAGRAM_RESEND; - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - } - if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { - /* - * If the address went un-reachable, we need to move - * to the alternate for ALL chunks in queue - */ - sctp_move_chunks_from_net(stcb, net); - } - sctp_free_remote_addr(net); - - /* mark the retran info */ - if (asconf->sent != SCTP_DATAGRAM_RESEND) - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - asconf->sent = SCTP_DATAGRAM_RESEND; - asconf->flags |= CHUNK_FLAGS_FRAGMENT_OK; - - /* send another ASCONF if any and we can do */ - sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED); - } - return (0); -} - -/* Mobility adaptation */ -void -sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb) -{ - if (stcb->asoc.deleted_primary == NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n"); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); - return; - } - SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); - sctp_free_remote_addr(stcb->asoc.deleted_primary); - stcb->asoc.deleted_primary = NULL; - sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); - return; -} - -/* - * For the shutdown and shutdown-ack, we do not keep one around on the - * control queue. This means we must generate a new one and call the general - * chunk output routine, AFTER having done threshold management. - * It is assumed that net is non-NULL. - */ -int -sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_nets *alt; - - /* first threshold management */ - if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { - /* Assoc is over */ - return (1); - } - sctp_backoff_on_timeout(stcb, net, 1, 0, 0); - /* second select an alternative */ - alt = sctp_find_alternate_net(stcb, net, 0); - - /* third generate a shutdown into the queue for out net */ - sctp_send_shutdown(stcb, alt); - - /* fourth restart timer */ - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt); - return (0); -} - -int -sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_nets *alt; - - /* first threshold management */ - if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { - /* Assoc is over */ - return (1); - } - sctp_backoff_on_timeout(stcb, net, 1, 0, 0); - /* second select an alternative */ - alt = sctp_find_alternate_net(stcb, net, 0); - - /* third generate a shutdown into the queue for out net */ - sctp_send_shutdown_ack(stcb, alt); - - /* fourth restart timer */ - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt); - return (0); -} - -static void -sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, struct sctp_tcb *stcb) -{ - struct sctp_stream_queue_pending *sp; - unsigned int i, chks_in_queue = 0; - int being_filled = 0; - - KASSERT(inp != NULL, ("inp is NULL")); - KASSERT(stcb != NULL, ("stcb is NULL")); - SCTP_TCB_LOCK_ASSERT(stcb); - KASSERT(TAILQ_EMPTY(&stcb->asoc.send_queue), ("send_queue not empty")); - KASSERT(TAILQ_EMPTY(&stcb->asoc.sent_queue), ("sent_queue not empty")); - - if (stcb->asoc.sent_queue_retran_cnt) { - SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", - stcb->asoc.sent_queue_retran_cnt); - stcb->asoc.sent_queue_retran_cnt = 0; - } - if (stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { - /* No stream scheduler information, initialize scheduler */ - stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); - if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { - /* yep, we lost a stream or two */ - SCTP_PRINTF("Found additional streams NOT managed by scheduler, corrected\n"); - } else { - /* no streams lost */ - stcb->asoc.total_output_queue_size = 0; - } - } - /* Check to see if some data queued, if so report it */ - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - TAILQ_FOREACH(sp, &stcb->asoc.strmout[i].outqueue, next) { - if (sp->msg_is_complete) - being_filled++; - chks_in_queue++; - } - } - } - if (chks_in_queue != stcb->asoc.stream_queue_cnt) { - SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", - stcb->asoc.stream_queue_cnt, chks_in_queue); - } - if (chks_in_queue) { - /* call the output queue function */ - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); - if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) && - (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { - /* - * Probably should go in and make it go back through - * and add fragments allowed - */ - if (being_filled == 0) { - SCTP_PRINTF("Still nothing moved %d chunks are stuck\n", - chks_in_queue); - } - } - } else { - SCTP_PRINTF("Found no chunks on any queue tot:%lu\n", - (u_long)stcb->asoc.total_output_queue_size); - stcb->asoc.total_output_queue_size = 0; - } -} - -int -sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - bool net_was_pf; - - net_was_pf = (net->dest_state & SCTP_ADDR_PF) != 0; - if (net->hb_responded == 0) { - if (net->ro._s_addr != NULL) { - /* Invalidate the src address if we did not get - * a response last time. - */ - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } - sctp_backoff_on_timeout(stcb, net, 1, 0, 0); - if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { - /* Assoc is over */ - return (1); - } - } - /* Zero PBA, if it needs it */ - if (net->partial_bytes_acked > 0) { - net->partial_bytes_acked = 0; - } - if ((stcb->asoc.total_output_queue_size > 0) && - (TAILQ_EMPTY(&stcb->asoc.send_queue)) && - (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { - sctp_audit_stream_queues_for_size(inp, stcb); - } - if ((((net->dest_state & SCTP_ADDR_NOHB) == 0) || - (net->dest_state & SCTP_ADDR_UNCONFIRMED)) && - (net_was_pf || ((net->dest_state & SCTP_ADDR_PF) == 0))) { - /* When moving to PF during threshold management, a HB has been - queued in that routine. */ - uint32_t ms_gone_by; - - if ((net->last_sent_time.tv_sec > 0) || - (net->last_sent_time.tv_usec > 0)) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct timeval diff; - - SCTP_GETTIME_TIMEVAL(&diff); - timevalsub(&diff, &net->last_sent_time); -#else - struct timeval diff, now; - - SCTP_GETTIME_TIMEVAL(&now); - timersub(&now, &net->last_sent_time, &diff); -#endif - ms_gone_by = (uint32_t)(diff.tv_sec * 1000) + - (uint32_t)(diff.tv_usec / 1000); - } else { - ms_gone_by = 0xffffffff; - } - if ((ms_gone_by >= net->heart_beat_delay) || - (net->dest_state & SCTP_ADDR_UNCONFIRMED) || - (net->dest_state & SCTP_ADDR_PF)) { - sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - } - } - return (0); -} - -void -sctp_pathmtu_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - uint32_t next_mtu, mtu; - - next_mtu = sctp_get_next_mtu(net->mtu); - - if ((next_mtu > net->mtu) && (net->port == 0)) { - if ((net->src_addr_selected == 0) || - (net->ro._s_addr == NULL) || - (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { - if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } else if (net->ro._s_addr == NULL) { -#if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) - if (net->ro._l_addr.sa.sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; - /* KAME hack: embed scopeid */ -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) - (void)in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL); -#else - (void)in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL); -#endif -#elif defined(SCTP_KAME) - (void)sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)); -#else - (void)in6_embedscope(&sin6->sin6_addr, sin6); -#endif - } -#endif - - net->ro._s_addr = sctp_source_address_selection(inp, - stcb, - (sctp_route_t *)&net->ro, - net, 0, stcb->asoc.vrf_id); -#if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) - if (net->ro._l_addr.sa.sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; -#ifdef SCTP_KAME - (void)sa6_recoverscope(sin6); -#else - (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); -#endif /* SCTP_KAME */ - } -#endif /* INET6 */ - } - if (net->ro._s_addr) - net->src_addr_selected = 1; - } - if (net->ro._s_addr) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_nh); -#else - mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt); -#endif -#if defined(INET) || defined(INET6) - if (net->port) { - mtu -= sizeof(struct udphdr); - } -#endif - if (mtu > next_mtu) { - net->mtu = next_mtu; - } else { - net->mtu = mtu; - } - } - } - /* restart the timer */ - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); -} - -void -sctp_autoclose_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb) -{ - struct timeval tn, *tim_touse; - struct sctp_association *asoc; - uint32_t ticks_gone_by; - - (void)SCTP_GETTIME_TIMEVAL(&tn); - if (stcb->asoc.sctp_autoclose_ticks > 0 && - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { - /* Auto close is on */ - asoc = &stcb->asoc; - /* pick the time to use */ - if (asoc->time_last_rcvd.tv_sec > - asoc->time_last_sent.tv_sec) { - tim_touse = &asoc->time_last_rcvd; - } else { - tim_touse = &asoc->time_last_sent; - } - /* Now has long enough transpired to autoclose? */ - ticks_gone_by = sctp_secs_to_ticks((uint32_t)(tn.tv_sec - tim_touse->tv_sec)); - if (ticks_gone_by >= asoc->sctp_autoclose_ticks) { - /* - * autoclose time has hit, call the output routine, - * which should do nothing just to be SURE we don't - * have hanging data. We can then safely check the - * queues and know that we are clear to send - * shutdown - */ - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); - /* Are we clean? */ - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue)) { - /* - * there is nothing queued to send, so I'm - * done... - */ - if (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) { - /* only send SHUTDOWN 1st time thru */ - struct sctp_nets *net; - - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (stcb->asoc.alternate) { - net = stcb->asoc.alternate; - } else { - net = stcb->asoc.primary_destination; - } - sctp_send_shutdown(stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, net); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); - } - } - } else { - /* - * No auto close at this time, reset t-o to check - * later - */ - uint32_t tmp; - - /* fool the timer startup to use the time left */ - tmp = asoc->sctp_autoclose_ticks; - asoc->sctp_autoclose_ticks -= ticks_gone_by; - sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); - /* restore the real tick value */ - asoc->sctp_autoclose_ticks = tmp; - } - } -} - diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.h deleted file mode 100644 index 0fe9c03b..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_timer.h +++ /dev/null @@ -1,103 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_TIMER_H_ -#define _NETINET_SCTP_TIMER_H_ - -#if defined(_KERNEL) || defined(__Userspace__) - -#define SCTP_RTT_SHIFT 3 -#define SCTP_RTT_VAR_SHIFT 2 - -struct sctp_nets * -sctp_find_alternate_net(struct sctp_tcb *, struct sctp_nets *, int); - -int -sctp_t3rxt_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -int -sctp_t1init_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -int -sctp_shutdown_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -int -sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -int -sctp_cookie_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -void -sctp_pathmtu_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -int -sctp_shutdownack_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); -int -sctp_strreset_timer(struct sctp_inpcb *, struct sctp_tcb *); - -int -sctp_asconf_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -void -sctp_delete_prim_timer(struct sctp_inpcb *, struct sctp_tcb *); - -void -sctp_autoclose_timer(struct sctp_inpcb *, struct sctp_tcb *); - -void sctp_audit_retranmission_queue(struct sctp_association *); - -void sctp_iterator_timer(struct sctp_iterator *it); - -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) || defined(APPLE_LION) || defined(APPLE_MOUNTAINLION) -void sctp_slowtimo(void); -#else -void sctp_gc(struct inpcbinfo *); -#endif -#endif -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_uio.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_uio.h deleted file mode 100644 index 068d4fd2..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_uio.h +++ /dev/null @@ -1,1358 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_UIO_H_ -#define _NETINET_SCTP_UIO_H_ - -#if (defined(__APPLE__) && !defined(__Userspace__) && defined(KERNEL)) -#ifndef _KERNEL -#define _KERNEL -#endif -#endif -#if !defined(_WIN32) -#if !defined(_KERNEL) -#include -#endif -#include -#include -#include -#endif -#if defined(_WIN32) && !defined(__Userspace__) -#pragma warning(push) -#pragma warning(disable: 4200) -#if defined(_KERNEL) -#include -#include -#include -#endif -#endif - -typedef uint32_t sctp_assoc_t; - -#define SCTP_FUTURE_ASSOC 0 -#define SCTP_CURRENT_ASSOC 1 -#define SCTP_ALL_ASSOC 2 - -struct sctp_event { - sctp_assoc_t se_assoc_id; - uint16_t se_type; - uint8_t se_on; -}; - -/* Compatibility to previous define's */ -#define sctp_stream_reset_events sctp_stream_reset_event - -/* On/Off setup for subscription to events */ -struct sctp_event_subscribe { - uint8_t sctp_data_io_event; - uint8_t sctp_association_event; - uint8_t sctp_address_event; - uint8_t sctp_send_failure_event; - uint8_t sctp_peer_error_event; - uint8_t sctp_shutdown_event; - uint8_t sctp_partial_delivery_event; - uint8_t sctp_adaptation_layer_event; - uint8_t sctp_authentication_event; - uint8_t sctp_sender_dry_event; - uint8_t sctp_stream_reset_event; -}; - -/* ancillary data types */ -#define SCTP_INIT 0x0001 -#define SCTP_SNDRCV 0x0002 -#define SCTP_EXTRCV 0x0003 -#define SCTP_SNDINFO 0x0004 -#define SCTP_RCVINFO 0x0005 -#define SCTP_NXTINFO 0x0006 -#define SCTP_PRINFO 0x0007 -#define SCTP_AUTHINFO 0x0008 -#define SCTP_DSTADDRV4 0x0009 -#define SCTP_DSTADDRV6 0x000a - -/* - * ancillary data structures - */ -struct sctp_initmsg { - uint16_t sinit_num_ostreams; - uint16_t sinit_max_instreams; - uint16_t sinit_max_attempts; - uint16_t sinit_max_init_timeo; -}; - -/* We add 96 bytes to the size of sctp_sndrcvinfo. - * This makes the current structure 128 bytes long - * which is nicely 64 bit aligned but also has room - * for us to add more and keep ABI compatibility. - * For example, already we have the sctp_extrcvinfo - * when enabled which is 48 bytes. - */ - -/* - * The assoc up needs a verfid - * all sendrcvinfo's need a verfid for SENDING only. - */ - -#define SCTP_ALIGN_RESV_PAD 92 -#define SCTP_ALIGN_RESV_PAD_SHORT 76 - -struct sctp_sndrcvinfo { - uint16_t sinfo_stream; - uint16_t sinfo_ssn; - uint16_t sinfo_flags; - uint32_t sinfo_ppid; - uint32_t sinfo_context; - uint32_t sinfo_timetolive; - uint32_t sinfo_tsn; - uint32_t sinfo_cumtsn; - sctp_assoc_t sinfo_assoc_id; - uint16_t sinfo_keynumber; - uint16_t sinfo_keynumber_valid; - uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD]; -}; - -struct sctp_extrcvinfo { - uint16_t sinfo_stream; - uint16_t sinfo_ssn; - uint16_t sinfo_flags; - uint32_t sinfo_ppid; - uint32_t sinfo_context; - uint32_t sinfo_timetolive; /* should have been sinfo_pr_value */ - uint32_t sinfo_tsn; - uint32_t sinfo_cumtsn; - sctp_assoc_t sinfo_assoc_id; - uint16_t serinfo_next_flags; - uint16_t serinfo_next_stream; - uint32_t serinfo_next_aid; - uint32_t serinfo_next_length; - uint32_t serinfo_next_ppid; - uint16_t sinfo_keynumber; - uint16_t sinfo_keynumber_valid; - uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD_SHORT]; -}; -#define sinfo_pr_value sinfo_timetolive -#define sreinfo_next_flags serinfo_next_flags -#define sreinfo_next_stream serinfo_next_stream -#define sreinfo_next_aid serinfo_next_aid -#define sreinfo_next_length serinfo_next_length -#define sreinfo_next_ppid serinfo_next_ppid - -struct sctp_sndinfo { - uint16_t snd_sid; - uint16_t snd_flags; - uint32_t snd_ppid; - uint32_t snd_context; - sctp_assoc_t snd_assoc_id; -}; - -struct sctp_prinfo { - uint16_t pr_policy; - uint32_t pr_value; -}; - -struct sctp_default_prinfo { - uint16_t pr_policy; - uint32_t pr_value; - sctp_assoc_t pr_assoc_id; -}; - -struct sctp_authinfo { - uint16_t auth_keynumber; -}; - -struct sctp_rcvinfo { - uint16_t rcv_sid; - uint16_t rcv_ssn; - uint16_t rcv_flags; - uint32_t rcv_ppid; - uint32_t rcv_tsn; - uint32_t rcv_cumtsn; - uint32_t rcv_context; - sctp_assoc_t rcv_assoc_id; -}; - -struct sctp_nxtinfo { - uint16_t nxt_sid; - uint16_t nxt_flags; - uint32_t nxt_ppid; - uint32_t nxt_length; - sctp_assoc_t nxt_assoc_id; -}; - -#define SCTP_NO_NEXT_MSG 0x0000 -#define SCTP_NEXT_MSG_AVAIL 0x0001 -#define SCTP_NEXT_MSG_ISCOMPLETE 0x0002 -#define SCTP_NEXT_MSG_IS_UNORDERED 0x0004 -#define SCTP_NEXT_MSG_IS_NOTIFICATION 0x0008 - -struct sctp_recvv_rn { - struct sctp_rcvinfo recvv_rcvinfo; - struct sctp_nxtinfo recvv_nxtinfo; -}; - -#define SCTP_RECVV_NOINFO 0 -#define SCTP_RECVV_RCVINFO 1 -#define SCTP_RECVV_NXTINFO 2 -#define SCTP_RECVV_RN 3 - -#define SCTP_SENDV_NOINFO 0 -#define SCTP_SENDV_SNDINFO 1 -#define SCTP_SENDV_PRINFO 2 -#define SCTP_SENDV_AUTHINFO 3 -#define SCTP_SENDV_SPA 4 - -struct sctp_sendv_spa { - uint32_t sendv_flags; - struct sctp_sndinfo sendv_sndinfo; - struct sctp_prinfo sendv_prinfo; - struct sctp_authinfo sendv_authinfo; -}; - -#define SCTP_SEND_SNDINFO_VALID 0x00000001 -#define SCTP_SEND_PRINFO_VALID 0x00000002 -#define SCTP_SEND_AUTHINFO_VALID 0x00000004 - -struct sctp_snd_all_completes { - uint16_t sall_stream; - uint16_t sall_flags; - uint32_t sall_ppid; - uint32_t sall_context; - uint32_t sall_num_sent; - uint32_t sall_num_failed; -}; - -/* Flags that go into the sinfo->sinfo_flags field */ -#define SCTP_NOTIFICATION 0x0010 /* next message is a notification */ -#define SCTP_COMPLETE 0x0020 /* next message is complete */ -#define SCTP_EOF 0x0100 /* Start shutdown procedures */ -#define SCTP_ABORT 0x0200 /* Send an ABORT to peer */ -#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */ -#define SCTP_ADDR_OVER 0x0800 /* Override the primary-address */ -#define SCTP_SENDALL 0x1000 /* Send this on all associations */ -#define SCTP_EOR 0x2000 /* end of message signal */ -#define SCTP_SACK_IMMEDIATELY 0x4000 /* Set I-Bit */ - -#define INVALID_SINFO_FLAG(x) (((x) & 0xfffffff0 \ - & ~(SCTP_EOF | SCTP_ABORT | SCTP_UNORDERED |\ - SCTP_ADDR_OVER | SCTP_SENDALL | SCTP_EOR |\ - SCTP_SACK_IMMEDIATELY)) != 0) -/* for the endpoint */ - -/* The lower four bits is an enumeration of PR-SCTP policies */ -#define SCTP_PR_SCTP_NONE 0x0000 /* Reliable transfer */ -#define SCTP_PR_SCTP_TTL 0x0001 /* Time based PR-SCTP */ -#define SCTP_PR_SCTP_PRIO 0x0002 /* Buffer based PR-SCTP */ -#define SCTP_PR_SCTP_BUF SCTP_PR_SCTP_PRIO /* For backwards compatibility */ -#define SCTP_PR_SCTP_RTX 0x0003 /* Number of retransmissions based PR-SCTP */ -#define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_RTX -#define SCTP_PR_SCTP_ALL 0x000f /* Used for aggregated stats */ - -#define PR_SCTP_POLICY(x) ((x) & 0x0f) -#define PR_SCTP_ENABLED(x) ((PR_SCTP_POLICY(x) != SCTP_PR_SCTP_NONE) && \ - (PR_SCTP_POLICY(x) != SCTP_PR_SCTP_ALL)) -#define PR_SCTP_TTL_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_TTL) -#define PR_SCTP_BUF_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_BUF) -#define PR_SCTP_RTX_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_RTX) -#define PR_SCTP_INVALID_POLICY(x) (PR_SCTP_POLICY(x) > SCTP_PR_SCTP_MAX) -#define PR_SCTP_VALID_POLICY(x) (PR_SCTP_POLICY(x) <= SCTP_PR_SCTP_MAX) - -/* Stat's */ -struct sctp_pcbinfo { - uint32_t ep_count; - uint32_t asoc_count; - uint32_t laddr_count; - uint32_t raddr_count; - uint32_t chk_count; - uint32_t readq_count; - uint32_t free_chunks; - uint32_t stream_oque; -}; - -struct sctp_sockstat { - sctp_assoc_t ss_assoc_id; - uint32_t ss_total_sndbuf; - uint32_t ss_total_recv_buf; -}; - -/* - * notification event structures - */ - -/* - * association change event - */ -struct sctp_assoc_change { - uint16_t sac_type; - uint16_t sac_flags; - uint32_t sac_length; - uint16_t sac_state; - uint16_t sac_error; - uint16_t sac_outbound_streams; - uint16_t sac_inbound_streams; - sctp_assoc_t sac_assoc_id; - uint8_t sac_info[]; -}; - -/* sac_state values */ -#define SCTP_COMM_UP 0x0001 -#define SCTP_COMM_LOST 0x0002 -#define SCTP_RESTART 0x0003 -#define SCTP_SHUTDOWN_COMP 0x0004 -#define SCTP_CANT_STR_ASSOC 0x0005 - -/* sac_info values */ -#define SCTP_ASSOC_SUPPORTS_PR 0x01 -#define SCTP_ASSOC_SUPPORTS_AUTH 0x02 -#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03 -#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04 -#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05 -#define SCTP_ASSOC_SUPPORTS_INTERLEAVING 0x06 -#define SCTP_ASSOC_SUPPORTS_MAX 0x06 -/* - * Address event - */ -struct sctp_paddr_change { - uint16_t spc_type; - uint16_t spc_flags; - uint32_t spc_length; - struct sockaddr_storage spc_aaddr; - uint32_t spc_state; - uint32_t spc_error; - sctp_assoc_t spc_assoc_id; -}; - -/* paddr state values */ -#define SCTP_ADDR_AVAILABLE 0x0001 -#define SCTP_ADDR_UNREACHABLE 0x0002 -#define SCTP_ADDR_REMOVED 0x0003 -#define SCTP_ADDR_ADDED 0x0004 -#define SCTP_ADDR_MADE_PRIM 0x0005 -#define SCTP_ADDR_CONFIRMED 0x0006 - -#define SCTP_ACTIVE 0x0001 /* SCTP_ADDR_REACHABLE */ -#define SCTP_INACTIVE 0x0002 /* neither SCTP_ADDR_REACHABLE - nor SCTP_ADDR_UNCONFIRMED */ -#define SCTP_UNCONFIRMED 0x0200 /* SCTP_ADDR_UNCONFIRMED */ - -/* remote error events */ -struct sctp_remote_error { - uint16_t sre_type; - uint16_t sre_flags; - uint32_t sre_length; - uint16_t sre_error; - sctp_assoc_t sre_assoc_id; - uint8_t sre_data[]; -}; - -/* data send failure event (deprecated) */ -struct sctp_send_failed { - uint16_t ssf_type; - uint16_t ssf_flags; - uint32_t ssf_length; - uint32_t ssf_error; - struct sctp_sndrcvinfo ssf_info; - sctp_assoc_t ssf_assoc_id; - uint8_t ssf_data[]; -}; - -/* data send failure event (not deprecated) */ -struct sctp_send_failed_event { - uint16_t ssfe_type; - uint16_t ssfe_flags; - uint32_t ssfe_length; - uint32_t ssfe_error; - struct sctp_sndinfo ssfe_info; - sctp_assoc_t ssfe_assoc_id; - uint8_t ssfe_data[]; -}; - -/* flag that indicates state of data */ -#define SCTP_DATA_UNSENT 0x0001 /* inqueue never on wire */ -#define SCTP_DATA_SENT 0x0002 /* on wire at failure */ - -/* shutdown event */ -struct sctp_shutdown_event { - uint16_t sse_type; - uint16_t sse_flags; - uint32_t sse_length; - sctp_assoc_t sse_assoc_id; -}; - -/* Adaptation layer indication stuff */ -struct sctp_adaptation_event { - uint16_t sai_type; - uint16_t sai_flags; - uint32_t sai_length; - uint32_t sai_adaptation_ind; - sctp_assoc_t sai_assoc_id; -}; - -struct sctp_setadaptation { - uint32_t ssb_adaptation_ind; -}; - -/* compatible old spelling */ -struct sctp_adaption_event { - uint16_t sai_type; - uint16_t sai_flags; - uint32_t sai_length; - uint32_t sai_adaption_ind; - sctp_assoc_t sai_assoc_id; -}; - -struct sctp_setadaption { - uint32_t ssb_adaption_ind; -}; - -/* - * Partial Delivery API event - */ -struct sctp_pdapi_event { - uint16_t pdapi_type; - uint16_t pdapi_flags; - uint32_t pdapi_length; - uint32_t pdapi_indication; - uint16_t pdapi_stream; - uint16_t pdapi_seq; - sctp_assoc_t pdapi_assoc_id; -}; - -/* indication values */ -#define SCTP_PARTIAL_DELIVERY_ABORTED 0x0001 - -/* - * authentication key event - */ -struct sctp_authkey_event { - uint16_t auth_type; - uint16_t auth_flags; - uint32_t auth_length; - uint16_t auth_keynumber; - uint16_t auth_altkeynumber; - uint32_t auth_indication; - sctp_assoc_t auth_assoc_id; -}; - -/* indication values */ -#define SCTP_AUTH_NEW_KEY 0x0001 -#define SCTP_AUTH_NEWKEY SCTP_AUTH_NEW_KEY -#define SCTP_AUTH_NO_AUTH 0x0002 -#define SCTP_AUTH_FREE_KEY 0x0003 - -struct sctp_sender_dry_event { - uint16_t sender_dry_type; - uint16_t sender_dry_flags; - uint32_t sender_dry_length; - sctp_assoc_t sender_dry_assoc_id; -}; - -/* - * Stream reset event - subscribe to SCTP_STREAM_RESET_EVENT - */ -struct sctp_stream_reset_event { - uint16_t strreset_type; - uint16_t strreset_flags; - uint32_t strreset_length; - sctp_assoc_t strreset_assoc_id; - uint16_t strreset_stream_list[]; -}; - -/* flags in stream_reset_event (strreset_flags) */ -#define SCTP_STREAM_RESET_INCOMING_SSN 0x0001 -#define SCTP_STREAM_RESET_OUTGOING_SSN 0x0002 -#define SCTP_STREAM_RESET_DENIED 0x0004 -#define SCTP_STREAM_RESET_FAILED 0x0008 - -/* - * Assoc reset event - subscribe to SCTP_ASSOC_RESET_EVENT - */ -struct sctp_assoc_reset_event { - uint16_t assocreset_type; - uint16_t assocreset_flags; - uint32_t assocreset_length; - sctp_assoc_t assocreset_assoc_id; - uint32_t assocreset_local_tsn; - uint32_t assocreset_remote_tsn; -}; - -#define SCTP_ASSOC_RESET_DENIED 0x0004 -#define SCTP_ASSOC_RESET_FAILED 0x0008 - -/* - * Stream change event - subscribe to SCTP_STREAM_CHANGE_EVENT - */ -struct sctp_stream_change_event { - uint16_t strchange_type; - uint16_t strchange_flags; - uint32_t strchange_length; - sctp_assoc_t strchange_assoc_id; - uint16_t strchange_instrms; - uint16_t strchange_outstrms; -}; - -#define SCTP_STREAM_CHANGE_DENIED 0x0004 -#define SCTP_STREAM_CHANGE_FAILED 0x0008 - -/* SCTP notification event */ -struct sctp_tlv { - uint16_t sn_type; - uint16_t sn_flags; - uint32_t sn_length; -}; - -union sctp_notification { - struct sctp_tlv sn_header; - struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_paddr_change; - struct sctp_remote_error sn_remote_error; - struct sctp_send_failed sn_send_failed; - struct sctp_shutdown_event sn_shutdown_event; - struct sctp_adaptation_event sn_adaptation_event; - /* compatibility same as above */ - struct sctp_adaption_event sn_adaption_event; - struct sctp_pdapi_event sn_pdapi_event; - struct sctp_authkey_event sn_auth_event; - struct sctp_sender_dry_event sn_sender_dry_event; - struct sctp_send_failed_event sn_send_failed_event; - struct sctp_stream_reset_event sn_strreset_event; - struct sctp_assoc_reset_event sn_assocreset_event; - struct sctp_stream_change_event sn_strchange_event; -}; - -/* notification types */ -#define SCTP_ASSOC_CHANGE 0x0001 -#define SCTP_PEER_ADDR_CHANGE 0x0002 -#define SCTP_REMOTE_ERROR 0x0003 -#define SCTP_SEND_FAILED 0x0004 -#define SCTP_SHUTDOWN_EVENT 0x0005 -#define SCTP_ADAPTATION_INDICATION 0x0006 -/* same as above */ -#define SCTP_ADAPTION_INDICATION 0x0006 -#define SCTP_PARTIAL_DELIVERY_EVENT 0x0007 -#define SCTP_AUTHENTICATION_EVENT 0x0008 -#define SCTP_STREAM_RESET_EVENT 0x0009 -#define SCTP_SENDER_DRY_EVENT 0x000a -#define SCTP_NOTIFICATIONS_STOPPED_EVENT 0x000b /* we don't send this*/ -#define SCTP_ASSOC_RESET_EVENT 0x000c -#define SCTP_STREAM_CHANGE_EVENT 0x000d -#define SCTP_SEND_FAILED_EVENT 0x000e -/* - * socket option structs - */ - -struct sctp_paddrparams { - struct sockaddr_storage spp_address; - sctp_assoc_t spp_assoc_id; - uint32_t spp_hbinterval; - uint32_t spp_pathmtu; - uint32_t spp_flags; - uint32_t spp_ipv6_flowlabel; - uint16_t spp_pathmaxrxt; - uint8_t spp_dscp; -}; -#define spp_ipv4_tos spp_dscp - -#define SPP_HB_ENABLE 0x00000001 -#define SPP_HB_DISABLE 0x00000002 -#define SPP_HB_DEMAND 0x00000004 -#define SPP_PMTUD_ENABLE 0x00000008 -#define SPP_PMTUD_DISABLE 0x00000010 -#define SPP_HB_TIME_IS_ZERO 0x00000080 -#define SPP_IPV6_FLOWLABEL 0x00000100 -#define SPP_DSCP 0x00000200 -#define SPP_IPV4_TOS SPP_DSCP - -struct sctp_paddrthlds { - struct sockaddr_storage spt_address; - sctp_assoc_t spt_assoc_id; - uint16_t spt_pathmaxrxt; - uint16_t spt_pathpfthld; - uint16_t spt_pathcpthld; -}; - -struct sctp_paddrinfo { - struct sockaddr_storage spinfo_address; - sctp_assoc_t spinfo_assoc_id; - int32_t spinfo_state; - uint32_t spinfo_cwnd; - uint32_t spinfo_srtt; - uint32_t spinfo_rto; - uint32_t spinfo_mtu; -}; - -struct sctp_rtoinfo { - sctp_assoc_t srto_assoc_id; - uint32_t srto_initial; - uint32_t srto_max; - uint32_t srto_min; -}; - -struct sctp_assocparams { - sctp_assoc_t sasoc_assoc_id; - uint32_t sasoc_peer_rwnd; - uint32_t sasoc_local_rwnd; - uint32_t sasoc_cookie_life; - uint16_t sasoc_asocmaxrxt; - uint16_t sasoc_number_peer_destinations; -}; - -struct sctp_setprim { - struct sockaddr_storage ssp_addr; - sctp_assoc_t ssp_assoc_id; - uint8_t ssp_padding[4]; -}; - -struct sctp_setpeerprim { - struct sockaddr_storage sspp_addr; - sctp_assoc_t sspp_assoc_id; - uint8_t sspp_padding[4]; -}; - -union sctp_sockstore { - struct sockaddr_in sin; - struct sockaddr_in6 sin6; -#if defined(__Userspace__) - struct sockaddr_conn sconn; -#endif - struct sockaddr sa; -}; - -struct sctp_getaddresses { - sctp_assoc_t sget_assoc_id; - union sctp_sockstore addr[]; -}; - -struct sctp_status { - sctp_assoc_t sstat_assoc_id; - int32_t sstat_state; - uint32_t sstat_rwnd; - uint16_t sstat_unackdata; - uint16_t sstat_penddata; - uint16_t sstat_instrms; - uint16_t sstat_outstrms; - uint32_t sstat_fragmentation_point; - struct sctp_paddrinfo sstat_primary; -}; - -/* - * AUTHENTICATION support - */ -/* SCTP_AUTH_CHUNK */ -struct sctp_authchunk { - uint8_t sauth_chunk; -}; - -/* SCTP_AUTH_KEY */ -struct sctp_authkey { - sctp_assoc_t sca_assoc_id; - uint16_t sca_keynumber; - uint16_t sca_keylength; - uint8_t sca_key[]; -}; - -/* SCTP_HMAC_IDENT */ -struct sctp_hmacalgo { - uint32_t shmac_number_of_idents; - uint16_t shmac_idents[]; -}; - -/* AUTH hmac_id */ -#define SCTP_AUTH_HMAC_ID_RSVD 0x0000 -#define SCTP_AUTH_HMAC_ID_SHA1 0x0001 /* default, mandatory */ -#define SCTP_AUTH_HMAC_ID_SHA256 0x0003 - -/* SCTP_AUTH_ACTIVE_KEY / SCTP_AUTH_DELETE_KEY */ -struct sctp_authkeyid { - sctp_assoc_t scact_assoc_id; - uint16_t scact_keynumber; -}; - -/* SCTP_PEER_AUTH_CHUNKS / SCTP_LOCAL_AUTH_CHUNKS */ -struct sctp_authchunks { - sctp_assoc_t gauth_assoc_id; - uint32_t gauth_number_of_chunks; - uint8_t gauth_chunks[]; -}; - -struct sctp_assoc_value { - sctp_assoc_t assoc_id; - uint32_t assoc_value; -}; - -struct sctp_cc_option { - int option; - struct sctp_assoc_value aid_value; -}; - -struct sctp_stream_value { - sctp_assoc_t assoc_id; - uint16_t stream_id; - uint16_t stream_value; -}; - -struct sctp_assoc_ids { - uint32_t gaids_number_of_ids; - sctp_assoc_t gaids_assoc_id[]; -}; - -struct sctp_sack_info { - sctp_assoc_t sack_assoc_id; - uint32_t sack_delay; - uint32_t sack_freq; -}; - -struct sctp_timeouts { - sctp_assoc_t stimo_assoc_id; - uint32_t stimo_init; - uint32_t stimo_data; - uint32_t stimo_sack; - uint32_t stimo_shutdown; - uint32_t stimo_heartbeat; - uint32_t stimo_cookie; - uint32_t stimo_shutdownack; -}; - -struct sctp_udpencaps { - struct sockaddr_storage sue_address; - sctp_assoc_t sue_assoc_id; - uint16_t sue_port; -}; - -struct sctp_prstatus { - sctp_assoc_t sprstat_assoc_id; - uint16_t sprstat_sid; - uint16_t sprstat_policy; - uint64_t sprstat_abandoned_unsent; - uint64_t sprstat_abandoned_sent; -}; - -struct sctp_cwnd_args { - struct sctp_nets *net; /* network to */ /* FIXME: LP64 issue */ - uint32_t cwnd_new_value;/* cwnd in k */ - uint32_t pseudo_cumack; - uint16_t inflight; /* flightsize in k */ - uint16_t cwnd_augment; /* increment to it */ - uint8_t meets_pseudo_cumack; - uint8_t need_new_pseudo_cumack; - uint8_t cnt_in_send; - uint8_t cnt_in_str; -}; - -struct sctp_blk_args { - uint32_t onsb; /* in 1k bytes */ - uint32_t sndlen; /* len of send being attempted */ - uint32_t peer_rwnd; /* rwnd of peer */ - uint16_t send_sent_qcnt;/* chnk cnt */ - uint16_t stream_qcnt; /* chnk cnt */ - uint16_t chunks_on_oque;/* chunks out */ - uint16_t flight_size; /* flight size in k */ -}; - -/* - * Max we can reset in one setting, note this is dictated not by the define - * but the size of a mbuf cluster so don't change this define and think you - * can specify more. You must do multiple resets if you want to reset more - * than SCTP_MAX_EXPLICIT_STR_RESET. - */ -#define SCTP_MAX_EXPLICT_STR_RESET 1000 - -struct sctp_reset_streams { - sctp_assoc_t srs_assoc_id; - uint16_t srs_flags; - uint16_t srs_number_streams; /* 0 == ALL */ - uint16_t srs_stream_list[];/* list if strrst_num_streams is not 0 */ -}; - -struct sctp_add_streams { - sctp_assoc_t sas_assoc_id; - uint16_t sas_instrms; - uint16_t sas_outstrms; -}; - -struct sctp_get_nonce_values { - sctp_assoc_t gn_assoc_id; - uint32_t gn_peers_tag; - uint32_t gn_local_tag; -}; - -/* Values for SCTP_ACCEPT_ZERO_CHECKSUM */ -#define SCTP_EDMID_NONE 0 -#define SCTP_EDMID_LOWER_LAYER_DTLS 1 - -/* Debugging logs */ -struct sctp_str_log { - void *stcb; /* FIXME: LP64 issue */ - uint32_t n_tsn; - uint32_t e_tsn; - uint16_t n_sseq; - uint16_t e_sseq; - uint16_t strm; -}; - -struct sctp_sb_log { - void *stcb; /* FIXME: LP64 issue */ - uint32_t so_sbcc; - uint32_t stcb_sbcc; - uint32_t incr; -}; - -struct sctp_fr_log { - uint32_t largest_tsn; - uint32_t largest_new_tsn; - uint32_t tsn; -}; - -struct sctp_fr_map { - uint32_t base; - uint32_t cum; - uint32_t high; -}; - -struct sctp_rwnd_log { - uint32_t rwnd; - uint32_t send_size; - uint32_t overhead; - uint32_t new_rwnd; -}; - -struct sctp_mbcnt_log { - uint32_t total_queue_size; - uint32_t size_change; - uint32_t total_queue_mb_size; - uint32_t mbcnt_change; -}; - -struct sctp_sack_log { - uint32_t cumack; - uint32_t oldcumack; - uint32_t tsn; - uint16_t numGaps; - uint16_t numDups; -}; - -struct sctp_lock_log { - void *sock; /* FIXME: LP64 issue */ - void *inp; /* FIXME: LP64 issue */ - uint8_t tcb_lock; - uint8_t inp_lock; - uint8_t info_lock; - uint8_t sock_lock; - uint8_t sockrcvbuf_lock; - uint8_t socksndbuf_lock; - uint8_t create_lock; - uint8_t resv; -}; - -struct sctp_rto_log { - void * net; /* FIXME: LP64 issue */ - uint32_t rtt; -}; - -struct sctp_nagle_log { - void *stcb; /* FIXME: LP64 issue */ - uint32_t total_flight; - uint32_t total_in_queue; - uint16_t count_in_queue; - uint16_t count_in_flight; -}; - -struct sctp_sbwake_log { - void *stcb; /* FIXME: LP64 issue */ - uint16_t send_q; - uint16_t sent_q; - uint16_t flight; - uint16_t wake_cnt; - uint8_t stream_qcnt; /* chnk cnt */ - uint8_t chunks_on_oque;/* chunks out */ - uint8_t sbflags; - uint8_t sctpflags; -}; - -struct sctp_misc_info { - uint32_t log1; - uint32_t log2; - uint32_t log3; - uint32_t log4; -}; - -struct sctp_log_closing { - void *inp; /* FIXME: LP64 issue */ - void *stcb; /* FIXME: LP64 issue */ - uint32_t sctp_flags; - uint16_t state; - int16_t loc; -}; - -struct sctp_mbuf_log { - struct mbuf *mp; /* FIXME: LP64 issue */ - caddr_t ext; - caddr_t data; - uint16_t size; - uint8_t refcnt; - uint8_t mbuf_flags; -}; - -struct sctp_cwnd_log { - uint64_t time_event; - uint8_t from; - uint8_t event_type; - uint8_t resv[2]; - union { - struct sctp_log_closing close; - struct sctp_blk_args blk; - struct sctp_cwnd_args cwnd; - struct sctp_str_log strlog; - struct sctp_fr_log fr; - struct sctp_fr_map map; - struct sctp_rwnd_log rwnd; - struct sctp_mbcnt_log mbcnt; - struct sctp_sack_log sack; - struct sctp_lock_log lock; - struct sctp_rto_log rto; - struct sctp_sb_log sb; - struct sctp_nagle_log nagle; - struct sctp_sbwake_log wake; - struct sctp_mbuf_log mb; - struct sctp_misc_info misc; - } x; -}; - -struct sctp_cwnd_log_req { - int32_t num_in_log; /* Number in log */ - int32_t num_ret; /* Number returned */ - int32_t start_at; /* start at this one */ - int32_t end_at; /* end at this one */ - struct sctp_cwnd_log log[]; -}; - -struct sctp_timeval { - uint32_t tv_sec; - uint32_t tv_usec; -}; - -struct sctpstat { - struct sctp_timeval sctps_discontinuitytime; /* sctpStats 18 (TimeStamp) */ - /* MIB according to RFC 3873 */ - uint32_t sctps_currestab; /* sctpStats 1 (Gauge32) */ - uint32_t sctps_activeestab; /* sctpStats 2 (Counter32) */ - uint32_t sctps_restartestab; - uint32_t sctps_collisionestab; - uint32_t sctps_passiveestab; /* sctpStats 3 (Counter32) */ - uint32_t sctps_aborted; /* sctpStats 4 (Counter32) */ - uint32_t sctps_shutdown; /* sctpStats 5 (Counter32) */ - uint32_t sctps_outoftheblue; /* sctpStats 6 (Counter32) */ - uint32_t sctps_checksumerrors; /* sctpStats 7 (Counter32) */ - uint32_t sctps_outcontrolchunks; /* sctpStats 8 (Counter64) */ - uint32_t sctps_outorderchunks; /* sctpStats 9 (Counter64) */ - uint32_t sctps_outunorderchunks; /* sctpStats 10 (Counter64) */ - uint32_t sctps_incontrolchunks; /* sctpStats 11 (Counter64) */ - uint32_t sctps_inorderchunks; /* sctpStats 12 (Counter64) */ - uint32_t sctps_inunorderchunks; /* sctpStats 13 (Counter64) */ - uint32_t sctps_fragusrmsgs; /* sctpStats 14 (Counter64) */ - uint32_t sctps_reasmusrmsgs; /* sctpStats 15 (Counter64) */ - uint32_t sctps_outpackets; /* sctpStats 16 (Counter64) */ - uint32_t sctps_inpackets; /* sctpStats 17 (Counter64) */ - - /* input statistics: */ - uint32_t sctps_recvpackets; /* total input packets */ - uint32_t sctps_recvdatagrams; /* total input datagrams */ - uint32_t sctps_recvpktwithdata; /* total packets that had data */ - uint32_t sctps_recvsacks; /* total input SACK chunks */ - uint32_t sctps_recvdata; /* total input DATA chunks */ - uint32_t sctps_recvdupdata; /* total input duplicate DATA chunks */ - uint32_t sctps_recvheartbeat; /* total input HB chunks */ - uint32_t sctps_recvheartbeatack; /* total input HB-ACK chunks */ - uint32_t sctps_recvecne; /* total input ECNE chunks */ - uint32_t sctps_recvauth; /* total input AUTH chunks */ - uint32_t sctps_recvauthmissing; /* total input chunks missing AUTH */ - uint32_t sctps_recvivalhmacid; /* total number of invalid HMAC ids received */ - uint32_t sctps_recvivalkeyid; /* total number of invalid secret ids received */ - uint32_t sctps_recvauthfailed; /* total number of auth failed */ - uint32_t sctps_recvexpress; /* total fast path receives all one chunk */ - uint32_t sctps_recvexpressm; /* total fast path multi-part data */ - uint32_t sctps_recv_spare; /* formerly sctps_recvnocrc */ - uint32_t sctps_recvswcrc; - uint32_t sctps_recvhwcrc; - - /* output statistics: */ - uint32_t sctps_sendpackets; /* total output packets */ - uint32_t sctps_sendsacks; /* total output SACKs */ - uint32_t sctps_senddata; /* total output DATA chunks */ - uint32_t sctps_sendretransdata; /* total output retransmitted DATA chunks */ - uint32_t sctps_sendfastretrans; /* total output fast retransmitted DATA chunks */ - uint32_t sctps_sendmultfastretrans; /* total FR's that happened more than once - * to same chunk (u-del multi-fr algo). - */ - uint32_t sctps_sendheartbeat; /* total output HB chunks */ - uint32_t sctps_sendecne; /* total output ECNE chunks */ - uint32_t sctps_sendauth; /* total output AUTH chunks FIXME */ - uint32_t sctps_senderrors; /* ip_output error counter */ - uint32_t sctps_send_spare; /* formerly sctps_sendnocrc */ - uint32_t sctps_sendswcrc; - uint32_t sctps_sendhwcrc; - /* PCKDROPREP statistics: */ - uint32_t sctps_pdrpfmbox; /* Packet drop from middle box */ - uint32_t sctps_pdrpfehos; /* P-drop from end host */ - uint32_t sctps_pdrpmbda; /* P-drops with data */ - uint32_t sctps_pdrpmbct; /* P-drops, non-data, non-endhost */ - uint32_t sctps_pdrpbwrpt; /* P-drop, non-endhost, bandwidth rep only */ - uint32_t sctps_pdrpcrupt; /* P-drop, not enough for chunk header */ - uint32_t sctps_pdrpnedat; /* P-drop, not enough data to confirm */ - uint32_t sctps_pdrppdbrk; /* P-drop, where process_chunk_drop said break */ - uint32_t sctps_pdrptsnnf; /* P-drop, could not find TSN */ - uint32_t sctps_pdrpdnfnd; /* P-drop, attempt reverse TSN lookup */ - uint32_t sctps_pdrpdiwnp; /* P-drop, e-host confirms zero-rwnd */ - uint32_t sctps_pdrpdizrw; /* P-drop, midbox confirms no space */ - uint32_t sctps_pdrpbadd; /* P-drop, data did not match TSN */ - uint32_t sctps_pdrpmark; /* P-drop, TSN's marked for Fast Retran */ - /* timeouts */ - uint32_t sctps_timoiterator; /* Number of iterator timers that fired */ - uint32_t sctps_timodata; /* Number of T3 data time outs */ - uint32_t sctps_timowindowprobe; /* Number of window probe (T3) timers that fired */ - uint32_t sctps_timoinit; /* Number of INIT timers that fired */ - uint32_t sctps_timosack; /* Number of sack timers that fired */ - uint32_t sctps_timoshutdown; /* Number of shutdown timers that fired */ - uint32_t sctps_timoheartbeat; /* Number of heartbeat timers that fired */ - uint32_t sctps_timocookie; /* Number of times a cookie timeout fired */ - uint32_t sctps_timosecret; /* Number of times an endpoint changed its cookie secret*/ - uint32_t sctps_timopathmtu; /* Number of PMTU timers that fired */ - uint32_t sctps_timoshutdownack; /* Number of shutdown ack timers that fired */ - uint32_t sctps_timoshutdownguard; /* Number of shutdown guard timers that fired */ - uint32_t sctps_timostrmrst; /* Number of stream reset timers that fired */ - uint32_t sctps_timoearlyfr; /* Number of early FR timers that fired */ - uint32_t sctps_timoasconf; /* Number of times an asconf timer fired */ - uint32_t sctps_timodelprim; /* Number of times a prim_deleted timer fired */ - uint32_t sctps_timoautoclose; /* Number of times auto close timer fired */ - uint32_t sctps_timoassockill; /* Number of asoc free timers expired */ - uint32_t sctps_timoinpkill; /* Number of inp free timers expired */ - /* former early FR counters */ - uint32_t sctps_spare[11]; - /* others */ - uint32_t sctps_hdrops; /* packet shorter than header */ - uint32_t sctps_badsum; /* checksum error */ - uint32_t sctps_noport; /* no endpoint for port */ - uint32_t sctps_badvtag; /* bad v-tag */ - uint32_t sctps_badsid; /* bad SID */ - uint32_t sctps_nomem; /* no memory */ - uint32_t sctps_fastretransinrtt; /* number of multiple FR in a RTT window */ - uint32_t sctps_markedretrans; - uint32_t sctps_naglesent; /* nagle allowed sending */ - uint32_t sctps_naglequeued; /* nagle doesn't allow sending */ - uint32_t sctps_maxburstqueued; /* max burst doesn't allow sending */ - uint32_t sctps_ifnomemqueued; /* look ahead tells us no memory in - * interface ring buffer OR we had a - * send error and are queuing one send. - */ - uint32_t sctps_windowprobed; /* total number of window probes sent */ - uint32_t sctps_lowlevelerr; /* total times an output error causes us - * to clamp down on next user send. - */ - uint32_t sctps_lowlevelerrusr; /* total times sctp_senderrors were caused from - * a user send from a user invoked send not - * a sack response - */ - uint32_t sctps_datadropchklmt; /* Number of in data drops due to chunk limit reached */ - uint32_t sctps_datadroprwnd; /* Number of in data drops due to rwnd limit reached */ - uint32_t sctps_ecnereducedcwnd; /* Number of times a ECN reduced the cwnd */ - uint32_t sctps_vtagexpress; /* Used express lookup via vtag */ - uint32_t sctps_vtagbogus; /* Collision in express lookup. */ - uint32_t sctps_primary_randry; /* Number of times the sender ran dry of user data on primary */ - uint32_t sctps_cmt_randry; /* Same for above */ - uint32_t sctps_slowpath_sack; /* Sacks the slow way */ - uint32_t sctps_wu_sacks_sent; /* Window Update only sacks sent */ - uint32_t sctps_sends_with_flags; /* number of sends with sinfo_flags !=0 */ - uint32_t sctps_sends_with_unord; /* number of unordered sends */ - uint32_t sctps_sends_with_eof; /* number of sends with EOF flag set */ - uint32_t sctps_sends_with_abort; /* number of sends with ABORT flag set */ - uint32_t sctps_protocol_drain_calls; /* number of times protocol drain called */ - uint32_t sctps_protocol_drains_done; /* number of times we did a protocol drain */ - uint32_t sctps_read_peeks; /* Number of times recv was called with peek */ - uint32_t sctps_cached_chk; /* Number of cached chunks used */ - uint32_t sctps_cached_strmoq; /* Number of cached stream oq's used */ - uint32_t sctps_left_abandon; /* Number of unread messages abandoned by close */ - uint32_t sctps_send_burst_avoid; /* Unused */ - uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already max burst inflight to net */ - uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via fwd-tsn's */ - uint32_t sctps_queue_upd_ecne; /* Number of times we queued or updated an ECN chunk on send queue */ - uint32_t sctps_recvzerocrc; /* Number of accepted packets with zero CRC */ - uint32_t sctps_sendzerocrc; /* Number of packets sent with zero CRC */ - uint32_t sctps_reserved[29]; /* Future ABI compat - remove int's from here when adding new */ -}; - -#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1) -#define SCTP_STAT_DECR(_x) SCTP_STAT_DECR_BY(_x,1) -#if defined(__FreeBSD__) && !defined(__Userspace__) -#if defined(SMP) && defined(SCTP_USE_PERCPU_STAT) -#define SCTP_STAT_INCR_BY(_x,_d) (SCTP_BASE_STATS[PCPU_GET(cpuid)]._x += _d) -#define SCTP_STAT_DECR_BY(_x,_d) (SCTP_BASE_STATS[PCPU_GET(cpuid)]._x -= _d) -#else -#define SCTP_STAT_INCR_BY(_x,_d) atomic_add_int(&SCTP_BASE_STAT(_x), _d) -#define SCTP_STAT_DECR_BY(_x,_d) atomic_subtract_int(&SCTP_BASE_STAT(_x), _d) -#endif -#else -#define SCTP_STAT_INCR_BY(_x,_d) atomic_add_int(&SCTP_BASE_STAT(_x), _d) -#define SCTP_STAT_DECR_BY(_x,_d) atomic_subtract_int(&SCTP_BASE_STAT(_x), _d) -#endif -/* The following macros are for handling MIB values, */ -#define SCTP_STAT_INCR_COUNTER32(_x) SCTP_STAT_INCR(_x) -#define SCTP_STAT_INCR_COUNTER64(_x) SCTP_STAT_INCR(_x) -#define SCTP_STAT_INCR_GAUGE32(_x) SCTP_STAT_INCR(_x) -#define SCTP_STAT_DECR_COUNTER32(_x) SCTP_STAT_DECR(_x) -#define SCTP_STAT_DECR_COUNTER64(_x) SCTP_STAT_DECR(_x) -#define SCTP_STAT_DECR_GAUGE32(_x) SCTP_STAT_DECR(_x) - -/***********************************/ -/* And something for us old timers */ -/***********************************/ - -#if !(defined(__APPLE__) && !defined(__Userspace__)) -#if !defined(__Userspace__) -#ifndef ntohll -#if defined(__linux__) -#ifndef _BSD_SOURCE -#define _BSD_SOURCE -#endif -#include -#else -#include -#endif -#define ntohll(x) be64toh(x) -#endif - -#ifndef htonll -#if defined(__linux__) -#ifndef _BSD_SOURCE -#define _BSD_SOURCE -#endif -#include -#else -#include -#endif -#define htonll(x) htobe64(x) -#endif -#endif -#endif -/***********************************/ - -struct xsctp_inpcb { - uint32_t last; - uint32_t flags; - uint64_t features; - uint32_t total_sends; - uint32_t total_recvs; - uint32_t total_nospaces; - uint32_t fragmentation_point; - uint16_t local_port; -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint16_t qlen_old; - uint16_t maxqlen_old; -#else - uint16_t qlen; - uint16_t maxqlen; -#endif - uint16_t __spare16; -#if defined(__FreeBSD__) && !defined(__Userspace__) - kvaddr_t socket; -#else - void *socket; -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint32_t qlen; - uint32_t maxqlen; -#endif - uint32_t extra_padding[26]; /* future */ -}; - -struct xsctp_tcb { - union sctp_sockstore primary_addr; /* sctpAssocEntry 5/6 */ - uint32_t last; - uint32_t heartbeat_interval; /* sctpAssocEntry 7 */ - uint32_t state; /* sctpAssocEntry 8 */ - uint32_t in_streams; /* sctpAssocEntry 9 */ - uint32_t out_streams; /* sctpAssocEntry 10 */ - uint32_t max_nr_retrans; /* sctpAssocEntry 11 */ - uint32_t primary_process; /* sctpAssocEntry 12 */ - uint32_t T1_expireries; /* sctpAssocEntry 13 */ - uint32_t T2_expireries; /* sctpAssocEntry 14 */ - uint32_t retransmitted_tsns; /* sctpAssocEntry 15 */ - uint32_t total_sends; - uint32_t total_recvs; - uint32_t local_tag; - uint32_t remote_tag; - uint32_t initial_tsn; - uint32_t highest_tsn; - uint32_t cumulative_tsn; - uint32_t cumulative_tsn_ack; - uint32_t mtu; - uint32_t refcnt; - uint16_t local_port; /* sctpAssocEntry 3 */ - uint16_t remote_port; /* sctpAssocEntry 4 */ - struct sctp_timeval start_time; /* sctpAssocEntry 16 */ - struct sctp_timeval discontinuity_time; /* sctpAssocEntry 17 */ - uint32_t peers_rwnd; - sctp_assoc_t assoc_id; /* sctpAssocEntry 1 */ - uint32_t extra_padding[32]; /* future */ -}; - -struct xsctp_laddr { - union sctp_sockstore address; /* sctpAssocLocalAddrEntry 1/2 */ - uint32_t last; - struct sctp_timeval start_time; /* sctpAssocLocalAddrEntry 3 */ - uint32_t extra_padding[32]; /* future */ -}; - -struct xsctp_raddr { - union sctp_sockstore address; /* sctpAssocLocalRemEntry 1/2 */ - uint32_t last; - uint32_t rto; /* sctpAssocLocalRemEntry 5 */ - uint32_t max_path_rtx; /* sctpAssocLocalRemEntry 6 */ - uint32_t rtx; /* sctpAssocLocalRemEntry 7 */ - uint32_t error_counter; /* */ - uint32_t cwnd; /* */ - uint32_t flight_size; /* */ - uint32_t mtu; /* */ - uint8_t active; /* sctpAssocLocalRemEntry 3 */ - uint8_t confirmed; /* */ - uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */ - uint8_t potentially_failed; - struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */ - uint32_t rtt; - uint32_t heartbeat_interval; - uint32_t ssthresh; - uint16_t encaps_port; - uint16_t state; - uint32_t extra_padding[29]; /* future */ -}; - -#define SCTP_MAX_LOGGING_SIZE 30000 -#define SCTP_TRACE_PARAMS 6 /* This number MUST be even */ - -struct sctp_log_entry { - uint64_t timestamp; - uint32_t subsys; - uint32_t padding; - uint32_t params[SCTP_TRACE_PARAMS]; -}; - -struct sctp_log { - struct sctp_log_entry entry[SCTP_MAX_LOGGING_SIZE]; - uint32_t index; - uint32_t padding; -}; - -/* - * Kernel defined for sctp_send - */ -#if defined(_KERNEL) || defined(__Userspace__) -int -sctp_lower_sosend(struct socket *so, - struct sockaddr *addr, - struct uio *uio, - struct mbuf *top, - struct mbuf *control, - int flags, - struct sctp_sndrcvinfo *srcv -#if !defined(__Userspace__) -#if defined(__FreeBSD__) - ,struct thread *p -#elif defined(_WIN32) - , PKTHREAD p -#else - ,struct proc *p -#endif -#endif -); - -int -sctp_sorecvmsg(struct socket *so, - struct uio *uio, - struct mbuf **mp, - struct sockaddr *from, - int fromlen, - int *msg_flags, - struct sctp_sndrcvinfo *sinfo, - int filling_sinfo); -#endif - -/* - * API system calls - */ -#if !(defined(_KERNEL)) && !(defined(__Userspace__)) - -__BEGIN_DECLS -int sctp_peeloff(int, sctp_assoc_t); -int sctp_bindx(int, struct sockaddr *, int, int); -int sctp_connectx(int, const struct sockaddr *, int, sctp_assoc_t *); -int sctp_getaddrlen(sa_family_t); -int sctp_getpaddrs(int, sctp_assoc_t, struct sockaddr **); -void sctp_freepaddrs(struct sockaddr *); -int sctp_getladdrs(int, sctp_assoc_t, struct sockaddr **); -void sctp_freeladdrs(struct sockaddr *); -int sctp_opt_info(int, sctp_assoc_t, int, void *, socklen_t *); - -/* deprecated */ -ssize_t sctp_sendmsg(int, const void *, size_t, const struct sockaddr *, - socklen_t, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t); - -/* deprecated */ -ssize_t sctp_send(int, const void *, size_t, - const struct sctp_sndrcvinfo *, int); - -/* deprecated */ -ssize_t sctp_sendx(int, const void *, size_t, struct sockaddr *, - int, struct sctp_sndrcvinfo *, int); - -/* deprecated */ -ssize_t sctp_sendmsgx(int sd, const void *, size_t, struct sockaddr *, - int, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t); - -sctp_assoc_t sctp_getassocid(int, struct sockaddr *); - -/* deprecated */ -ssize_t sctp_recvmsg(int, void *, size_t, struct sockaddr *, socklen_t *, - struct sctp_sndrcvinfo *, int *); - -ssize_t sctp_sendv(int, const struct iovec *, int, struct sockaddr *, - int, void *, socklen_t, unsigned int, int); - -ssize_t sctp_recvv(int, const struct iovec *, int, struct sockaddr *, - socklen_t *, void *, socklen_t *, unsigned int *, int *); -__END_DECLS - -#endif /* !_KERNEL */ -#endif /* !__sctp_uio_h__ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_userspace.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_userspace.c deleted file mode 100644 index 71888901..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_userspace.c +++ /dev/null @@ -1,425 +0,0 @@ -/*- - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - - -#ifdef _WIN32 -#include -#include -#include -#if !defined(__MINGW32__) -#pragma comment(lib, "iphlpapi.lib") -#endif -#endif -#include -#if defined(__FreeBSD__) -#include -#endif - -#if defined(__linux__) -#include -#endif - -#if defined(_WIN32) -/* Adapter to translate Unix thread start routines to Windows thread start - * routines. - */ -#if defined(__MINGW32__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#endif -static DWORD WINAPI -sctp_create_thread_adapter(void *arg) { - start_routine_t start_routine = (start_routine_t)arg; - return start_routine(NULL) == NULL; -} - -int -sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine) -{ - *thread = CreateThread(NULL, 0, sctp_create_thread_adapter, - (void *)start_routine, 0, NULL); - if (*thread == NULL) - return GetLastError(); - return 0; -} - -#if defined(__MINGW32__) -#pragma GCC diagnostic pop -#endif - -#else -int -sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine) -{ - return pthread_create(thread, NULL, start_routine, NULL); -} -#endif - -void -sctp_userspace_set_threadname(const char *name) -{ -#if defined(__APPLE__) - pthread_setname_np(name); -#endif -#if defined(__linux__) - prctl(PR_SET_NAME, name); -#endif -#if defined(__FreeBSD__) - pthread_set_name_np(pthread_self(), name); -#endif -} - -#if !defined(_WIN32) && !defined(__native_client__) -int -sctp_userspace_get_mtu_from_ifn(uint32_t if_index) -{ -#if defined(INET) || defined(INET6) - struct ifreq ifr; - int fd; -#endif - int mtu; - - if (if_index == 0xffffffff) { - mtu = 1280; - } else { - mtu = 0; -#if defined(INET) || defined(INET6) - memset(&ifr, 0, sizeof(struct ifreq)); - if (if_indextoname(if_index, ifr.ifr_name) != NULL) { - /* TODO can I use the raw socket here and not have to open a new one with each query? */ -#if defined(INET) - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { -#else - if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0) { -#endif - if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0) { - mtu = ifr.ifr_mtu; - } - close(fd); - } - } -#endif - } - return (mtu); -} -#endif - -#if defined(__native_client__) -int -sctp_userspace_get_mtu_from_ifn(uint32_t if_index) -{ - return 1280; -} -#endif - -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__linux__) || defined(__native_client__) || defined(__NetBSD__) || defined(__QNX__) || defined(_WIN32) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) -int -timingsafe_bcmp(const void *b1, const void *b2, size_t n) -{ - const unsigned char *p1 = b1, *p2 = b2; - int ret = 0; - - for (; n > 0; n--) - ret |= *p1++ ^ *p2++; - return (ret != 0); -} -#endif - -#ifdef _WIN32 -int -sctp_userspace_get_mtu_from_ifn(uint32_t if_index) -{ -#if defined(INET) || defined(INET6) - PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt; - DWORD AdapterAddrsSize, Err; -#endif - int mtu; - - if (if_index == 0xffffffff) { - mtu = 1280; - } else { - mtu = 0; -#if defined(INET) || defined(INET6) - AdapterAddrsSize = 0; - pAdapterAddrs = NULL; - if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { - if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { - SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() sizing failed with error code %d, AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); - mtu = -1; - goto cleanup; - } - } - if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { - SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); - mtu = -1; - goto cleanup; - } - if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { - SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() failed with error code %d\n", Err); - mtu = -1; - goto cleanup; - } - for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { - if (pAdapt->IfIndex == if_index) { - mtu = pAdapt->Mtu; - break; - } - } - cleanup: - if (pAdapterAddrs != NULL) { - GlobalFree(pAdapterAddrs); - } -#endif - } - return (mtu); -} - -void -getwintimeofday(struct timeval *tv) -{ - FILETIME filetime; - ULARGE_INTEGER ularge; - - GetSystemTimeAsFileTime(&filetime); - ularge.LowPart = filetime.dwLowDateTime; - ularge.HighPart = filetime.dwHighDateTime; - /* Change base from Jan 1 1601 00:00:00 to Jan 1 1970 00:00:00 */ -#if defined(__MINGW32__) - ularge.QuadPart -= 116444736000000000ULL; -#else - ularge.QuadPart -= 116444736000000000UI64; -#endif - /* - * ularge.QuadPart is now the number of 100-nanosecond intervals - * since Jan 1 1970 00:00:00. - */ -#if defined(__MINGW32__) - tv->tv_sec = (long)(ularge.QuadPart / 10000000ULL); - tv->tv_usec = (long)((ularge.QuadPart % 10000000ULL) / 10ULL); -#else - tv->tv_sec = (long)(ularge.QuadPart / 10000000UI64); - tv->tv_usec = (long)((ularge.QuadPart % 10000000UI64) / 10UI64); -#endif -} - -int -win_if_nametoindex(const char *ifname) -{ - IP_ADAPTER_ADDRESSES *addresses, *addr; - ULONG status, size; - int index = 0; - - if (!ifname) { - return 0; - } - - size = 0; - status = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size); - if (status != ERROR_BUFFER_OVERFLOW) { - return 0; - } - addresses = malloc(size); - status = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &size); - if (status == ERROR_SUCCESS) { - for (addr = addresses; addr; addr = addr->Next) { - if (addr->AdapterName && !strcmp(ifname, addr->AdapterName)) { - index = addr->IfIndex; - break; - } - } - } - - free(addresses); - return index; -} - -#if WINVER < 0x0600 -/* These functions are written based on the code at - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * Therefore, for the rest of the file the following applies: - * - * - * Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), - * DAnCE(TM), and CoSMIC(TM) - * - * [1]ACE(TM), [2]TAO(TM), [3]CIAO(TM), DAnCE(TM), and [4]CoSMIC(TM) - * (henceforth referred to as "DOC software") are copyrighted by - * [5]Douglas C. Schmidt and his [6]research group at [7]Washington - * University, [8]University of California, Irvine, and [9]Vanderbilt - * University, Copyright (c) 1993-2012, all rights reserved. Since DOC - * software is open-source, freely available software, you are free to - * use, modify, copy, and distribute--perpetually and irrevocably--the - * DOC software source code and object code produced from the source, as - * well as copy and distribute modified versions of this software. You - * must, however, include this copyright statement along with any code - * built using DOC software that you release. No copyright statement - * needs to be provided if you just ship binary executables of your - * software products. - * - * You can use DOC software in commercial and/or binary software releases - * and are under no obligation to redistribute any of your source code - * that is built using DOC software. Note, however, that you may not - * misappropriate the DOC software code, such as copyrighting it yourself - * or claiming authorship of the DOC software code, in a way that will - * prevent DOC software from being distributed freely using an - * open-source development model. You needn't inform anyone that you're - * using DOC software in your software, though we encourage you to let - * [10]us know so we can promote your project in the [11]DOC software - * success stories. - * - * The [12]ACE, [13]TAO, [14]CIAO, [15]DAnCE, and [16]CoSMIC web sites - * are maintained by the [17]DOC Group at the [18]Institute for Software - * Integrated Systems (ISIS) and the [19]Center for Distributed Object - * Computing of Washington University, St. Louis for the development of - * open-source software as part of the open-source software community. - * Submissions are provided by the submitter ``as is'' with no warranties - * whatsoever, including any warranty of merchantability, noninfringement - * of third party intellectual property, or fitness for any particular - * purpose. In no event shall the submitter be liable for any direct, - * indirect, special, exemplary, punitive, or consequential damages, - * including without limitation, lost profits, even if advised of the - * possibility of such damages. Likewise, DOC software is provided as is - * with no warranties of any kind, including the warranties of design, - * merchantability, and fitness for a particular purpose, - * noninfringement, or arising from a course of dealing, usage or trade - * practice. Washington University, UC Irvine, Vanderbilt University, - * their employees, and students shall have no liability with respect to - * the infringement of copyrights, trade secrets or any patents by DOC - * software or any part thereof. Moreover, in no event will Washington - * University, UC Irvine, or Vanderbilt University, their employees, or - * students be liable for any lost revenue or profits or other special, - * indirect and consequential damages. - * - * DOC software is provided with no support and without any obligation on - * the part of Washington University, UC Irvine, Vanderbilt University, - * their employees, or students to assist in its use, correction, - * modification, or enhancement. A [20]number of companies around the - * world provide commercial support for DOC software, however. DOC - * software is Y2K-compliant, as long as the underlying OS platform is - * Y2K-compliant. Likewise, DOC software is compliant with the new US - * daylight savings rule passed by Congress as "The Energy Policy Act of - * 2005," which established new daylight savings times (DST) rules for - * the United States that expand DST as of March 2007. Since DOC software - * obtains time/date and calendaring information from operating systems - * users will not be affected by the new DST rules as long as they - * upgrade their operating systems accordingly. - * - * The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), - * Washington University, UC Irvine, and Vanderbilt University, may not - * be used to endorse or promote products or services derived from this - * source without express written permission from Washington University, - * UC Irvine, or Vanderbilt University. This license grants no permission - * to call products or services derived from this source ACE(TM), - * TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM), nor does it grant - * permission for the name Washington University, UC Irvine, or - * Vanderbilt University to appear in their names. - * - * If you have any suggestions, additions, comments, or questions, please - * let [21]me know. - * - * [22]Douglas C. Schmidt - * - * References - * - * 1. http://www.cs.wustl.edu/~schmidt/ACE.html - * 2. http://www.cs.wustl.edu/~schmidt/TAO.html - * 3. http://www.dre.vanderbilt.edu/CIAO/ - * 4. http://www.dre.vanderbilt.edu/cosmic/ - * 5. http://www.dre.vanderbilt.edu/~schmidt/ - * 6. http://www.cs.wustl.edu/~schmidt/ACE-members.html - * 7. http://www.wustl.edu/ - * 8. http://www.uci.edu/ - * 9. http://www.vanderbilt.edu/ - * 10. mailto:doc_group@cs.wustl.edu - * 11. http://www.cs.wustl.edu/~schmidt/ACE-users.html - * 12. http://www.cs.wustl.edu/~schmidt/ACE.html - * 13. http://www.cs.wustl.edu/~schmidt/TAO.html - * 14. http://www.dre.vanderbilt.edu/CIAO/ - * 15. http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/DAnCE/ - * 16. http://www.dre.vanderbilt.edu/cosmic/ - * 17. http://www.dre.vanderbilt.edu/ - * 18. http://www.isis.vanderbilt.edu/ - * 19. http://www.cs.wustl.edu/~schmidt/doc-center.html - * 20. http://www.cs.wustl.edu/~schmidt/commercial-support.html - * 21. mailto:d.schmidt@vanderbilt.edu - * 22. http://www.dre.vanderbilt.edu/~schmidt/ - * 23. http://www.cs.wustl.edu/ACE.html - */ - -void -InitializeXPConditionVariable(userland_cond_t *cv) -{ - cv->waiters_count = 0; - InitializeCriticalSection(&(cv->waiters_count_lock)); - cv->events_[C_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); - cv->events_[C_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL); -} - -void -DeleteXPConditionVariable(userland_cond_t *cv) -{ - CloseHandle(cv->events_[C_BROADCAST]); - CloseHandle(cv->events_[C_SIGNAL]); - DeleteCriticalSection(&(cv->waiters_count_lock)); -} - -int -SleepXPConditionVariable(userland_cond_t *cv, userland_mutex_t *mtx) -{ - int result, last_waiter; - - EnterCriticalSection(&cv->waiters_count_lock); - cv->waiters_count++; - LeaveCriticalSection(&cv->waiters_count_lock); - LeaveCriticalSection (mtx); - result = WaitForMultipleObjects(2, cv->events_, FALSE, INFINITE); - if (result==-1) { - result = GetLastError(); - } - EnterCriticalSection(&cv->waiters_count_lock); - cv->waiters_count--; - last_waiter = result == (C_SIGNAL + C_BROADCAST && (cv->waiters_count == 0)); - LeaveCriticalSection(&cv->waiters_count_lock); - if (last_waiter) - ResetEvent(cv->events_[C_BROADCAST]); - EnterCriticalSection (mtx); - return result; -} - -void -WakeAllXPConditionVariable(userland_cond_t *cv) -{ - int have_waiters; - EnterCriticalSection(&cv->waiters_count_lock); - have_waiters = cv->waiters_count > 0; - LeaveCriticalSection(&cv->waiters_count_lock); - if (have_waiters) - SetEvent (cv->events_[C_BROADCAST]); -} -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_usrreq.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_usrreq.c deleted file mode 100644 index ffc86643..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_usrreq.c +++ /dev/null @@ -1,9017 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#include -#include -#include -#ifdef INET6 -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__Userspace__) -#include -#else -#include -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#if defined(HAVE_SCTP_PEELOFF_SOCKOPT) -#include -#endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ - -extern const struct sctp_cc_functions sctp_cc_functions[]; -extern const struct sctp_ss_functions sctp_ss_functions[]; - -#if defined(__Userspace__) -void -sctp_init(uint16_t port, - int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), - void (*debug_printf)(const char *format, ...), int start_threads) -#elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) -void -sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED) -#elif defined(__FreeBSD__) -static void -sctp_init(void *arg SCTP_UNUSED) -#else -void -sctp_init(void) -#endif -{ -#if !defined(__Userspace__) - u_long sb_max_adj; - -#else - init_random(); -#endif - /* Initialize and modify the sysctled variables */ - sctp_init_sysctls(); -#if defined(__Userspace__) - SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port; -#else -#if defined(__APPLE__) && !defined(__Userspace__) - sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES)); - SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj; -#else - if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) - SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8); - /* - * Allow a user to take no more than 1/2 the number of clusters or - * the SB_MAX, whichever is smaller, for the send window. - */ - sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); - SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, - (((uint32_t)nmbclusters / 2) * MCLBYTES)); -#endif - /* - * Now for the recv window, should we take the same amount? or - * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For - * now I will just copy. - */ - SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace); -#endif - SCTP_BASE_VAR(first_time) = 0; - SCTP_BASE_VAR(sctp_pcb_initialized) = 0; -#if defined(__Userspace__) -#if !defined(_WIN32) -#if defined(INET) || defined(INET6) - SCTP_BASE_VAR(userspace_route) = -1; -#endif -#endif -#ifdef INET - SCTP_BASE_VAR(userspace_rawsctp) = -1; - SCTP_BASE_VAR(userspace_udpsctp) = -1; -#endif -#ifdef INET6 - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - SCTP_BASE_VAR(userspace_udpsctp6) = -1; -#endif - SCTP_BASE_VAR(timer_thread_should_exit) = 0; - SCTP_BASE_VAR(conn_output) = conn_output; - SCTP_BASE_VAR(debug_printf) = debug_printf; - SCTP_BASE_VAR(crc32c_offloaded) = 0; - SCTP_BASE_VAR(iterator_thread_started) = 0; - SCTP_BASE_VAR(timer_thread_started) = 0; -#endif -#if defined(__Userspace__) - sctp_pcb_init(start_threads); - if (start_threads) { - sctp_start_timer_thread(); - } -#else - sctp_pcb_init(); -#endif -#if defined(SCTP_PACKET_LOGGING) - SCTP_BASE_VAR(packet_log_writers) = 0; - SCTP_BASE_VAR(packet_log_end) = 0; - memset(&SCTP_BASE_VAR(packet_log_buffer), 0, SCTP_PACKET_LOG_SIZE); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_BASE_VAR(sctp_main_timer_ticks) = 0; - sctp_start_main_timer(); - timeout(sctp_delayed_startup, NULL, 1); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_BASE_VAR(eh_tag) = EVENTHANDLER_REGISTER(rt_addrmsg, - sctp_addr_change_event_handler, NULL, EVENTHANDLER_PRI_FIRST); -#endif -} -#if defined(__FreeBSD__) && !defined(__Userspace__) -VNET_SYSINIT(sctp_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, sctp_init, NULL); - -#ifdef VIMAGE -static void -sctp_finish(void *unused __unused) -{ - EVENTHANDLER_DEREGISTER(rt_addrmsg, SCTP_BASE_VAR(eh_tag)); - sctp_pcb_finish(); -} -VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL); -#endif -#else -void -sctp_finish(void) -{ -#if defined(__APPLE__) && !defined(__Userspace__) - untimeout(sctp_delayed_startup, NULL); - sctp_over_udp_stop(); - sctp_address_monitor_stop(); - sctp_stop_main_timer(); -#endif -#if defined(__Userspace__) -#if defined(INET) || defined(INET6) - recv_thread_destroy(); -#endif - sctp_stop_timer_thread(); -#endif - sctp_pcb_finish(); -#if defined(_WIN32) && !defined(__Userspace__) - sctp_finish_sysctls(); -#endif -#if defined(__Userspace__) - finish_random(); -#endif -} -#endif - -void -sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint32_t mtu, bool resend) -{ - struct sctp_association *asoc; - struct sctp_tmit_chunk *chk; - uint32_t overhead; - - asoc = &stcb->asoc; - KASSERT(mtu < asoc->smallest_mtu, - ("Currently only reducing association MTU %u supported (MTU %u)", - asoc->smallest_mtu, mtu)); - asoc->smallest_mtu = mtu; - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - overhead = SCTP_MIN_OVERHEAD; - } else { -#if defined(__Userspace__) - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - overhead = sizeof(struct sctphdr); - } else { - overhead = SCTP_MIN_V4_OVERHEAD; - } -#else - overhead = SCTP_MIN_V4_OVERHEAD; -#endif - } - if (asoc->idata_supported) { - if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) { - overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); - } - } else { - if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) { - overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); - } - } - KASSERT(overhead % 4 == 0, - ("overhead (%u) not a multiple of 4", overhead)); - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (((uint32_t)chk->send_size + overhead) > mtu) { - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - } - } - TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { - if (((uint32_t)chk->send_size + overhead) > mtu) { - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - if (resend && chk->sent < SCTP_DATAGRAM_RESEND) { - /* - * If requested, mark the chunk for immediate - * resend, since we sent it being too big. - */ - sctp_flight_size_decrease(chk); - sctp_total_flight_decrease(stcb, chk); - chk->sent = SCTP_DATAGRAM_RESEND; - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - chk->rec.data.doing_fast_retransmit = 0; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, - chk->whoTo->flight_size, - chk->book_size, - (uint32_t)(uintptr_t)chk->whoTo, - chk->rec.data.tsn); - } - /* Clear any time, so NO RTT is being done. */ - if (chk->do_rtt == 1) { - chk->do_rtt = 0; - chk->whoTo->rto_needed = 1; - } - } - } - } -} - -#ifdef INET -#if !defined(__Userspace__) -void -sctp_notify(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net, - uint8_t icmp_type, - uint8_t icmp_code, - uint16_t ip_len, - uint32_t next_mtu) -{ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - int timer_stopped; - - if (icmp_type != ICMP_UNREACH) { - /* We only care about unreachable */ - SCTP_TCB_UNLOCK(stcb); - return; - } - if ((icmp_code == ICMP_UNREACH_NET) || - (icmp_code == ICMP_UNREACH_HOST) || - (icmp_code == ICMP_UNREACH_NET_UNKNOWN) || - (icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || - (icmp_code == ICMP_UNREACH_ISOLATED) || - (icmp_code == ICMP_UNREACH_NET_PROHIB) || - (icmp_code == ICMP_UNREACH_HOST_PROHIB) || -#if defined(__NetBSD__) - (icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) { -#else - (icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { -#endif - /* Mark the net unreachable. */ - if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* OK, that destination is NOT reachable. */ - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state &= ~SCTP_ADDR_PF; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, 0, - (void *)net, SCTP_SO_NOT_LOCKED); - } - SCTP_TCB_UNLOCK(stcb); - } else if ((icmp_code == ICMP_UNREACH_PROTOCOL) || - (icmp_code == ICMP_UNREACH_PORT)) { - /* Treat it like an ABORT. */ - sctp_abort_notification(stcb, true, false, 0, NULL, SCTP_SO_NOT_LOCKED); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); - /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/ -#endif - /* no need to unlock here, since the TCB is gone */ - } else if (icmp_code == ICMP_UNREACH_NEEDFRAG) { - if (net->dest_state & SCTP_ADDR_NO_PMTUD) { - SCTP_TCB_UNLOCK(stcb); - return; - } - /* Find the next (smaller) MTU */ - if (next_mtu == 0) { - /* - * Old type router that does not tell us what the next - * MTU is. - * Rats we will have to guess (in a educated fashion - * of course). - */ - next_mtu = sctp_get_prev_mtu(ip_len); - } - /* Stop the PMTU timer. */ - if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - timer_stopped = 1; - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); - } else { - timer_stopped = 0; - } - /* Update the path MTU. */ - if (net->port) { - next_mtu -= sizeof(struct udphdr); - } - if (net->mtu > next_mtu) { - net->mtu = next_mtu; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (net->port) { - sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr)); - } else { - sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu); - } -#endif - } - /* Update the association MTU */ - if (stcb->asoc.smallest_mtu > next_mtu) { - sctp_pathmtu_adjustment(stcb, next_mtu, true); - } - /* Finally, start the PMTU timer if it was running before. */ - if (timer_stopped) { - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); - } - SCTP_TCB_UNLOCK(stcb); - } else { - SCTP_TCB_UNLOCK(stcb); - } -} -#endif - -#if !defined(__Userspace__) -#if defined(__FreeBSD__) -void sctp_ctlinput(struct icmp *icmp) -{ - struct ip *inner_ip, *outer_ip; - struct sctphdr *sh; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sctp_init_chunk *ch; - struct sockaddr_in src, dst; - - if (icmp_errmap(icmp) == 0) - return; - - outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); - inner_ip = &icmp->icmp_ip; - sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); - memset(&src, 0, sizeof(struct sockaddr_in)); - src.sin_family = AF_INET; - src.sin_len = sizeof(struct sockaddr_in); - src.sin_port = sh->src_port; - src.sin_addr = inner_ip->ip_src; - memset(&dst, 0, sizeof(struct sockaddr_in)); - dst.sin_family = AF_INET; - dst.sin_len = sizeof(struct sockaddr_in); - dst.sin_port = sh->dest_port; - dst.sin_addr = inner_ip->ip_dst; - /* - * 'dst' holds the dest of the packet that failed to be sent. - * 'src' holds our local endpoint address. Thus we reverse - * the dst and the src in the lookup. - */ - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, - SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the verification tag */ - if (ntohl(sh->v_tag) != 0) { - /* - * This must be the verification tag used for - * sending out packets. We don't consider - * packets reflecting the verification tag. - */ - if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - if (ntohs(outer_ip->ip_len) >= - sizeof(struct ip) + - 8 + (inner_ip->ip_hl << 2) + 20) { - /* - * In this case we can check if we - * got an INIT chunk and if the - * initiate tag matches. - */ - ch = (struct sctp_init_chunk *)(sh + 1); - if ((ch->ch.chunk_type != SCTP_INITIATION) || - (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - } - sctp_notify(inp, stcb, net, - icmp->icmp_type, - icmp->icmp_code, - ntohs(inner_ip->ip_len), - (uint32_t)ntohs(icmp->icmp_nextmtu)); - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } -} -#else -void -#if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN) -sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip, struct ifnet *ifp SCTP_UNUSED) -#else -sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) -#endif -{ - struct ip *inner_ip; - struct sctphdr *sh; - struct icmp *icmp; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sockaddr_in src, dst; - -#if !defined(__FreeBSD__) && !defined(__Userspace__) - if (sa->sa_family != AF_INET || - ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { - return; - } -#endif - if (PRC_IS_REDIRECT(cmd)) { - vip = NULL; - } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { - return; - } - if (vip != NULL) { - inner_ip = (struct ip *)vip; - icmp = (struct icmp *)((caddr_t)inner_ip - - (sizeof(struct icmp) - sizeof(struct ip))); - sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); - memset(&src, 0, sizeof(struct sockaddr_in)); - src.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - src.sin_len = sizeof(struct sockaddr_in); -#endif - src.sin_port = sh->src_port; - src.sin_addr = inner_ip->ip_src; - memset(&dst, 0, sizeof(struct sockaddr_in)); - dst.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - dst.sin_port = sh->dest_port; - dst.sin_addr = inner_ip->ip_dst; - /* - * 'dst' holds the dest of the packet that failed to be sent. - * 'src' holds our local endpoint address. Thus we reverse - * the dst and the src in the lookup. - */ - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, - SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the verification tag */ - if (ntohl(sh->v_tag) != 0) { - /* - * This must be the verification tag used for - * sending out packets. We don't consider - * packets reflecting the verification tag. - */ - if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - sctp_notify(inp, stcb, net, - icmp->icmp_type, - icmp->icmp_code, - inner_ip->ip_len, - (uint32_t)ntohs(icmp->icmp_nextmtu)); -#if defined(__Userspace__) - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - struct socket *upcall_socket; - - upcall_socket = stcb->sctp_socket; - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - if ((upcall_socket->so_upcall != NULL) && - (upcall_socket->so_error != 0)) { - (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); - } - ACCEPT_LOCK(); - SOCK_LOCK(upcall_socket); - sorele(upcall_socket); - } -#endif - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } - } - return; -} -#endif -#endif -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -static int -sctp_getcred(SYSCTL_HANDLER_ARGS) -{ - struct xucred xuc; - struct sockaddr_in addrs[2]; - struct sctp_inpcb *inp; - struct sctp_nets *net; - struct sctp_tcb *stcb; - int error; - uint32_t vrf_id; - - /* FIX, for non-bsd is this right? */ - vrf_id = SCTP_DEFAULT_VRFID; - - error = priv_check(req->td, PRIV_NETINET_GETCRED); - - if (error) - return (error); - - error = SYSCTL_IN(req, addrs, sizeof(addrs)); - if (error) - return (error); - - stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]), - sintosa(&addrs[0]), - &inp, &net, 1, vrf_id); - if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { - if ((inp != NULL) && (stcb == NULL)) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - goto cred_can_cont; - } - - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - goto out; - } - SCTP_TCB_UNLOCK(stcb); - /* We use the write lock here, only - * since in the error leg we need it. - * If we used RLOCK, then we would have - * to wlock/decr/unlock/rlock. Which - * in theory could create a hole. Better - * to use higher wlock. - */ - SCTP_INP_WLOCK(inp); - cred_can_cont: - error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); - if (error) { - SCTP_INP_WUNLOCK(inp); - goto out; - } - cru2x(inp->sctp_socket->so_cred, &xuc); - SCTP_INP_WUNLOCK(inp); - error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); -out: - return (error); -} - -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, - CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - 0, 0, sctp_getcred, "S,ucred", - "Get the ucred of a SCTP connection"); -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) -void -#else -int -#endif -sctp_abort(struct socket *so) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - return; -#else - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); -#endif - } - - SCTP_INP_WLOCK(inp); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 17); -#endif - if (((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)) { - inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP; -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 16); -#endif - SCTP_INP_WUNLOCK(inp); - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - SOCK_LOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - KASSERT(!SOLISTENING(so), - ("sctp_abort: called on listening socket %p", so)); -#endif - SCTP_SB_CLEAR(so->so_snd); - SCTP_SB_CLEAR(so->so_rcv); -#if defined(__APPLE__) && !defined(__Userspace__) - so->so_usecount--; -#else - /* Now null out the reference, we are completely detached. */ - so->so_pcb = NULL; -#endif - SOCK_UNLOCK(so); - } else { - SCTP_INP_WUNLOCK(inp); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#else - return (0); -#endif -} - -#ifdef INET -#if defined(__Userspace__) -int -#else -static int -#endif -#if defined(__Userspace__) -sctp_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) -#elif defined(__FreeBSD__) -sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) -#elif defined(_WIN32) -sctp_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED) -#else -sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED) -#endif -{ - struct sctp_inpcb *inp; - struct inpcb *ip_inp; - int error; -#if !defined(__Userspace__) - uint32_t vrf_id = SCTP_DEFAULT_VRFID; -#endif - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp != NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); - if (error) { - return (error); - } - } - error = sctp_inpcb_alloc(so, vrf_id); - if (error) { - return (error); - } - inp = (struct sctp_inpcb *)so->so_pcb; - SCTP_INP_WLOCK(inp); - inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ - ip_inp = &inp->ip_inp.inp; - ip_inp->inp_vflag |= INP_IPV4; - ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); - SCTP_INP_WUNLOCK(inp); - return (0); -} - -#if defined(__Userspace__) -int -sctp_bind(struct socket *so, struct sockaddr *addr) { - void *p = NULL; -#elif defined(__FreeBSD__) -static int -sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) -{ -#elif defined(__APPLE__) -static int -sctp_bind(struct socket *so, struct sockaddr *addr, struct proc *p) { -#elif defined(_WIN32) -static int -sctp_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) { -#else -static int -sctp_bind(struct socket *so, struct mbuf *nam, struct proc *p) -{ - struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL; - -#endif - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - if (addr != NULL) { -#ifdef HAVE_SA_LEN - if ((addr->sa_family != AF_INET) || - (addr->sa_len != sizeof(struct sockaddr_in))) { -#else - if (addr->sa_family != AF_INET) { -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - } - return (sctp_inpcb_bind(so, addr, NULL, p)); -} - -#endif -#if defined(__Userspace__) - -int -sctpconn_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) -{ - struct sctp_inpcb *inp; - struct inpcb *ip_inp; - int error; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp != NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); - if (error) { - return (error); - } - } - error = sctp_inpcb_alloc(so, vrf_id); - if (error) { - return (error); - } - inp = (struct sctp_inpcb *)so->so_pcb; - SCTP_INP_WLOCK(inp); - inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; - inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_CONN; - ip_inp = &inp->ip_inp.inp; - ip_inp->inp_vflag |= INP_CONN; - ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); - SCTP_INP_WUNLOCK(inp); - return (0); -} - -int -sctpconn_bind(struct socket *so, struct sockaddr *addr) -{ - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - if (addr != NULL) { -#ifdef HAVE_SA_LEN - if ((addr->sa_family != AF_CONN) || - (addr->sa_len != sizeof(struct sockaddr_conn))) { -#else - if (addr->sa_family != AF_CONN) { -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - } - return (sctp_inpcb_bind(so, addr, NULL, NULL)); -} - -#endif -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -void -sctp_close(struct socket *so) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) - return; - - /* Inform all the lower layer assoc that we - * are done. - */ - SCTP_INP_WLOCK(inp); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 17); -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP; -#if defined(__Userspace__) - if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || -#else - if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || -#endif - (SCTP_SBAVAIL(&so->so_rcv) > 0)) { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 13); -#endif - SCTP_INP_WUNLOCK(inp); - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - } else { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 14); -#endif - SCTP_INP_WUNLOCK(inp); - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - } - /* The socket is now detached, no matter what - * the state of the SCTP association. - */ - SOCK_LOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (!SOLISTENING(so)) { - SCTP_SB_CLEAR(so->so_snd); - SCTP_SB_CLEAR(so->so_rcv); - } -#else - SCTP_SB_CLEAR(so->so_snd); - SCTP_SB_CLEAR(so->so_rcv); -#endif -#if !(defined(__APPLE__) && !defined(__Userspace__)) - /* Now null out the reference, we are completely detached. */ - so->so_pcb = NULL; -#endif - SOCK_UNLOCK(so); - } else { - SCTP_INP_WUNLOCK(inp); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif -} -#else -int -sctp_detach(struct socket *so) -{ - struct sctp_inpcb *inp; - uint32_t flags; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - sctp_must_try_again: - flags = inp->sctp_flags; -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 17); -#endif - if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { - if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || - (SCTP_SBAVAIL(&so->so_rcv) > 0)) { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 13); -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - } else { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 13); -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - } - /* The socket is now detached, no matter what - * the state of the SCTP association. - */ - SCTP_SB_CLEAR(so->so_snd); - /* same for the rcv ones, they are only - * here for the accounting/select. - */ - SCTP_SB_CLEAR(so->so_rcv); -#if !(defined(__APPLE__) && !defined(__Userspace__)) - /* Now disconnect */ - so->so_pcb = NULL; -#endif - } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } - } - return (0); -} -#endif - -#if defined(__Userspace__) -/* __Userspace__ is not calling sctp_sendm */ -#endif -#if !(defined(_WIN32) && !defined(__Userspace__)) -int -#if defined(__FreeBSD__) && !defined(__Userspace__) -sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *p); - -#else -sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct proc *p); - -#endif -int -#if defined(__FreeBSD__) && !defined(__Userspace__) -sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *p) -{ -#else -sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct proc *p) -{ -#endif - struct sctp_inpcb *inp; - int error; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - if (control) { - sctp_m_freem(control); - control = NULL; - } - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - sctp_m_freem(m); - return (EINVAL); - } - /* Got to have an to address if we are NOT a connected socket */ - if ((addr == NULL) && - ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || - (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { - goto connected_type; - } - - error = 0; - if (addr == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); - error = EDESTADDRREQ; - } else if (addr->sa_family != AF_INET) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); - error = EAFNOSUPPORT; -#if defined(HAVE_SA_LEN) - } else if (addr->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; -#endif - } - if (error != 0) { - sctp_m_freem(m); - if (control) { - sctp_m_freem(control); - control = NULL; - } - return (error); - } -connected_type: - /* now what about control */ - if (control) { - if (inp->control) { - sctp_m_freem(inp->control); - inp->control = NULL; - } - inp->control = control; - } - /* Place the data */ - if (inp->pkt) { - SCTP_BUF_NEXT(inp->pkt_last) = m; - inp->pkt_last = m; - } else { - inp->pkt_last = inp->pkt = m; - } - if ( -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) - /* FreeBSD uses a flag passed */ - ((flags & PRUS_MORETOCOME) == 0) -#else - 1 /* Open BSD does not have any "more to come" - * indication */ -#endif - ) { - /* - * note with the current version this code will only be used - * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for - * re-defining sosend to use the sctp_sosend. One can - * optionally switch back to this code (by changing back the - * definitions) but this is not advisable. This code is used - * by FreeBSD when sending a file with sendfile() though. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - int ret; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - inp->pkt = NULL; - inp->control = NULL; - return (ret); - } else { - return (0); - } -} -#endif - -int -sctp_disconnect(struct socket *so) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct sctp_inpcb *inp; - struct sctp_association *asoc; - struct sctp_tcb *stcb; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - return (ENOTCONN); - } - SCTP_INP_RLOCK(inp); - KASSERT(inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE || - inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL, - ("Not a one-to-one style socket")); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - return (ENOTCONN); - } - SCTP_TCB_LOCK(stcb); - asoc = &stcb->asoc; - if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { - /* We are about to be freed, out of here */ - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - return (0); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif -#if defined(__Userspace__) - if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || - (SCTP_SBAVAIL(&so->so_rcv) > 0)) { -#else - if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || - (SCTP_SBAVAIL(&so->so_rcv) > 0)) { -#endif - if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) { - /* Left with Data unread */ - struct mbuf *op_err; - - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - } - SCTP_INP_RUNLOCK(inp); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); - /* No unlock tcb assoc is gone */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - return (0); - } - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->stream_queue_cnt == 0)) { - /* there is nothing queued to send, so done */ - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - goto abort_anyway; - } - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - /* only send SHUTDOWN 1st time thru */ - struct sctp_nets *netp; - - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - if (stcb->asoc.alternate) { - netp = stcb->asoc.alternate; - } else { - netp = stcb->asoc.primary_destination; - } - sctp_send_shutdown(stcb,netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); - sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); - } - } else { - /* - * we still got (or just got) data to send, - * so set SHUTDOWN_PENDING - */ - /* - * XXX sockets draft says that SCTP_EOF - * should be sent with no data. currently, - * we will allow user data to be sent first - * and move to SHUTDOWN-PENDING - */ - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - abort_anyway: - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; - sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_INP_RUNLOCK(inp); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - return (0); - } else { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); - } - } - soisdisconnecting(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - return (0); -} - -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -int -sctp_flush(struct socket *so, int how) -{ - /* - * We will just clear out the values and let - * subsequent close clear out the data, if any. - * Note if the user did a shutdown(SHUT_RD) they - * will not be able to read the data, the socket - * will block that from happening. - */ - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - SCTP_INP_RLOCK(inp); - /* For the 1 to many model this does nothing */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { - SCTP_INP_RUNLOCK(inp); - return (0); - } - SCTP_INP_RUNLOCK(inp); - if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { - /* First make sure the sb will be happy, we don't - * use these except maybe the count - */ - SCTP_INP_WLOCK(inp); - SCTP_INP_READ_LOCK(inp); - inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; - SCTP_INP_READ_UNLOCK(inp); - SCTP_INP_WUNLOCK(inp); - SOCK_LOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - KASSERT(!SOLISTENING(so), - ("sctp_flush: called on listening socket %p", so)); -#endif - SCTP_SB_CLEAR(so->so_rcv); - SOCK_UNLOCK(so); - } - if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { - /* First make sure the sb will be happy, we don't - * use these except maybe the count - */ - SOCK_LOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - KASSERT(!SOLISTENING(so), - ("sctp_flush: called on listening socket %p", so)); -#endif - SOCK_UNLOCK(so); - } - return (0); -} -#endif - -int -sctp_shutdown(struct socket *so) -{ - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - SCTP_INP_RLOCK(inp); - /* For UDP model this is a invalid call */ - if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { - /* Restore the flags that the soshutdown took away. */ -#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__) - SOCKBUF_LOCK(&so->so_rcv); - so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; - SOCKBUF_UNLOCK(&so->so_rcv); -#else - SOCK_LOCK(so); - so->so_state &= ~SS_CANTRCVMORE; - SOCK_UNLOCK(so); -#endif - /* This proc will wakeup for read and do nothing (I hope) */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - return (EOPNOTSUPP); - } else { - /* - * Ok, if we reach here its the TCP model and it is either - * a SHUT_WR or SHUT_RDWR. - * This means we put the shutdown flag against it. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct sctp_tcb *stcb; - struct sctp_association *asoc; - struct sctp_nets *netp; - - if ((so->so_state & - (SS_ISCONNECTED|SS_ISCONNECTING|SS_ISDISCONNECTING)) == 0) { - SCTP_INP_RUNLOCK(inp); - return (ENOTCONN); - } - socantsendmore(so); - - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - /* - * Ok, we hit the case that the shutdown call was - * made after an abort or something. Nothing to do - * now. - */ - SCTP_INP_RUNLOCK(inp); - return (0); - } - SCTP_TCB_LOCK(stcb); - asoc = &stcb->asoc; - if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - return (0); - } - if ((SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_ECHOED) && - (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN)) { - /* If we are not in or before ESTABLISHED, there is - * no protocol action required. - */ - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - return (0); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - if (stcb->asoc.alternate) { - netp = stcb->asoc.alternate; - } else { - netp = stcb->asoc.primary_destination; - } - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) && - TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->stream_queue_cnt == 0)) { - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - goto abort_anyway; - } - /* there is nothing queued to send, so I'm done... */ - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); - sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, netp); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, NULL); - } else { - /* - * We still got (or just got) data to send, so set - * SHUTDOWN_PENDING. - */ - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); - if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); - } - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { - struct mbuf *op_err; - abort_anyway: - op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; - SCTP_INP_RUNLOCK(inp); - sctp_abort_an_association(stcb->sctp_ep, stcb, - op_err, false, SCTP_SO_LOCKED); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - return (0); - } - } - /* XXX: Why do this in the case where we have still data queued? */ - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - return (0); - } -} - -/* - * copies a "user" presentable address and removes embedded scope, etc. - * returns 0 on success, 1 on error - */ -static uint32_t -sctp_fill_user_address(struct sockaddr *dst, struct sockaddr *src) -{ -#ifdef INET6 -#if defined(SCTP_EMBEDDED_V6_SCOPE) - struct sockaddr_in6 lsa6; - - src = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)src, - &lsa6); -#endif -#endif -#ifdef HAVE_SA_LEN - memcpy(dst, src, src->sa_len); -#else - switch (src->sa_family) { -#ifdef INET - case AF_INET: - memcpy(dst, src, sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: - memcpy(dst, src, sizeof(struct sockaddr_in6)); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(dst, src, sizeof(struct sockaddr_conn)); - break; -#endif - default: - /* TSNH */ - break; - } -#endif - return (0); -} - -static size_t -sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - size_t limit, - struct sockaddr *addr, - uint32_t vrf_id) -{ - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - size_t actual; - int loopback_scope; -#if defined(INET) - int ipv4_local_scope, ipv4_addr_legal; -#endif -#if defined(INET6) - int local_scope, site_scope, ipv6_addr_legal; -#endif -#if defined(__Userspace__) - int conn_addr_legal; -#endif - struct sctp_vrf *vrf; - - SCTP_IPI_ADDR_LOCK_ASSERT(); - actual = 0; - if (limit == 0) - return (actual); - - if (stcb) { - /* Turn on all the appropriate scope */ - loopback_scope = stcb->asoc.scope.loopback_scope; -#if defined(INET) - ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; - ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; -#endif -#if defined(INET6) - local_scope = stcb->asoc.scope.local_scope; - site_scope = stcb->asoc.scope.site_scope; - ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; -#endif -#if defined(__Userspace__) - conn_addr_legal = stcb->asoc.scope.conn_addr_legal; -#endif - } else { - /* Use generic values for endpoints. */ - loopback_scope = 1; -#if defined(INET) - ipv4_local_scope = 1; -#endif -#if defined(INET6) - local_scope = 1; - site_scope = 1; -#endif - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { -#if defined(INET6) - ipv6_addr_legal = 1; -#endif -#if defined(INET) - if (SCTP_IPV6_V6ONLY(inp)) { - ipv4_addr_legal = 0; - } else { - ipv4_addr_legal = 1; - } -#endif -#if defined(__Userspace__) - conn_addr_legal = 0; -#endif - } else { -#if defined(INET6) - ipv6_addr_legal = 0; -#endif -#if defined(__Userspace__) - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - conn_addr_legal = 1; -#if defined(INET) - ipv4_addr_legal = 0; -#endif - } else { - conn_addr_legal = 0; -#if defined(INET) - ipv4_addr_legal = 1; -#endif - } -#else -#if defined(INET) - ipv4_addr_legal = 1; -#endif -#endif - } - } - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - return (0); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if ((loopback_scope == 0) && - SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - /* Skip loopback if loopback_scope not set */ - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (stcb) { - /* - * For the BOUND-ALL case, the list - * associated with a TCB is Always - * considered a reverse list.. i.e. - * it lists addresses that are NOT - * part of the association. If this - * is one of those we must skip it. - */ - if (sctp_is_addr_restricted(stcb, - sctp_ifa)) { - continue; - } - } - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (ipv4_addr_legal) { - struct sockaddr_in *sin; - - sin = &sctp_ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - /* - * we skip unspecified - * addresses - */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if ((ipv4_local_scope == 0) && - (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { - continue; - } -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { - if (actual + sizeof(struct sockaddr_in6) > limit) { - return (actual); - } - in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)addr); - ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport; - addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6)); - actual += sizeof(struct sockaddr_in6); - } else { -#endif - if (actual + sizeof(struct sockaddr_in) > limit) { - return (actual); - } - memcpy(addr, sin, sizeof(struct sockaddr_in)); - ((struct sockaddr_in *)addr)->sin_port = inp->sctp_lport; - addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in)); - actual += sizeof(struct sockaddr_in); -#ifdef INET6 - } -#endif - } else { - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (ipv6_addr_legal) { - struct sockaddr_in6 *sin6; - -#if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME) - struct sockaddr_in6 lsa6; -#endif - sin6 = &sctp_ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* - * we skip unspecified - * addresses - */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (local_scope == 0) - continue; -#if defined(SCTP_EMBEDDED_V6_SCOPE) - if (sin6->sin6_scope_id == 0) { -#ifdef SCTP_KAME - if (sa6_recoverscope(sin6) != 0) - /* - * bad link - * local - * address - */ - continue; -#else - lsa6 = *sin6; - if (in6_recoverscope(&lsa6, - &lsa6.sin6_addr, - NULL)) - /* - * bad link - * local - * address - */ - continue; - sin6 = &lsa6; -#endif /* SCTP_KAME */ - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - } - if ((site_scope == 0) && - (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - continue; - } - if (actual + sizeof(struct sockaddr_in6) > limit) { - return (actual); - } - memcpy(addr, sin6, sizeof(struct sockaddr_in6)); - ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport; - addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6)); - actual += sizeof(struct sockaddr_in6); - } else { - continue; - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (conn_addr_legal) { - if (actual + sizeof(struct sockaddr_conn) > limit) { - return (actual); - } - memcpy(addr, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn)); - ((struct sockaddr_conn *)addr)->sconn_port = inp->sctp_lport; - addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_conn)); - actual += sizeof(struct sockaddr_conn); - } else { - continue; - } -#endif - default: - /* TSNH */ - break; - } - } - } - } else { - struct sctp_laddr *laddr; - size_t sa_len; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (stcb) { - if (sctp_is_addr_restricted(stcb, laddr->ifa)) { - continue; - } - } -#ifdef HAVE_SA_LEN - sa_len = laddr->ifa->address.sa.sa_len; -#else - switch (laddr->ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - sa_len = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa_len = sizeof(struct sockaddr_in6); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - sa_len = sizeof(struct sockaddr_conn); - break; -#endif - default: - /* TSNH */ - sa_len = 0; - break; - } -#endif - if (actual + sa_len > limit) { - return (actual); - } - if (sctp_fill_user_address(addr, &laddr->ifa->address.sa)) - continue; - switch (laddr->ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - ((struct sockaddr_in *)addr)->sin_port = inp->sctp_lport; - break; -#endif -#ifdef INET6 - case AF_INET6: - ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - ((struct sockaddr_conn *)addr)->sconn_port = inp->sctp_lport; - break; -#endif - default: - /* TSNH */ - break; - } - addr = (struct sockaddr *)((caddr_t)addr + sa_len); - actual += sa_len; - } - } - return (actual); -} - -static size_t -sctp_fill_up_addresses(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - size_t limit, - struct sockaddr *addr) -{ - size_t size; -#ifdef SCTP_MVRF - uint32_t id; -#endif - - SCTP_IPI_ADDR_RLOCK(); -#ifdef SCTP_MVRF -/* - * FIX ME: ?? this WILL report duplicate addresses if they appear - * in more than one VRF. - */ - /* fill up addresses for all VRFs on the endpoint */ - size = 0; - for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) { - size += sctp_fill_up_addresses_vrf(inp, stcb, limit, addr, - inp->m_vrf_ids[id]); - addr = (struct sockaddr *)((caddr_t)addr + size); - } -#else - /* fill up addresses for the endpoint's default vrf */ - size = sctp_fill_up_addresses_vrf(inp, stcb, limit, addr, - inp->def_vrf_id); -#endif - SCTP_IPI_ADDR_RUNLOCK(); - return (size); -} - -static size_t -sctp_max_size_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) -{ - struct sctp_vrf *vrf; - size_t size; - - /* - * In both sub-set bound an bound_all cases we return the size of - * the maximum number of addresses that you could get. In reality - * the sub-set bound may have an exclusion list for a given TCB or - * in the bound-all case a TCB may NOT include the loopback or other - * addresses as well. - */ - SCTP_IPI_ADDR_LOCK_ASSERT(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - return (0); - } - size = 0; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - /* Count them if they are the right type */ - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) - size += sizeof(struct sockaddr_in6); - else - size += sizeof(struct sockaddr_in); -#else - size += sizeof(struct sockaddr_in); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - size += sizeof(struct sockaddr_in6); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - size += sizeof(struct sockaddr_conn); - break; -#endif - default: - break; - } - } - } - } else { - struct sctp_laddr *laddr; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - switch (laddr->ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) - size += sizeof(struct sockaddr_in6); - else - size += sizeof(struct sockaddr_in); -#else - size += sizeof(struct sockaddr_in); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - size += sizeof(struct sockaddr_in6); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - size += sizeof(struct sockaddr_conn); - break; -#endif - default: - break; - } - } - } - return (size); -} - -static size_t -sctp_max_size_addresses(struct sctp_inpcb *inp) -{ - size_t size; -#ifdef SCTP_MVRF - int id; -#endif - - SCTP_IPI_ADDR_RLOCK(); -#ifdef SCTP_MVRF -/* - * FIX ME: ?? this WILL count duplicate addresses if they appear - * in more than one VRF. - */ - /* Maximum size of all addresses for all VRFs on the endpoint */ - size = 0; - for (id = 0; id < inp->num_vrfs; id++) { - size += sctp_max_size_addresses_vrf(inp, inp->m_vrf_ids[id]); - } -#else - /* Maximum size of all addresses for the endpoint's default VRF */ - size = sctp_max_size_addresses_vrf(inp, inp->def_vrf_id); -#endif - SCTP_IPI_ADDR_RUNLOCK(); - return (size); -} - -static int -sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, - size_t optsize, void *p, int delay) -{ - int error; - int creat_lock_on = 0; - struct sctp_tcb *stcb = NULL; - struct sockaddr *sa; - unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; - uint32_t vrf_id; - sctp_assoc_t *a_id; - - SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { - /* We are already connected AND the TCP model */ - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); - return (EADDRINUSE); - } - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && - (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - SCTP_INP_RUNLOCK(inp); - } - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - return (EALREADY); - } - SCTP_INP_INCR_REF(inp); - SCTP_ASOC_CREATE_LOCK(inp); - creat_lock_on = 1; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); - error = EFAULT; - goto out_now; - } - totaddrp = (unsigned int *)optval; - totaddr = *totaddrp; - sa = (struct sockaddr *)(totaddrp + 1); - error = sctp_connectx_helper_find(inp, sa, totaddr, &num_v4, &num_v6, (unsigned int)(optsize - sizeof(int))); - if (error != 0) { - /* Already have or am bring up an association */ - SCTP_ASOC_CREATE_UNLOCK(inp); - creat_lock_on = 0; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - goto out_now; - } -#ifdef INET6 - if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && - (num_v6 > 0)) { - error = EINVAL; - goto out_now; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - (num_v4 > 0)) { - if (SCTP_IPV6_V6ONLY(inp)) { - /* - * if IPV6_V6ONLY flag, ignore connections destined - * to a v4 addr or v4-mapped addr - */ - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } - } -#endif /* INET6 */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { - /* Bind a ephemeral port */ - error = sctp_inpcb_bind(so, NULL, NULL, p); - if (error) { - goto out_now; - } - } - - /* FIX ME: do we want to pass in a vrf on the connect call? */ - vrf_id = inp->def_vrf_id; - - /* We are GOOD to go */ - stcb = sctp_aloc_assoc_connected(inp, sa, &error, 0, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, -#if defined(__FreeBSD__) && !defined(__Userspace__) - (struct thread *)p, -#elif defined(_WIN32) && !defined(__Userspace__) - (PKTHREAD)p, -#else - (struct proc *)p, -#endif - SCTP_INITIALIZE_AUTH_PARAMS); - if (stcb == NULL) { - /* Gak! no memory */ - goto out_now; - } - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - /* move to second address */ - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); - break; -#endif - default: - break; - } - - error = 0; - sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error); - /* Fill in the return id */ - if (error) { - goto out_now; - } - a_id = (sctp_assoc_t *)optval; - *a_id = sctp_get_associd(stcb); - - if (delay) { - /* doing delayed connection */ - stcb->asoc.delayed_connection = 1; - sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); - } else { - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - } - SCTP_TCB_UNLOCK(stcb); - out_now: - if (creat_lock_on) { - SCTP_ASOC_CREATE_UNLOCK(inp); - } - SCTP_INP_DECR_REF(inp); - return (error); -} - -#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ - SCTP_INP_RLOCK(inp); \ - stcb = LIST_FIRST(&inp->sctp_asoc_list); \ - if (stcb) { \ - SCTP_TCB_LOCK(stcb); \ - } \ - SCTP_INP_RUNLOCK(inp); \ - } else if (assoc_id > SCTP_ALL_ASSOC) { \ - stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ - if (stcb == NULL) { \ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ - error = ENOENT; \ - break; \ - } \ - } else { \ - stcb = NULL; \ - } \ -} - -#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ - if (size < sizeof(type)) { \ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ - error = EINVAL; \ - break; \ - } else { \ - destp = (type *)srcp; \ - } \ -} - -#if defined(__Userspace__) -int -#else -static int -#endif -sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, - void *p) { - struct sctp_inpcb *inp = NULL; - int error, val = 0; - struct sctp_tcb *stcb = NULL; - - if (optval == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return EINVAL; - } - error = 0; - - switch (optname) { - case SCTP_NODELAY: - case SCTP_AUTOCLOSE: - case SCTP_EXPLICIT_EOR: - case SCTP_AUTO_ASCONF: - case SCTP_DISABLE_FRAGMENTS: - case SCTP_I_WANT_MAPPED_V4_ADDR: - case SCTP_USE_EXT_RCVINFO: - SCTP_INP_RLOCK(inp); - switch (optname) { - case SCTP_DISABLE_FRAGMENTS: - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); - break; - case SCTP_I_WANT_MAPPED_V4_ADDR: - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); - break; - case SCTP_AUTO_ASCONF: - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* only valid for bound all sockets */ - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto flags_out; - } - break; - case SCTP_EXPLICIT_EOR: - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); - break; - case SCTP_NODELAY: - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); - break; - case SCTP_USE_EXT_RCVINFO: - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); - break; - case SCTP_AUTOCLOSE: - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) - val = sctp_ticks_to_secs(inp->sctp_ep.auto_close_time); - else - val = 0; - break; - - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; - } /* end switch (sopt->sopt_name) */ - if (*optsize < sizeof(val)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - flags_out: - SCTP_INP_RUNLOCK(inp); - if (error == 0) { - /* return the option value */ - *(int *)optval = val; - *optsize = sizeof(val); - } - break; - case SCTP_GET_PACKET_LOG: - { -#ifdef SCTP_PACKET_LOGGING - uint8_t *target; - int ret; - - SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); - ret = sctp_copy_out_packet_log(target , (int)*optsize); - *optsize = ret; -#else - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; -#endif - break; - } - case SCTP_REUSE_PORT: - { - uint32_t *value; - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { - /* Can't do this for a 1-m socket */ - error = EINVAL; - break; - } - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); - *optsize = sizeof(uint32_t); - break; - } - case SCTP_PARTIAL_DELIVERY_POINT: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - *value = inp->partial_delivery_point; - *optsize = sizeof(uint32_t); - break; - } - case SCTP_FRAGMENT_INTERLEAVE: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { - *value = SCTP_FRAG_LEVEL_2; - } else { - *value = SCTP_FRAG_LEVEL_1; - } - } else { - *value = SCTP_FRAG_LEVEL_0; - } - *optsize = sizeof(uint32_t); - break; - } - case SCTP_INTERLEAVING_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.idata_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - if (inp->idata_supported) { - av->assoc_value = 1; - } else { - av->assoc_value = 0; - } - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_CMT_ON_OFF: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - av->assoc_value = stcb->asoc.sctp_cmt_on_off; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->sctp_cmt_on_off; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_PLUGGABLE_CC: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - av->assoc_value = stcb->asoc.congestion_control_module; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->sctp_ep.sctp_default_cc_module; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_CC_OPTION: - { - struct sctp_cc_option *cc_opt; - - SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); - SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); - if (stcb == NULL) { - error = EINVAL; - } else { - if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { - error = ENOTSUP; - } else { - error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 0, cc_opt); - *optsize = sizeof(struct sctp_cc_option); - } - SCTP_TCB_UNLOCK(stcb); - } - break; - } - case SCTP_STREAM_SCHEDULER: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - av->assoc_value = stcb->asoc.stream_scheduling_module; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->sctp_ep.sctp_default_ss_module; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_STREAM_SCHEDULER_VALUE: - { - struct sctp_stream_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - if ((av->stream_id >= stcb->asoc.streamoutcnt) || - (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - &av->stream_value) < 0)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } else { - *optsize = sizeof(struct sctp_stream_value); - } - SCTP_TCB_UNLOCK(stcb); - } else { - /* Can't get stream value without association */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; - } - case SCTP_GET_ADDR_LEN: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - error = EINVAL; -#ifdef INET - if (av->assoc_value == AF_INET) { - av->assoc_value = sizeof(struct sockaddr_in); - error = 0; - } -#endif -#ifdef INET6 - if (av->assoc_value == AF_INET6) { - av->assoc_value = sizeof(struct sockaddr_in6); - error = 0; - } -#endif -#if defined(__Userspace__) - if (av->assoc_value == AF_CONN) { - av->assoc_value = sizeof(struct sockaddr_conn); - error = 0; - } -#endif - if (error) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } else { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_GET_ASSOC_NUMBER: - { - uint32_t *value, cnt; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - SCTP_INP_RLOCK(inp); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* Can't do this for a 1-1 socket */ - error = EINVAL; - SCTP_INP_RUNLOCK(inp); - break; - } - cnt = 0; - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - cnt++; - } - SCTP_INP_RUNLOCK(inp); - *value = cnt; - *optsize = sizeof(uint32_t); - break; - } - case SCTP_GET_ASSOC_ID_LIST: - { - struct sctp_assoc_ids *ids; - uint32_t at; - size_t limit; - - SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); - SCTP_INP_RLOCK(inp); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* Can't do this for a 1-1 socket */ - error = EINVAL; - SCTP_INP_RUNLOCK(inp); - break; - } - at = 0; - limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - if (at < limit) { - ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); - if (at == 0) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - SCTP_INP_RUNLOCK(inp); - if (error == 0) { - ids->gaids_number_of_ids = at; - *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); - } - break; - } - case SCTP_CONTEXT: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.context; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->sctp_context; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_VRF_ID: - { - uint32_t *default_vrfid; - - SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); - *default_vrfid = inp->def_vrf_id; - *optsize = sizeof(uint32_t); - break; - } - case SCTP_GET_ASOC_VRF: - { - struct sctp_assoc_value *id; - - SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, id->assoc_id); - if (stcb == NULL) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } else { - id->assoc_value = stcb->asoc.vrf_id; - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_GET_VRF_IDS: - { -#ifdef SCTP_MVRF - int siz_needed; - uint32_t *vrf_ids; - - SCTP_CHECK_AND_CAST(vrf_ids, optval, uint32_t, *optsize); - siz_needed = inp->num_vrfs * sizeof(uint32_t); - if (*optsize < siz_needed) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } else { - memcpy(vrf_ids, inp->m_vrf_ids, siz_needed); - *optsize = siz_needed; - } -#else - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; -#endif - break; - } - case SCTP_GET_NONCE_VALUES: - { - struct sctp_get_nonce_values *gnv; - - SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); - SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); - - if (stcb) { - gnv->gn_peers_tag = stcb->asoc.peer_vtag; - gnv->gn_local_tag = stcb->asoc.my_vtag; - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_get_nonce_values); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; - } - break; - } - case SCTP_DELAYED_SACK: - { - struct sctp_sack_info *sack; - - SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); - SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); - if (stcb) { - sack->sack_delay = stcb->asoc.delayed_ack; - sack->sack_freq = stcb->asoc.sack_freq; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (sack->sack_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - sack->sack_delay = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); - sack->sack_freq = inp->sctp_ep.sctp_sack_freq; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_sack_info); - } - break; - } - case SCTP_GET_SNDBUF_USE: - { - struct sctp_sockstat *ss; - - SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); - SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); - - if (stcb) { - ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; - ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + - stcb->asoc.size_on_all_streams); - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_sockstat); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; - } - break; - } - case SCTP_MAX_BURST: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.max_burst; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->sctp_ep.max_burst; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_MAXSEG: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.sctp_frag_point; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->sctp_frag_point; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_GET_STAT_LOG: - error = sctp_fill_stat_log(optval, optsize); - break; - case SCTP_EVENTS: - { - struct sctp_event_subscribe *events; - - SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); - memset(events, 0, sizeof(struct sctp_event_subscribe)); - SCTP_INP_RLOCK(inp); - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) - events->sctp_data_io_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) - events->sctp_association_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) - events->sctp_address_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) - events->sctp_send_failure_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) - events->sctp_peer_error_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) - events->sctp_shutdown_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) - events->sctp_partial_delivery_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) - events->sctp_adaptation_layer_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) - events->sctp_authentication_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) - events->sctp_sender_dry_event = 1; - - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) - events->sctp_stream_reset_event = 1; - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(struct sctp_event_subscribe); - break; - } - case SCTP_ADAPTATION_LAYER: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - - SCTP_INP_RLOCK(inp); - *value = inp->sctp_ep.adaptation_layer_indicator; - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(uint32_t); - break; - } - case SCTP_SET_INITIAL_DBG_SEQ: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - SCTP_INP_RLOCK(inp); - *value = inp->sctp_ep.initial_sequence_debug; - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(uint32_t); - break; - } - case SCTP_GET_LOCAL_ADDR_SIZE: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - SCTP_INP_RLOCK(inp); - *value = (uint32_t)sctp_max_size_addresses(inp); - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(uint32_t); - break; - } - case SCTP_GET_REMOTE_ADDR_SIZE: - { - uint32_t *value; - struct sctp_nets *net; - size_t size; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - /* FIXME MT: change to sctp_assoc_value? */ - SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t)*value); - - if (stcb != NULL) { - size = 0; - /* Count the sizes */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { - size += sizeof(struct sockaddr_in6); - } else { - size += sizeof(struct sockaddr_in); - } -#else - size += sizeof(struct sockaddr_in); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - size += sizeof(struct sockaddr_in6); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - size += sizeof(struct sockaddr_conn); - break; -#endif - default: - break; - } - } - SCTP_TCB_UNLOCK(stcb); - *value = (uint32_t)size; - *optsize = sizeof(uint32_t); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((sctp_assoc_t)*value <= SCTP_ALL_ASSOC)) { - error = EINVAL; - } else { - error = ENOENT; - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } - break; - } - case SCTP_GET_PEER_ADDRESSES: - /* - * Get the address information, an array is passed in to - * fill up we pack it. - */ - { - size_t cpsz, left; - struct sockaddr *addr; - struct sctp_nets *net; - struct sctp_getaddresses *saddr; - - SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); - SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); - - if (stcb != NULL) { - left = *optsize - offsetof(struct sctp_getaddresses, addr); - *optsize = offsetof(struct sctp_getaddresses, addr); - addr = &saddr->addr[0].sa; - - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { - cpsz = sizeof(struct sockaddr_in6); - } else { - cpsz = sizeof(struct sockaddr_in); - } -#else - cpsz = sizeof(struct sockaddr_in); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - cpsz = sizeof(struct sockaddr_in6); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - cpsz = sizeof(struct sockaddr_conn); - break; -#endif - default: - cpsz = 0; - break; - } - if (cpsz == 0) { - break; - } - if (left < cpsz) { - /* not enough room. */ - break; - } -#if defined(INET) && defined(INET6) - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && - (net->ro._l_addr.sa.sa_family == AF_INET)) { - /* Must map the address */ - in6_sin_2_v4mapsin6(&net->ro._l_addr.sin, - (struct sockaddr_in6 *)addr); - } else { - memcpy(addr, &net->ro._l_addr, cpsz); - } -#else - memcpy(addr, &net->ro._l_addr, cpsz); -#endif - ((struct sockaddr_in *)addr)->sin_port = stcb->rport; - - addr = (struct sockaddr *)((caddr_t)addr + cpsz); - left -= cpsz; - *optsize += cpsz; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (saddr->sget_assoc_id <= SCTP_ALL_ASSOC)) { - error = EINVAL; - } else { - error = ENOENT; - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } - break; - } - case SCTP_GET_LOCAL_ADDRESSES: - { - size_t limit, actual; - struct sctp_getaddresses *saddr; - - SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); - SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((saddr->sget_assoc_id == SCTP_CURRENT_ASSOC) || - (saddr->sget_assoc_id == SCTP_ALL_ASSOC))) { - error = EINVAL; - } else { - limit = *optsize - offsetof(struct sctp_getaddresses, addr); - actual = sctp_fill_up_addresses(inp, stcb, limit, &saddr->addr[0].sa); - *optsize = offsetof(struct sctp_getaddresses, addr) + actual; - } - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - break; - } - case SCTP_PEER_ADDR_PARAMS: - { - struct sctp_paddrparams *paddrp; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); - SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); - -#if defined(INET) && defined(INET6) - if (paddrp->spp_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&paddrp->spp_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&paddrp->spp_address; - } - } else { - addr = (struct sockaddr *)&paddrp->spp_address; - } -#else - addr = (struct sockaddr *)&paddrp->spp_address; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - if ((stcb != NULL) && (net == NULL)) { -#ifdef INET - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr != INADDR_ANY) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)addr; - if (sconn->sconn_addr != NULL) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif - { - error = EAFNOSUPPORT; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - - if (stcb != NULL) { - /* Applies to the specific association */ - paddrp->spp_flags = 0; - if (net != NULL) { - paddrp->spp_hbinterval = net->heart_beat_delay; - paddrp->spp_pathmaxrxt = net->failure_threshold; - paddrp->spp_pathmtu = net->mtu; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - paddrp->spp_pathmtu -= SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - paddrp->spp_pathmtu -= sizeof(struct sctphdr); - break; -#endif - default: - break; - } - /* get flags for HB */ - if (net->dest_state & SCTP_ADDR_NOHB) { - paddrp->spp_flags |= SPP_HB_DISABLE; - } else { - paddrp->spp_flags |= SPP_HB_ENABLE; - } - /* get flags for PMTU */ - if (net->dest_state & SCTP_ADDR_NO_PMTUD) { - paddrp->spp_flags |= SPP_PMTUD_DISABLE; - } else { - paddrp->spp_flags |= SPP_PMTUD_ENABLE; - } - if (net->dscp & 0x01) { - paddrp->spp_dscp = net->dscp & 0xfc; - paddrp->spp_flags |= SPP_DSCP; - } -#ifdef INET6 - if ((net->ro._l_addr.sa.sa_family == AF_INET6) && - (net->flowlabel & 0x80000000)) { - paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; - paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; - } -#endif - } else { - /* - * No destination so return default - * value - */ - paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; - paddrp->spp_pathmtu = stcb->asoc.default_mtu; - if (stcb->asoc.default_dscp & 0x01) { - paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; - paddrp->spp_flags |= SPP_DSCP; - } -#ifdef INET6 - if (stcb->asoc.default_flowlabel & 0x80000000) { - paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; - paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; - } -#endif - /* default settings should be these */ - if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { - paddrp->spp_flags |= SPP_HB_DISABLE; - } else { - paddrp->spp_flags |= SPP_HB_ENABLE; - } - if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { - paddrp->spp_flags |= SPP_PMTUD_DISABLE; - } else { - paddrp->spp_flags |= SPP_PMTUD_ENABLE; - } - paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; - } - paddrp->spp_assoc_id = sctp_get_associd(stcb); - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC))) { - /* Use endpoint defaults */ - SCTP_INP_RLOCK(inp); - paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; - paddrp->spp_hbinterval = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); - paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; - /* get inp's default */ - if (inp->sctp_ep.default_dscp & 0x01) { - paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; - paddrp->spp_flags |= SPP_DSCP; - } -#ifdef INET6 - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - (inp->sctp_ep.default_flowlabel & 0x80000000)) { - paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; - paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; - } -#endif - paddrp->spp_pathmtu = inp->sctp_ep.default_mtu; - - if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { - paddrp->spp_flags |= SPP_HB_ENABLE; - } else { - paddrp->spp_flags |= SPP_HB_DISABLE; - } - if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { - paddrp->spp_flags |= SPP_PMTUD_ENABLE; - } else { - paddrp->spp_flags |= SPP_PMTUD_DISABLE; - } - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_paddrparams); - } - break; - } - case SCTP_GET_PEER_ADDR_INFO: - { - struct sctp_paddrinfo *paddri; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); - SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); - -#if defined(INET) && defined(INET6) - if (paddri->spinfo_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&paddri->spinfo_address; - } - } else { - addr = (struct sockaddr *)&paddri->spinfo_address; - } -#else - addr = (struct sockaddr *)&paddri->spinfo_address; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - - if ((stcb != NULL) && (net != NULL)) { - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { - /* It's unconfirmed */ - paddri->spinfo_state = SCTP_UNCONFIRMED; - } else if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* It's active */ - paddri->spinfo_state = SCTP_ACTIVE; - } else { - /* It's inactive */ - paddri->spinfo_state = SCTP_INACTIVE; - } - paddri->spinfo_cwnd = net->cwnd; - paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; - paddri->spinfo_rto = net->RTO; - paddri->spinfo_assoc_id = sctp_get_associd(stcb); - paddri->spinfo_mtu = net->mtu; - switch (addr->sa_family) { -#if defined(INET) - case AF_INET: - paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; - break; -#endif -#if defined(INET6) - case AF_INET6: - paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - paddri->spinfo_mtu -= sizeof(struct sctphdr); - break; -#endif - default: - break; - } - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_paddrinfo); - } else { - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - } - break; - } - case SCTP_PCB_STATUS: - { - struct sctp_pcbinfo *spcb; - - SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); - sctp_fill_pcbinfo(spcb); - *optsize = sizeof(struct sctp_pcbinfo); - break; - } - case SCTP_STATUS: - { - struct sctp_nets *net; - struct sctp_status *sstat; - - SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); - SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); - - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state); - sstat->sstat_assoc_id = sctp_get_associd(stcb); - sstat->sstat_rwnd = stcb->asoc.peers_rwnd; - sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; - /* - * We can't include chunks that have been passed to - * the socket layer. Only things in queue. - */ - sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + - stcb->asoc.cnt_on_all_streams); - sstat->sstat_instrms = stcb->asoc.streamincnt; - sstat->sstat_outstrms = stcb->asoc.streamoutcnt; - sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb); - net = stcb->asoc.primary_destination; - if (net != NULL) { -#ifdef HAVE_SA_LEN - memcpy(&sstat->sstat_primary.spinfo_address, - &net->ro._l_addr, - ((struct sockaddr *)(&net->ro._l_addr))->sa_len); -#else - switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) { -#if defined(INET) - case AF_INET: - memcpy(&sstat->sstat_primary.spinfo_address, - &net->ro._l_addr, - sizeof(struct sockaddr_in)); - break; -#endif -#if defined(INET6) - case AF_INET6: - memcpy(&sstat->sstat_primary.spinfo_address, - &net->ro._l_addr, - sizeof(struct sockaddr_in6)); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(&sstat->sstat_primary.spinfo_address, - &net->ro._l_addr, - sizeof(struct sockaddr_conn)); - break; -#endif - default: - break; - } -#endif - ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; - /* - * Again the user can get info from sctp_constants.h - * for what the state of the network is. - */ - if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { - /* It's unconfirmed */ - sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; - } else if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* It's active */ - sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; - } else { - /* It's inactive */ - sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; - } - sstat->sstat_primary.spinfo_cwnd = net->cwnd; - sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; - sstat->sstat_primary.spinfo_rto = net->RTO; - sstat->sstat_primary.spinfo_mtu = net->mtu; - switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) { -#if defined(INET) - case AF_INET: - sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; - break; -#endif -#if defined(INET6) - case AF_INET6: - sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - sstat->sstat_primary.spinfo_mtu -= sizeof(struct sctphdr); - break; -#endif - default: - break; - } - } else { - memset(&sstat->sstat_primary, 0, sizeof(struct sctp_paddrinfo)); - } - sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_status); - break; - } - case SCTP_RTOINFO: - { - struct sctp_rtoinfo *srto; - - SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); - SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); - - if (stcb) { - srto->srto_initial = stcb->asoc.initial_rto; - srto->srto_max = stcb->asoc.maxrto; - srto->srto_min = stcb->asoc.minrto; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (srto->srto_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - srto->srto_initial = inp->sctp_ep.initial_rto; - srto->srto_max = inp->sctp_ep.sctp_maxrto; - srto->srto_min = inp->sctp_ep.sctp_minrto; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_rtoinfo); - } - break; - } - case SCTP_TIMEOUTS: - { - struct sctp_timeouts *stimo; - - SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); - SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); - - if (stcb) { - stimo->stimo_init= stcb->asoc.timoinit; - stimo->stimo_data= stcb->asoc.timodata; - stimo->stimo_sack= stcb->asoc.timosack; - stimo->stimo_shutdown= stcb->asoc.timoshutdown; - stimo->stimo_heartbeat= stcb->asoc.timoheartbeat; - stimo->stimo_cookie= stcb->asoc.timocookie; - stimo->stimo_shutdownack= stcb->asoc.timoshutdownack; - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_timeouts); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; - } - case SCTP_ASSOCINFO: - { - struct sctp_assocparams *sasoc; - - SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); - SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); - - if (stcb) { - sasoc->sasoc_cookie_life = sctp_ticks_to_msecs(stcb->asoc.cookie_life); - sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; - sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; - sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; - sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - sasoc->sasoc_cookie_life = sctp_ticks_to_msecs(inp->sctp_ep.def_cookie_life); - sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; - sasoc->sasoc_number_peer_destinations = 0; - sasoc->sasoc_peer_rwnd = 0; - sasoc->sasoc_local_rwnd = (uint32_t)sbspace(&inp->sctp_socket->so_rcv); - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assocparams); - } - break; - } - case SCTP_DEFAULT_SEND_PARAM: - { - struct sctp_sndrcvinfo *s_info; - - SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); - SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); - - if (stcb) { - memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_sndrcvinfo); - } - break; - } - case SCTP_INITMSG: - { - struct sctp_initmsg *sinit; - - SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); - SCTP_INP_RLOCK(inp); - sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; - sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; - sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; - sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(struct sctp_initmsg); - break; - } - case SCTP_PRIMARY_ADDR: - /* we allow a "get" operation on this */ - { - struct sctp_setprim *ssp; - - SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); - SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); - - if (stcb) { - union sctp_sockstore *addr; - - addr = &stcb->asoc.primary_destination->ro._l_addr; - switch (addr->sa.sa_family) { -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { - in6_sin_2_v4mapsin6(&addr->sin, - (struct sockaddr_in6 *)&ssp->ssp_addr); - } else { - memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in)); - } -#else - memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in)); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6)); - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(&ssp->ssp_addr, &addr->sconn, sizeof(struct sockaddr_conn)); - break; -#endif - default: - break; - } - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_setprim); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; - } - case SCTP_HMAC_IDENT: - { - struct sctp_hmacalgo *shmac; - sctp_hmaclist_t *hmaclist; - size_t size; - int i; - - SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); - - SCTP_INP_RLOCK(inp); - hmaclist = inp->sctp_ep.local_hmacs; - if (hmaclist == NULL) { - /* no HMACs to return */ - *optsize = sizeof(*shmac); - SCTP_INP_RUNLOCK(inp); - break; - } - /* is there room for all of the hmac ids? */ - size = sizeof(*shmac) + (hmaclist->num_algo * - sizeof(shmac->shmac_idents[0])); - if (*optsize < size) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_INP_RUNLOCK(inp); - break; - } - /* copy in the list */ - shmac->shmac_number_of_idents = hmaclist->num_algo; - for (i = 0; i < hmaclist->num_algo; i++) { - shmac->shmac_idents[i] = hmaclist->hmac[i]; - } - SCTP_INP_RUNLOCK(inp); - *optsize = size; - break; - } - case SCTP_AUTH_ACTIVE_KEY: - { - struct sctp_authkeyid *scact; - - SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); - SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); - - if (stcb) { - /* get the active key on the assoc */ - scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (scact->scact_assoc_id == SCTP_FUTURE_ASSOC))) { - /* get the endpoint active key */ - SCTP_INP_RLOCK(inp); - scact->scact_keynumber = inp->sctp_ep.default_keyid; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_authkeyid); - } - break; - } - case SCTP_LOCAL_AUTH_CHUNKS: - { - struct sctp_authchunks *sac; - sctp_auth_chklist_t *chklist = NULL; - size_t size = 0; - - SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); - SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); - - if (stcb) { - /* get off the assoc */ - chklist = stcb->asoc.local_auth_chunks; - /* is there enough space? */ - size = sctp_auth_get_chklist_size(chklist); - if (*optsize < (sizeof(struct sctp_authchunks) + size)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } else { - /* copy in the chunks */ - (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); - sac->gauth_number_of_chunks = (uint32_t)size; - *optsize = sizeof(struct sctp_authchunks) + size; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC))) { - /* get off the endpoint */ - SCTP_INP_RLOCK(inp); - chklist = inp->sctp_ep.local_auth_chunks; - /* is there enough space? */ - size = sctp_auth_get_chklist_size(chklist); - if (*optsize < (sizeof(struct sctp_authchunks) + size)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } else { - /* copy in the chunks */ - (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); - sac->gauth_number_of_chunks = (uint32_t)size; - *optsize = sizeof(struct sctp_authchunks) + size; - } - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_PEER_AUTH_CHUNKS: - { - struct sctp_authchunks *sac; - sctp_auth_chklist_t *chklist = NULL; - size_t size = 0; - - SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); - SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); - - if (stcb) { - /* get off the assoc */ - chklist = stcb->asoc.peer_auth_chunks; - /* is there enough space? */ - size = sctp_auth_get_chklist_size(chklist); - if (*optsize < (sizeof(struct sctp_authchunks) + size)) { - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - } else { - /* copy in the chunks */ - (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); - sac->gauth_number_of_chunks = (uint32_t)size; - *optsize = sizeof(struct sctp_authchunks) + size; - } - SCTP_TCB_UNLOCK(stcb); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - } - break; - } -#if defined(HAVE_SCTP_PEELOFF_SOCKOPT) - case SCTP_PEELOFF: - { - struct sctp_peeloff_opt *peeloff; - - SCTP_CHECK_AND_CAST(peeloff, optval, struct sctp_peeloff_opt, *optsize); - /* do the peeloff */ - error = sctp_peeloff_option(p, peeloff); - if (error == 0) { - *optsize = sizeof(struct sctp_peeloff_opt); - } - } - break; -#endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ - case SCTP_EVENT: - { - struct sctp_event *event; - uint32_t event_type; - - SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); - SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); - - switch (event->se_type) { - case SCTP_ASSOC_CHANGE: - event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; - break; - case SCTP_PEER_ADDR_CHANGE: - event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; - break; - case SCTP_REMOTE_ERROR: - event_type = SCTP_PCB_FLAGS_RECVPEERERR; - break; - case SCTP_SEND_FAILED: - event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; - break; - case SCTP_SHUTDOWN_EVENT: - event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; - break; - case SCTP_ADAPTATION_INDICATION: - event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; - break; - case SCTP_PARTIAL_DELIVERY_EVENT: - event_type = SCTP_PCB_FLAGS_PDAPIEVNT; - break; - case SCTP_AUTHENTICATION_EVENT: - event_type = SCTP_PCB_FLAGS_AUTHEVNT; - break; - case SCTP_STREAM_RESET_EVENT: - event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; - break; - case SCTP_SENDER_DRY_EVENT: - event_type = SCTP_PCB_FLAGS_DRYEVNT; - break; - case SCTP_NOTIFICATIONS_STOPPED_EVENT: - event_type = 0; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); - error = ENOTSUP; - break; - case SCTP_ASSOC_RESET_EVENT: - event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; - break; - case SCTP_STREAM_CHANGE_EVENT: - event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; - break; - case SCTP_SEND_FAILED_EVENT: - event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; - break; - default: - event_type = 0; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if (event_type > 0) { - if (stcb) { - event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (event->se_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - event->se_on = sctp_is_feature_on(inp, event_type); - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - } - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - if (error == 0) { - *optsize = sizeof(struct sctp_event); - } - break; - } - case SCTP_RECVRCVINFO: - if (*optsize < sizeof(int)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } else { - SCTP_INP_RLOCK(inp); - *(int *)optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(int); - } - break; - case SCTP_RECVNXTINFO: - if (*optsize < sizeof(int)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } else { - SCTP_INP_RLOCK(inp); - *(int *)optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); - SCTP_INP_RUNLOCK(inp); - *optsize = sizeof(int); - } - break; - case SCTP_DEFAULT_SNDINFO: - { - struct sctp_sndinfo *info; - - SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); - SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); - - if (stcb) { - info->snd_sid = stcb->asoc.def_send.sinfo_stream; - info->snd_flags = stcb->asoc.def_send.sinfo_flags; - info->snd_flags &= 0xfff0; - info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; - info->snd_context = stcb->asoc.def_send.sinfo_context; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (info->snd_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - info->snd_sid = inp->def_send.sinfo_stream; - info->snd_flags = inp->def_send.sinfo_flags; - info->snd_flags &= 0xfff0; - info->snd_ppid = inp->def_send.sinfo_ppid; - info->snd_context = inp->def_send.sinfo_context; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_sndinfo); - } - break; - } - case SCTP_DEFAULT_PRINFO: - { - struct sctp_default_prinfo *info; - - SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); - SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); - - if (stcb) { - info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); - info->pr_value = stcb->asoc.def_send.sinfo_timetolive; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (info->pr_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); - info->pr_value = inp->def_send.sinfo_timetolive; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_default_prinfo); - } - break; - } - case SCTP_PEER_ADDR_THLDS: - { - struct sctp_paddrthlds *thlds; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); - SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); - -#if defined(INET) && defined(INET6) - if (thlds->spt_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&thlds->spt_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&thlds->spt_address; - } - } else { - addr = (struct sockaddr *)&thlds->spt_address; - } -#else - addr = (struct sockaddr *)&thlds->spt_address; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - if ((stcb != NULL) && (net == NULL)) { -#ifdef INET - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr != INADDR_ANY) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)addr; - if (sconn->sconn_addr != NULL) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif - { - error = EAFNOSUPPORT; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - - if (stcb != NULL) { - if (net != NULL) { - thlds->spt_pathmaxrxt = net->failure_threshold; - thlds->spt_pathpfthld = net->pf_threshold; - thlds->spt_pathcpthld = 0xffff; - } else { - thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; - thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; - thlds->spt_pathcpthld = 0xffff; - } - thlds->spt_assoc_id = sctp_get_associd(stcb); - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC))) { - /* Use endpoint defaults */ - SCTP_INP_RLOCK(inp); - thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; - thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; - thlds->spt_pathcpthld = 0xffff; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_paddrthlds); - } - break; - } - case SCTP_REMOTE_UDP_ENCAPS_PORT: - { - struct sctp_udpencaps *encaps; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); - SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); - -#if defined(INET) && defined(INET6) - if (encaps->sue_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&encaps->sue_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&encaps->sue_address; - } - } else { - addr = (struct sockaddr *)&encaps->sue_address; - } -#else - addr = (struct sockaddr *)&encaps->sue_address; -#endif - if (stcb) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - if ((stcb != NULL) && (net == NULL)) { -#ifdef INET - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr != INADDR_ANY) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)addr; - if (sconn->sconn_addr != NULL) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } else -#endif - { - error = EAFNOSUPPORT; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - - if (stcb != NULL) { - if (net) { - encaps->sue_port = net->port; - } else { - encaps->sue_port = stcb->asoc.port; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - encaps->sue_port = inp->sctp_ep.port; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_udpencaps); - } - break; - } - case SCTP_ECN_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.ecn_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->ecn_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_PR_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.prsctp_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->prsctp_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_AUTH_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.auth_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->auth_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_ASCONF_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.asconf_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->asconf_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_RECONFIG_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.reconfig_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->reconfig_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_NRSACK_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.nrsack_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->nrsack_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_PKTDROP_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.pktdrop_supported; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->pktdrop_supported; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_ENABLE_STREAM_RESET: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = (uint32_t)stcb->asoc.local_strreset_support; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = (uint32_t)inp->local_strreset_support; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - case SCTP_PR_STREAM_STATUS: - { - struct sctp_prstatus *sprstat; - uint16_t sid; - uint16_t policy; - - SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize); - SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id); - - sid = sprstat->sprstat_sid; - policy = sprstat->sprstat_policy; -#if defined(SCTP_DETAILED_STR_STATS) - if ((stcb != NULL) && - (sid < stcb->asoc.streamoutcnt) && - (policy != SCTP_PR_SCTP_NONE) && - ((policy <= SCTP_PR_SCTP_MAX) || - (policy == SCTP_PR_SCTP_ALL))) { - if (policy == SCTP_PR_SCTP_ALL) { - sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; - sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; - } else { - sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy]; - sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy]; - } -#else - if ((stcb != NULL) && - (sid < stcb->asoc.streamoutcnt) && - (policy == SCTP_PR_SCTP_ALL)) { - sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; - sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; -#endif - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - if (error == 0) { - *optsize = sizeof(struct sctp_prstatus); - } - break; - } - case SCTP_PR_ASSOC_STATUS: - { - struct sctp_prstatus *sprstat; - uint16_t policy; - - SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize); - SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id); - - policy = sprstat->sprstat_policy; - if ((stcb != NULL) && - (policy != SCTP_PR_SCTP_NONE) && - ((policy <= SCTP_PR_SCTP_MAX) || - (policy == SCTP_PR_SCTP_ALL))) { - if (policy == SCTP_PR_SCTP_ALL) { - sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0]; - sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0]; - } else { - sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy]; - sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy]; - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - if (error == 0) { - *optsize = sizeof(struct sctp_prstatus); - } - break; - } - case SCTP_MAX_CWND: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - av->assoc_value = stcb->asoc.max_cwnd; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_RLOCK(inp); - av->assoc_value = inp->max_cwnd; - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - if (error == 0) { - *optsize = sizeof(struct sctp_assoc_value); - } - break; - } - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; - break; - } /* end switch (sopt->sopt_name) */ - if (error) { - *optsize = 0; - } - return (error); -} - -#if defined(__Userspace__) -int -#else -static int -#endif -sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, - void *p) -{ - int error, set_opt; - uint32_t *mopt; - struct sctp_tcb *stcb = NULL; - struct sctp_inpcb *inp = NULL; - uint32_t vrf_id; - - if (optval == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - vrf_id = inp->def_vrf_id; - - error = 0; - switch (optname) { - case SCTP_NODELAY: - case SCTP_AUTOCLOSE: - case SCTP_AUTO_ASCONF: - case SCTP_EXPLICIT_EOR: - case SCTP_DISABLE_FRAGMENTS: - case SCTP_USE_EXT_RCVINFO: - case SCTP_I_WANT_MAPPED_V4_ADDR: - /* copy in the option value */ - SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); - set_opt = 0; - if (error) - break; - switch (optname) { - case SCTP_DISABLE_FRAGMENTS: - set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; - break; - case SCTP_AUTO_ASCONF: - /* - * NOTE: we don't really support this flag - */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* only valid for bound all sockets */ - if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && - (*mopt != 0)) { - /* forbidden by admin */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); - return (EPERM); - } - set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - break; - case SCTP_EXPLICIT_EOR: - set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; - break; - case SCTP_USE_EXT_RCVINFO: - set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; - break; - case SCTP_I_WANT_MAPPED_V4_ADDR: - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - break; - case SCTP_NODELAY: - set_opt = SCTP_PCB_FLAGS_NODELAY; - break; - case SCTP_AUTOCLOSE: - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; - /* - * The value is in ticks. Note this does not effect - * old associations, only new ones. - */ - inp->sctp_ep.auto_close_time = sctp_secs_to_ticks(*mopt); - break; - } - SCTP_INP_WLOCK(inp); - if (*mopt != 0) { - sctp_feature_on(inp, set_opt); - } else { - sctp_feature_off(inp, set_opt); - } - SCTP_INP_WUNLOCK(inp); - break; - case SCTP_REUSE_PORT: - { - SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { - /* Can't set it after we are bound */ - error = EINVAL; - break; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { - /* Can't do this for a 1-m socket */ - error = EINVAL; - break; - } - if (optval) - sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); - else - sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); - break; - } - case SCTP_PARTIAL_DELIVERY_POINT: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); - if (*value > SCTP_SB_LIMIT_RCV(so)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - inp->partial_delivery_point = *value; - break; - } - case SCTP_FRAGMENT_INTERLEAVE: - /* not yet until we re-write sctp_recvmsg() */ - { - uint32_t *level; - - SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); - if (*level == SCTP_FRAG_LEVEL_2) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); - } else if (*level == SCTP_FRAG_LEVEL_1) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); - } else if (*level == SCTP_FRAG_LEVEL_0) { - sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); - - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; - } - case SCTP_INTERLEAVING_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->idata_supported = 0; - } else { - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && - (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS))) { - inp->idata_supported = 1; - } else { - /* Must have Frag interleave and stream interleave on */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_CMT_ON_OFF: - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - if (av->assoc_value > SCTP_CMT_MAX) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - stcb->asoc.sctp_cmt_on_off = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_FUTURE_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->sctp_cmt_on_off = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_CURRENT_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.sctp_cmt_on_off = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; - } - break; - case SCTP_PLUGGABLE_CC: - { - struct sctp_assoc_value *av; - struct sctp_nets *net; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - if ((av->assoc_value != SCTP_CC_RFC2581) && - (av->assoc_value != SCTP_CC_HSTCP) && - (av->assoc_value != SCTP_CC_HTCP) && - (av->assoc_value != SCTP_CC_RTCC)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; - stcb->asoc.congestion_control_module = av->assoc_value; - if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); - } - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_FUTURE_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->sctp_ep.sctp_default_cc_module = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_CURRENT_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; - stcb->asoc.congestion_control_module = av->assoc_value; - if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); - } - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_CC_OPTION: - { - struct sctp_cc_option *cc_opt; - - SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); - SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); - if (stcb == NULL) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC)) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { - (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, cc_opt); - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } else { - error = EINVAL; - } - } else { - if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { - error = ENOTSUP; - } else { - error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, - cc_opt); - } - SCTP_TCB_UNLOCK(stcb); - } - break; - } - case SCTP_STREAM_SCHEDULER: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - if ((av->assoc_value != SCTP_SS_DEFAULT) && - (av->assoc_value != SCTP_SS_RR) && - (av->assoc_value != SCTP_SS_RR_PKT) && - (av->assoc_value != SCTP_SS_PRIO) && - (av->assoc_value != SCTP_SS_FB) && - (av->assoc_value != SCTP_SS_FCFS)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, true); - stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; - stcb->asoc.stream_scheduling_module = av->assoc_value; - stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_FUTURE_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->sctp_ep.sctp_default_ss_module = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_CURRENT_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, true); - stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; - stcb->asoc.stream_scheduling_module = av->assoc_value; - stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_STREAM_SCHEDULER_VALUE: - { - struct sctp_stream_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - if ((av->stream_id >= stcb->asoc.streamoutcnt) || - (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - av->stream_value) < 0)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_CURRENT_ASSOC)) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (av->stream_id < stcb->asoc.streamoutcnt) { - stcb->asoc.ss_functions.sctp_ss_set_value(stcb, - &stcb->asoc, - &stcb->asoc.strmout[av->stream_id], - av->stream_value); - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } else { - /* Can't set stream value without association */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_CLR_STAT_LOG: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; - break; - case SCTP_CONTEXT: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - stcb->asoc.context = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_FUTURE_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->sctp_context = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_CURRENT_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.context = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_VRF_ID: - { - uint32_t *default_vrfid; -#ifdef SCTP_MVRF - int i; -#endif - SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); - if (*default_vrfid > SCTP_MAX_VRF_ID) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - /* The VRF must be in the VRF list */ - if (*default_vrfid == inp->m_vrf_ids[i]) { - SCTP_INP_WLOCK(inp); - inp->def_vrf_id = *default_vrfid; - SCTP_INP_WUNLOCK(inp); - goto sctp_done; - } - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; -#else - inp->def_vrf_id = *default_vrfid; -#endif -#ifdef SCTP_MVRF - sctp_done: -#endif - break; - } - case SCTP_DEL_VRF_ID: - { -#ifdef SCTP_MVRF - uint32_t *del_vrfid; - int i, fnd = 0; - - SCTP_CHECK_AND_CAST(del_vrfid, optval, uint32_t, optsize); - if (*del_vrfid > SCTP_MAX_VRF_ID) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if (inp->num_vrfs == 1) { - /* Can't delete last one */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { - /* Can't add more once you are bound */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - SCTP_INP_WLOCK(inp); - for (i = 0; i < inp->num_vrfs; i++) { - if (*del_vrfid == inp->m_vrf_ids[i]) { - fnd = 1; - break; - } - } - if (!fnd) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if (i != (inp->num_vrfs - 1)) { - /* Take bottom one and move to this slot */ - inp->m_vrf_ids[i] = inp->m_vrf_ids[(inp->num_vrfs-1)]; - } - if (*del_vrfid == inp->def_vrf_id) { - /* Take the first one as the new default */ - inp->def_vrf_id = inp->m_vrf_ids[0]; - } - /* Drop the number by one killing last one */ - inp->num_vrfs--; -#else - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; -#endif - break; - } - case SCTP_ADD_VRF_ID: - { -#ifdef SCTP_MVRF - uint32_t *add_vrfid; - int i; - - SCTP_CHECK_AND_CAST(add_vrfid, optval, uint32_t, optsize); - if (*add_vrfid > SCTP_MAX_VRF_ID) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { - /* Can't add more once you are bound */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - SCTP_INP_WLOCK(inp); - /* Verify its not already here */ - for (i = 0; i < inp->num_vrfs; i++) { - if (*add_vrfid == inp->m_vrf_ids[i]) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - SCTP_INP_WUNLOCK(inp); - break; - } - } - if ((inp->num_vrfs + 1) > inp->vrf_size) { - /* need to grow array */ - uint32_t *tarray; - SCTP_MALLOC(tarray, uint32_t *, - (sizeof(uint32_t) * (inp->vrf_size + SCTP_DEFAULT_VRF_SIZE)), - SCTP_M_MVRF); - if (tarray == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - SCTP_INP_WUNLOCK(inp); - break; - } - memcpy(tarray, inp->m_vrf_ids, (sizeof(uint32_t) * inp->vrf_size)); - SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF); - inp->m_vrf_ids = tarray; - inp->vrf_size += SCTP_DEFAULT_VRF_SIZE; - } - inp->m_vrf_ids[inp->num_vrfs] = *add_vrfid; - inp->num_vrfs++; - SCTP_INP_WUNLOCK(inp); -#else - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; -#endif - break; - } - case SCTP_DELAYED_SACK: - { - struct sctp_sack_info *sack; - - SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); - SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); - if (sack->sack_delay) { - if (sack->sack_delay > SCTP_MAX_SACK_DELAY) { - error = EINVAL; - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - break; - } - } - if (stcb) { - if (sack->sack_delay) { - stcb->asoc.delayed_ack = sack->sack_delay; - } - if (sack->sack_freq) { - stcb->asoc.sack_freq = sack->sack_freq; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || - (sack->sack_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - if (sack->sack_delay) { - inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = sctp_msecs_to_ticks(sack->sack_delay); - } - if (sack->sack_freq) { - inp->sctp_ep.sctp_sack_freq = sack->sack_freq; - } - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || - (sack->sack_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (sack->sack_delay) { - stcb->asoc.delayed_ack = sack->sack_delay; - } - if (sack->sack_freq) { - stcb->asoc.sack_freq = sack->sack_freq; - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_AUTH_CHUNK: - { - struct sctp_authchunk *sauth; - - SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); - - SCTP_INP_WLOCK(inp); - if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } else { - inp->auth_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - break; - } - case SCTP_AUTH_KEY: - { - struct sctp_authkey *sca; - struct sctp_keyhead *shared_keys; - sctp_sharedkey_t *shared_key; - sctp_key_t *key = NULL; - size_t size; - - SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); - if (sca->sca_keylength == 0) { - size = optsize - sizeof(struct sctp_authkey); - } else { - if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { - size = sca->sca_keylength; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - } - SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); - - if (stcb) { - shared_keys = &stcb->asoc.shared_keys; - /* clear the cached keys for this key id */ - sctp_clear_cachedkeys(stcb, sca->sca_keynumber); - /* - * create the new shared key and - * insert/replace it - */ - if (size > 0) { - key = sctp_set_key(sca->sca_key, (uint32_t) size); - if (key == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - SCTP_TCB_UNLOCK(stcb); - break; - } - } - shared_key = sctp_alloc_sharedkey(); - if (shared_key == NULL) { - sctp_free_key(key); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - SCTP_TCB_UNLOCK(stcb); - break; - } - shared_key->key = key; - shared_key->keyid = sca->sca_keynumber; - error = sctp_insert_sharedkey(shared_keys, shared_key); - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || - (sca->sca_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - shared_keys = &inp->sctp_ep.shared_keys; - /* - * clear the cached keys on all assocs for - * this key id - */ - sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); - /* - * create the new shared key and - * insert/replace it - */ - if (size > 0) { - key = sctp_set_key(sca->sca_key, (uint32_t) size); - if (key == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - SCTP_INP_WUNLOCK(inp); - break; - } - } - shared_key = sctp_alloc_sharedkey(); - if (shared_key == NULL) { - sctp_free_key(key); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - SCTP_INP_WUNLOCK(inp); - break; - } - shared_key->key = key; - shared_key->keyid = sca->sca_keynumber; - error = sctp_insert_sharedkey(shared_keys, shared_key); - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || - (sca->sca_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - shared_keys = &stcb->asoc.shared_keys; - /* clear the cached keys for this key id */ - sctp_clear_cachedkeys(stcb, sca->sca_keynumber); - /* - * create the new shared key and - * insert/replace it - */ - if (size > 0) { - key = sctp_set_key(sca->sca_key, (uint32_t) size); - if (key == NULL) { - SCTP_TCB_UNLOCK(stcb); - continue; - } - } - shared_key = sctp_alloc_sharedkey(); - if (shared_key == NULL) { - sctp_free_key(key); - SCTP_TCB_UNLOCK(stcb); - continue; - } - shared_key->key = key; - shared_key->keyid = sca->sca_keynumber; - error = sctp_insert_sharedkey(shared_keys, shared_key); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_HMAC_IDENT: - { - struct sctp_hmacalgo *shmac; - sctp_hmaclist_t *hmaclist; - uint16_t hmacid; - uint32_t i; - - SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); - if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) || - (shmac->shmac_number_of_idents > 0xffff)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - - hmaclist = sctp_alloc_hmaclist((uint16_t)shmac->shmac_number_of_idents); - if (hmaclist == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - break; - } - for (i = 0; i < shmac->shmac_number_of_idents; i++) { - hmacid = shmac->shmac_idents[i]; - if (sctp_auth_add_hmacid(hmaclist, hmacid)) { - /* invalid HMACs were found */; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - sctp_free_hmaclist(hmaclist); - goto sctp_set_hmac_done; - } - } - for (i = 0; i < hmaclist->num_algo; i++) { - if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { - /* already in list */ - break; - } - } - if (i == hmaclist->num_algo) { - /* not found in list */ - sctp_free_hmaclist(hmaclist); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - /* set it on the endpoint */ - SCTP_INP_WLOCK(inp); - if (inp->sctp_ep.local_hmacs) - sctp_free_hmaclist(inp->sctp_ep.local_hmacs); - inp->sctp_ep.local_hmacs = hmaclist; - SCTP_INP_WUNLOCK(inp); - sctp_set_hmac_done: - break; - } - case SCTP_AUTH_ACTIVE_KEY: - { - struct sctp_authkeyid *scact; - - SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); - SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); - - /* set the active key on the right place */ - if (stcb) { - /* set the active key on the assoc */ - if (sctp_auth_setactivekey(stcb, - scact->scact_keynumber)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, - SCTP_FROM_SCTP_USRREQ, - EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || - (scact->scact_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || - (scact->scact_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - sctp_auth_setactivekey(stcb, scact->scact_keynumber); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_AUTH_DELETE_KEY: - { - struct sctp_authkeyid *scdel; - - SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); - SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); - - /* delete the key from the right place */ - if (stcb) { - if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || - (scdel->scact_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || - (scdel->scact_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - sctp_delete_sharedkey(stcb, scdel->scact_keynumber); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_AUTH_DEACTIVATE_KEY: - { - struct sctp_authkeyid *keyid; - - SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); - SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); - - /* deactivate the key from the right place */ - if (stcb) { - if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || - (keyid->scact_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || - (keyid->scact_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - sctp_deact_sharedkey(stcb, keyid->scact_keynumber); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_ENABLE_STREAM_RESET: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_FUTURE_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->local_strreset_support = (uint8_t)av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_CURRENT_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_RESET_STREAMS: - { - struct sctp_reset_streams *strrst; - int i, send_out = 0; - int send_in = 0; - - SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize); - SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id); - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - break; - } - if (stcb->asoc.reconfig_supported == 0) { - /* - * Peer does not support the chunk type. - */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (sizeof(struct sctp_reset_streams) + - strrst->srs_number_streams * sizeof(uint16_t) > optsize) { - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) { - send_in = 1; - if (stcb->asoc.stream_reset_outstanding) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - SCTP_TCB_UNLOCK(stcb); - break; - } - } - if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) { - send_out = 1; - } - if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); - error = ENOMEM; - SCTP_TCB_UNLOCK(stcb); - break; - } - if ((send_in == 0) && (send_out == 0)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - break; - } - for (i = 0; i < strrst->srs_number_streams; i++) { - if ((send_in) && - (strrst->srs_stream_list[i] >= stcb->asoc.streamincnt)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if ((send_out) && - (strrst->srs_stream_list[i] >= stcb->asoc.streamoutcnt)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - } - if (error) { - SCTP_TCB_UNLOCK(stcb); - break; - } - if (send_out) { - int cnt; - uint16_t strm; - if (strrst->srs_number_streams) { - for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) { - strm = strrst->srs_stream_list[i]; - if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) { - stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING; - cnt++; - } - } - } else { - /* Its all */ - for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) { - if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) { - stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING; - cnt++; - } - } - } - } - if (send_in) { - error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams, - strrst->srs_stream_list, - send_in, 0, 0, 0, 0, 0); - } else { - error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED); - } - if (error == 0) { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); - } else { - /* - * For outgoing streams don't report any problems in - * sending the request to the application. - * XXX: Double check resetting incoming streams. - */ - error = 0; - } - SCTP_TCB_UNLOCK(stcb); - break; - } - case SCTP_ADD_STREAMS: - { - struct sctp_add_streams *stradd; - uint8_t addstream = 0; - uint16_t add_o_strmcnt = 0; - uint16_t add_i_strmcnt = 0; - - SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize); - SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id); - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - break; - } - if (stcb->asoc.reconfig_supported == 0) { - /* - * Peer does not support the chunk type. - */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (stcb->asoc.stream_reset_outstanding) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - SCTP_TCB_UNLOCK(stcb); - break; - } - if ((stradd->sas_outstrms == 0) && - (stradd->sas_instrms == 0)) { - error = EINVAL; - goto skip_stuff; - } - if (stradd->sas_outstrms) { - addstream = 1; - /* We allocate here */ - add_o_strmcnt = stradd->sas_outstrms; - if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) { - /* You can't have more than 64k */ - error = EINVAL; - goto skip_stuff; - } - } - if (stradd->sas_instrms) { - int cnt; - - addstream |= 2; - /* We allocate inside sctp_send_str_reset_req() */ - add_i_strmcnt = stradd->sas_instrms; - cnt = add_i_strmcnt; - cnt += stcb->asoc.streamincnt; - if (cnt > 0x0000ffff) { - /* You can't have more than 64k */ - error = EINVAL; - goto skip_stuff; - } - if (cnt > (int)stcb->asoc.max_inbound_streams) { - /* More than you are allowed */ - error = EINVAL; - goto skip_stuff; - } - } - error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); - skip_stuff: - SCTP_TCB_UNLOCK(stcb); - break; - } - case SCTP_RESET_ASSOC: - { - int i; - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); - SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value); - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - break; - } - if (stcb->asoc.reconfig_supported == 0) { - /* - * Peer does not support the chunk type. - */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - error = EOPNOTSUPP; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - break; - } - if (stcb->asoc.stream_reset_outstanding) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - SCTP_TCB_UNLOCK(stcb); - break; - } - /* Is there any data pending in the send or sent queues? */ - if (!TAILQ_EMPTY(&stcb->asoc.send_queue) || - !TAILQ_EMPTY(&stcb->asoc.sent_queue)) { - busy_out: - error = EBUSY; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - SCTP_TCB_UNLOCK(stcb); - break; - } - /* Do any streams have data queued? */ - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - goto busy_out; - } - } - error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); - SCTP_TCB_UNLOCK(stcb); - break; - } - case SCTP_CONNECT_X: - if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); - break; - case SCTP_CONNECT_X_DELAYED: - if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); - break; - case SCTP_CONNECT_X_COMPLETE: - { - struct sockaddr *sa; - - /* FIXME MT: check correct? */ - SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); - - /* find tcb */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb) { - SCTP_TCB_LOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - - if (stcb == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - error = ENOENT; - break; - } - if (stcb->asoc.delayed_connection == 1) { - stcb->asoc.delayed_connection = 0; - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, - stcb->asoc.primary_destination, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - } else { - /* - * already expired or did not use delayed - * connectx - */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - } - SCTP_TCB_UNLOCK(stcb); - break; - } - case SCTP_MAX_BURST: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - stcb->asoc.max_burst = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_FUTURE_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->sctp_ep.max_burst = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((av->assoc_id == SCTP_CURRENT_ASSOC) || - (av->assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.max_burst = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_MAXSEG: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - stcb->asoc.sctp_frag_point = av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - inp->sctp_frag_point = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_EVENTS: - { - struct sctp_event_subscribe *events; - - SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); - - SCTP_INP_WLOCK(inp); - if (events->sctp_data_io_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); - } - - if (events->sctp_association_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); - } - - if (events->sctp_address_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); - } - - if (events->sctp_send_failure_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); - } - - if (events->sctp_peer_error_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); - } - - if (events->sctp_shutdown_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); - } - - if (events->sctp_partial_delivery_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); - } - - if (events->sctp_adaptation_layer_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); - } - - if (events->sctp_authentication_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); - } - - if (events->sctp_sender_dry_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); - } - - if (events->sctp_stream_reset_event) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); - } - - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (events->sctp_association_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); - } - if (events->sctp_address_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); - } - if (events->sctp_send_failure_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); - } - if (events->sctp_peer_error_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); - } - if (events->sctp_shutdown_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); - } - if (events->sctp_partial_delivery_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); - } - if (events->sctp_adaptation_layer_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); - } - if (events->sctp_authentication_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); - } - if (events->sctp_sender_dry_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); - } - if (events->sctp_stream_reset_event) { - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); - } else { - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); - } - SCTP_TCB_UNLOCK(stcb); - } - /* Send up the sender dry event only for 1-to-1 style sockets. */ - if (events->sctp_sender_dry_event) { - if (((inp->sctp_flags & (SCTP_PCB_FLAGS_TCPTYPE | SCTP_PCB_FLAGS_IN_TCPPOOL)) != 0) && - !SCTP_IS_LISTENING(inp)) { - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb != NULL) { - SCTP_TCB_LOCK(stcb); - if (TAILQ_EMPTY(&stcb->asoc.send_queue) && - TAILQ_EMPTY(&stcb->asoc.sent_queue) && - (stcb->asoc.stream_queue_cnt == 0)) { - sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); - } - SCTP_TCB_UNLOCK(stcb); - } - } - } - SCTP_INP_WUNLOCK(inp); - break; - } - case SCTP_ADAPTATION_LAYER: - { - struct sctp_setadaptation *adap_bits; - - SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); - SCTP_INP_WLOCK(inp); - inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; - inp->sctp_ep.adaptation_layer_indicator_provided = 1; - SCTP_INP_WUNLOCK(inp); - break; - } -#ifdef SCTP_DEBUG - case SCTP_SET_INITIAL_DBG_SEQ: - { - uint32_t *vvv; - - SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); - SCTP_INP_WLOCK(inp); - inp->sctp_ep.initial_sequence_debug = *vvv; - SCTP_INP_WUNLOCK(inp); - break; - } -#endif - case SCTP_DEFAULT_SEND_PARAM: - { - struct sctp_sndrcvinfo *s_info; - - SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); - SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); - - if (stcb) { - if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { - memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || - (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || - (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { - memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_PEER_ADDR_PARAMS: - { - struct sctp_paddrparams *paddrp; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); - SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); - -#if defined(INET) && defined(INET6) - if (paddrp->spp_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&paddrp->spp_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&paddrp->spp_address; - } - } else { - addr = (struct sockaddr *)&paddrp->spp_address; - } -#else - addr = (struct sockaddr *)&paddrp->spp_address; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, - &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - if ((stcb != NULL) && (net == NULL)) { -#ifdef INET - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr != INADDR_ANY) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)addr; - if (sconn->sconn_addr != NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif - { - error = EAFNOSUPPORT; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - /* sanity checks */ - if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { - if (stcb) - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - - if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { - if (stcb) - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && - (paddrp->spp_pathmtu > 0) && - ((paddrp->spp_pathmtu < SCTP_SMALLEST_PMTU) || - (paddrp->spp_pathmtu > SCTP_LARGEST_PMTU))) { - if (stcb) - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - - if (stcb != NULL) { - /************************TCB SPECIFIC SET ******************/ - if (net != NULL) { - /************************NET SPECIFIC SET ******************/ - if (paddrp->spp_flags & SPP_HB_DISABLE) { - if (((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) && - ((net->dest_state & SCTP_ADDR_NOHB) == 0)) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); - } - net->dest_state |= SCTP_ADDR_NOHB; - } - if (paddrp->spp_flags & SPP_HB_ENABLE) { - if (paddrp->spp_hbinterval) { - net->heart_beat_delay = paddrp->spp_hbinterval; - } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { - net->heart_beat_delay = 0; - } - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); - net->dest_state &= ~SCTP_ADDR_NOHB; - } - if (paddrp->spp_flags & SPP_HB_DEMAND) { - if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { - sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); - } - } - if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { - if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); - } - net->dest_state |= SCTP_ADDR_NO_PMTUD; - if (paddrp->spp_pathmtu > 0) { - net->mtu = paddrp->spp_pathmtu; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - net->mtu += SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - net->mtu += SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - net->mtu += sizeof(struct sctphdr); - break; -#endif - default: - break; - } - if (net->mtu < stcb->asoc.smallest_mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu, true); - } - } - } - if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { - if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); - } - net->dest_state &= ~SCTP_ADDR_NO_PMTUD; - } - if (paddrp->spp_pathmaxrxt > 0) { - if (net->dest_state & SCTP_ADDR_PF) { - if (net->error_count > paddrp->spp_pathmaxrxt) { - net->dest_state &= ~SCTP_ADDR_PF; - } - } else { - if ((net->error_count <= paddrp->spp_pathmaxrxt) && - (net->error_count > net->pf_threshold)) { - net->dest_state |= SCTP_ADDR_PF; - sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - } - } - if (net->dest_state & SCTP_ADDR_REACHABLE) { - if (net->error_count > paddrp->spp_pathmaxrxt) { - net->dest_state &= ~SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); - } - } else { - if (net->error_count <= paddrp->spp_pathmaxrxt) { - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); - } - } - net->failure_threshold = paddrp->spp_pathmaxrxt; - } - if (paddrp->spp_flags & SPP_DSCP) { - net->dscp = paddrp->spp_dscp & 0xfc; - net->dscp |= 0x01; - } -#ifdef INET6 - if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { - if (net->ro._l_addr.sa.sa_family == AF_INET6) { - net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; - net->flowlabel |= 0x80000000; - } - } -#endif - } else { - /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ - if (paddrp->spp_pathmaxrxt > 0) { - stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->dest_state & SCTP_ADDR_PF) { - if (net->error_count > paddrp->spp_pathmaxrxt) { - net->dest_state &= ~SCTP_ADDR_PF; - } - } else { - if ((net->error_count <= paddrp->spp_pathmaxrxt) && - (net->error_count > net->pf_threshold)) { - net->dest_state |= SCTP_ADDR_PF; - sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - } - } - if (net->dest_state & SCTP_ADDR_REACHABLE) { - if (net->error_count > paddrp->spp_pathmaxrxt) { - net->dest_state &= ~SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); - } - } else { - if (net->error_count <= paddrp->spp_pathmaxrxt) { - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); - } - } - net->failure_threshold = paddrp->spp_pathmaxrxt; - } - } - if (paddrp->spp_flags & SPP_HB_ENABLE) { - if (paddrp->spp_hbinterval != 0) { - stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; - } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { - stcb->asoc.heart_beat_delay = 0; - } - /* Turn back on the timer */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (paddrp->spp_hbinterval != 0) { - net->heart_beat_delay = paddrp->spp_hbinterval; - } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { - net->heart_beat_delay = 0; - } - if (net->dest_state & SCTP_ADDR_NOHB) { - net->dest_state &= ~SCTP_ADDR_NOHB; - } - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); - } - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); - } - if (paddrp->spp_flags & SPP_HB_DISABLE) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if ((net->dest_state & SCTP_ADDR_NOHB) == 0) { - net->dest_state |= SCTP_ADDR_NOHB; - if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15); - } - } - } - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); - } - if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16); - } - net->dest_state |= SCTP_ADDR_NO_PMTUD; - if (paddrp->spp_pathmtu > 0) { - net->mtu = paddrp->spp_pathmtu; - switch (net->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - net->mtu += SCTP_MIN_V4_OVERHEAD; - break; -#endif -#ifdef INET6 - case AF_INET6: - net->mtu += SCTP_MIN_OVERHEAD; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - net->mtu += sizeof(struct sctphdr); - break; -#endif - default: - break; - } - if (net->mtu < stcb->asoc.smallest_mtu) { - sctp_pathmtu_adjustment(stcb, net->mtu, true); - } - } - } - if (paddrp->spp_pathmtu > 0) { - stcb->asoc.default_mtu = paddrp->spp_pathmtu; - } - sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); - } - if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); - } - net->dest_state &= ~SCTP_ADDR_NO_PMTUD; - } - stcb->asoc.default_mtu = 0; - sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); - } - if (paddrp->spp_flags & SPP_DSCP) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - net->dscp = paddrp->spp_dscp & 0xfc; - net->dscp |= 0x01; - } - stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; - stcb->asoc.default_dscp |= 0x01; - } -#ifdef INET6 - if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->ro._l_addr.sa.sa_family == AF_INET6) { - net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; - net->flowlabel |= 0x80000000; - } - } - stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; - stcb->asoc.default_flowlabel |= 0x80000000; - } -#endif - } - SCTP_TCB_UNLOCK(stcb); - } else { - /************************NO TCB, SET TO default stuff ******************/ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - /* - * For the TOS/FLOWLABEL stuff you set it - * with the options on the socket - */ - if (paddrp->spp_pathmaxrxt > 0) { - inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; - } - - if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) - inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; - else if (paddrp->spp_hbinterval != 0) { - if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) - paddrp->spp_hbinterval= SCTP_MAX_HB_INTERVAL; - inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(paddrp->spp_hbinterval); - } - - if (paddrp->spp_flags & SPP_HB_ENABLE) { - if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { - inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; - } else if (paddrp->spp_hbinterval) { - inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(paddrp->spp_hbinterval); - } - sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); - } else if (paddrp->spp_flags & SPP_HB_DISABLE) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); - } - if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { - inp->sctp_ep.default_mtu = 0; - sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); - } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { - if (paddrp->spp_pathmtu > 0) { - inp->sctp_ep.default_mtu = paddrp->spp_pathmtu; - } - sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); - } - if (paddrp->spp_flags & SPP_DSCP) { - inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; - inp->sctp_ep.default_dscp |= 0x01; - } -#ifdef INET6 - if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; - inp->sctp_ep.default_flowlabel |= 0x80000000; - } - } -#endif - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_RTOINFO: - { - struct sctp_rtoinfo *srto; - uint32_t new_init, new_min, new_max; - - SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); - SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); - - if (stcb) { - if (srto->srto_initial) - new_init = srto->srto_initial; - else - new_init = stcb->asoc.initial_rto; - if (srto->srto_max) - new_max = srto->srto_max; - else - new_max = stcb->asoc.maxrto; - if (srto->srto_min) - new_min = srto->srto_min; - else - new_min = stcb->asoc.minrto; - if ((new_min <= new_init) && (new_init <= new_max)) { - stcb->asoc.initial_rto = new_init; - stcb->asoc.maxrto = new_max; - stcb->asoc.minrto = new_min; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (srto->srto_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (srto->srto_initial) - new_init = srto->srto_initial; - else - new_init = inp->sctp_ep.initial_rto; - if (srto->srto_max) - new_max = srto->srto_max; - else - new_max = inp->sctp_ep.sctp_maxrto; - if (srto->srto_min) - new_min = srto->srto_min; - else - new_min = inp->sctp_ep.sctp_minrto; - if ((new_min <= new_init) && (new_init <= new_max)) { - inp->sctp_ep.initial_rto = new_init; - inp->sctp_ep.sctp_maxrto = new_max; - inp->sctp_ep.sctp_minrto = new_min; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_ASSOCINFO: - { - struct sctp_assocparams *sasoc; - - SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); - SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); - if (sasoc->sasoc_cookie_life > 0) { - /* boundary check the cookie life */ - if (sasoc->sasoc_cookie_life < SCTP_MIN_COOKIE_LIFE) { - sasoc->sasoc_cookie_life = SCTP_MIN_COOKIE_LIFE; - } - if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { - sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; - } - } - if (stcb) { - if (sasoc->sasoc_asocmaxrxt > 0) { - stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; - } - if (sasoc->sasoc_cookie_life > 0) { - stcb->asoc.cookie_life = sctp_msecs_to_ticks(sasoc->sasoc_cookie_life); - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (sasoc->sasoc_asocmaxrxt > 0) { - inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; - } - if (sasoc->sasoc_cookie_life > 0) { - inp->sctp_ep.def_cookie_life = sctp_msecs_to_ticks(sasoc->sasoc_cookie_life); - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_INITMSG: - { - struct sctp_initmsg *sinit; - - SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); - SCTP_INP_WLOCK(inp); - if (sinit->sinit_num_ostreams) - inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; - - if (sinit->sinit_max_instreams) - inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; - - if (sinit->sinit_max_attempts) - inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; - - if (sinit->sinit_max_init_timeo) - inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; - SCTP_INP_WUNLOCK(inp); - break; - } - case SCTP_PRIMARY_ADDR: - { - struct sctp_setprim *spa; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); - SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); - -#if defined(INET) && defined(INET6) - if (spa->ssp_addr.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&spa->ssp_addr; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&spa->ssp_addr; - } - } else { - addr = (struct sockaddr *)&spa->ssp_addr; - } -#else - addr = (struct sockaddr *)&spa->ssp_addr; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, - &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - - if ((stcb != NULL) && (net != NULL)) { - if (net != stcb->asoc.primary_destination) { - if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { - /* Ok we need to set it */ - if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { - if ((stcb->asoc.alternate) && - ((net->dest_state & SCTP_ADDR_PF) == 0) && - (net->dest_state & SCTP_ADDR_REACHABLE)) { - sctp_free_remote_addr(stcb->asoc.alternate); - stcb->asoc.alternate = NULL; - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - break; - } - case SCTP_SET_DYNAMIC_PRIMARY: - { - union sctp_sockstore *ss; -#ifdef SCTP_MVRF - int i, fnd = 0; -#endif -#if !defined(_WIN32) && !defined(__Userspace__) -#if defined(__APPLE__) - struct proc *proc; -#endif -#if defined(__FreeBSD__) - error = priv_check(curthread, - PRIV_NETINET_RESERVEDPORT); -#elif defined(__APPLE__) - proc = (struct proc *)p; - if (p) { - error = suser(proc->p_ucred, &proc->p_acflag); - } else { - break; - } -#else - error = suser(p, 0); -#endif - if (error) - break; -#endif - - SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); - /* SUPER USER CHECK? */ -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (vrf_id == inp->m_vrf_ids[i]) { - fnd = 1; - break; - } - } - if (!fnd) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } -#endif - error = sctp_dynamic_set_primary(&ss->sa, vrf_id); - break; - } - case SCTP_SET_PEER_PRIMARY_ADDR: - { - struct sctp_setpeerprim *sspp; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); - SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); - if (stcb != NULL) { - struct sctp_ifa *ifa; - -#if defined(INET) && defined(INET6) - if (sspp->sspp_addr.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&sspp->sspp_addr; - } - } else { - addr = (struct sockaddr *)&sspp->sspp_addr; - } -#else - addr = (struct sockaddr *)&sspp->sspp_addr; -#endif - ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); - if (ifa == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_of_it; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { - /* Must validate the ifa found is in our ep */ - struct sctp_laddr *laddr; - int found = 0; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) { - SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", - __func__); - continue; - } - if ((sctp_is_addr_restricted(stcb, laddr->ifa)) && - (!sctp_is_addr_pending(stcb, laddr->ifa))) { - continue; - } - if (laddr->ifa == ifa) { - found = 1; - break; - } - } - if (!found) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_of_it; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - } else { - switch (addr->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (prison_check_ip4(inp->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_of_it; - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (prison_check_ip6(inp->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_of_it; - } - break; - } -#endif - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_of_it; - } -#endif - } - if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); - out_of_it: - SCTP_TCB_UNLOCK(stcb); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; - } - case SCTP_BINDX_ADD_ADDR: - { - struct sockaddr *sa; -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *td; - - td = (struct thread *)p; -#endif - SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); -#ifdef INET - if (sa->sa_family == AF_INET) { - if (optsize < sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (td != NULL && - (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)sa)->sin_addr)))) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } -#endif - } else -#endif -#ifdef INET6 - if (sa->sa_family == AF_INET6) { - if (optsize < sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (td != NULL && - (error = prison_local_ip6(td->td_ucred, - &(((struct sockaddr_in6 *)sa)->sin6_addr), - (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } -#endif - } else -#endif - { - error = EAFNOSUPPORT; - break; - } - sctp_bindx_add_address(so, inp, sa, vrf_id, &error, p); - break; - } - case SCTP_BINDX_REM_ADDR: - { - struct sockaddr *sa; -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct thread *td; - td = (struct thread *)p; - -#endif - SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); -#ifdef INET - if (sa->sa_family == AF_INET) { - if (optsize < sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (td != NULL && - (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)sa)->sin_addr)))) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } -#endif - } else -#endif -#ifdef INET6 - if (sa->sa_family == AF_INET6) { - if (optsize < sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (td != NULL && - (error = prison_local_ip6(td->td_ucred, - &(((struct sockaddr_in6 *)sa)->sin6_addr), - (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } -#endif - } else -#endif - { - error = EAFNOSUPPORT; - break; - } - sctp_bindx_delete_address(inp, sa, vrf_id, &error); - break; - } -#if defined(__APPLE__) && !defined(__Userspace__) - case SCTP_LISTEN_FIX: - /* only applies to one-to-many sockets */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { - /* make sure the ACCEPTCONN flag is OFF */ - so->so_options &= ~SO_ACCEPTCONN; - } else { - /* otherwise, not allowed */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; -#endif - case SCTP_EVENT: - { - struct sctp_event *event; - uint32_t event_type; - - SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); - SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); - switch (event->se_type) { - case SCTP_ASSOC_CHANGE: - event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; - break; - case SCTP_PEER_ADDR_CHANGE: - event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; - break; - case SCTP_REMOTE_ERROR: - event_type = SCTP_PCB_FLAGS_RECVPEERERR; - break; - case SCTP_SEND_FAILED: - event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; - break; - case SCTP_SHUTDOWN_EVENT: - event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; - break; - case SCTP_ADAPTATION_INDICATION: - event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; - break; - case SCTP_PARTIAL_DELIVERY_EVENT: - event_type = SCTP_PCB_FLAGS_PDAPIEVNT; - break; - case SCTP_AUTHENTICATION_EVENT: - event_type = SCTP_PCB_FLAGS_AUTHEVNT; - break; - case SCTP_STREAM_RESET_EVENT: - event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; - break; - case SCTP_SENDER_DRY_EVENT: - event_type = SCTP_PCB_FLAGS_DRYEVNT; - break; - case SCTP_NOTIFICATIONS_STOPPED_EVENT: - event_type = 0; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); - error = ENOTSUP; - break; - case SCTP_ASSOC_RESET_EVENT: - event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; - break; - case SCTP_STREAM_CHANGE_EVENT: - event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; - break; - case SCTP_SEND_FAILED_EVENT: - event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; - break; - default: - event_type = 0; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if (event_type > 0) { - if (stcb) { - if (event->se_on) { - sctp_stcb_feature_on(inp, stcb, event_type); - if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { - if (TAILQ_EMPTY(&stcb->asoc.send_queue) && - TAILQ_EMPTY(&stcb->asoc.sent_queue) && - (stcb->asoc.stream_queue_cnt == 0)) { - sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); - } - } - } else { - sctp_stcb_feature_off(inp, stcb, event_type); - } - SCTP_TCB_UNLOCK(stcb); - } else { - /* - * We don't want to send up a storm of events, - * so return an error for sender dry events - */ - if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && - (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((event->se_assoc_id == SCTP_ALL_ASSOC) || - (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); - error = ENOTSUP; - break; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((event->se_assoc_id == SCTP_FUTURE_ASSOC) || - (event->se_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - if (event->se_on) { - sctp_feature_on(inp, event_type); - } else { - sctp_feature_off(inp, event_type); - } - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || - (event->se_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (event->se_on) { - sctp_stcb_feature_on(inp, stcb, event_type); - } else { - sctp_stcb_feature_off(inp, stcb, event_type); - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - } else { - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } - break; - } - case SCTP_RECVRCVINFO: - { - int *onoff; - - SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); - SCTP_INP_WLOCK(inp); - if (*onoff != 0) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); - } - SCTP_INP_WUNLOCK(inp); - break; - } - case SCTP_RECVNXTINFO: - { - int *onoff; - - SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); - SCTP_INP_WLOCK(inp); - if (*onoff != 0) { - sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); - } else { - sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); - } - SCTP_INP_WUNLOCK(inp); - break; - } - case SCTP_DEFAULT_SNDINFO: - { - struct sctp_sndinfo *info; - uint16_t policy; - - SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); - SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); - - if (stcb) { - if (info->snd_sid < stcb->asoc.streamoutcnt) { - stcb->asoc.def_send.sinfo_stream = info->snd_sid; - policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); - stcb->asoc.def_send.sinfo_flags = info->snd_flags; - stcb->asoc.def_send.sinfo_flags |= policy; - stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; - stcb->asoc.def_send.sinfo_context = info->snd_context; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((info->snd_assoc_id == SCTP_FUTURE_ASSOC) || - (info->snd_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->def_send.sinfo_stream = info->snd_sid; - policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); - inp->def_send.sinfo_flags = info->snd_flags; - inp->def_send.sinfo_flags |= policy; - inp->def_send.sinfo_ppid = info->snd_ppid; - inp->def_send.sinfo_context = info->snd_context; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || - (info->snd_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - if (info->snd_sid < stcb->asoc.streamoutcnt) { - stcb->asoc.def_send.sinfo_stream = info->snd_sid; - policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); - stcb->asoc.def_send.sinfo_flags = info->snd_flags; - stcb->asoc.def_send.sinfo_flags |= policy; - stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; - stcb->asoc.def_send.sinfo_context = info->snd_context; - } - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_DEFAULT_PRINFO: - { - struct sctp_default_prinfo *info; - - SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); - SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); - - if (info->pr_policy > SCTP_PR_SCTP_MAX) { - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - if (stcb) { - stcb->asoc.def_send.sinfo_flags &= 0xfff0; - stcb->asoc.def_send.sinfo_flags |= info->pr_policy; - stcb->asoc.def_send.sinfo_timetolive = info->pr_value; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((info->pr_assoc_id == SCTP_FUTURE_ASSOC) || - (info->pr_assoc_id == SCTP_ALL_ASSOC)))) { - SCTP_INP_WLOCK(inp); - inp->def_send.sinfo_flags &= 0xfff0; - inp->def_send.sinfo_flags |= info->pr_policy; - inp->def_send.sinfo_timetolive = info->pr_value; - SCTP_INP_WUNLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || - (info->pr_assoc_id == SCTP_ALL_ASSOC))) { - SCTP_INP_RLOCK(inp); - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - SCTP_TCB_LOCK(stcb); - stcb->asoc.def_send.sinfo_flags &= 0xfff0; - stcb->asoc.def_send.sinfo_flags |= info->pr_policy; - stcb->asoc.def_send.sinfo_timetolive = info->pr_value; - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } - } - break; - } - case SCTP_PEER_ADDR_THLDS: - /* Applies to the specific association */ - { - struct sctp_paddrthlds *thlds; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); - SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); - -#if defined(INET) && defined(INET6) - if (thlds->spt_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&thlds->spt_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&thlds->spt_address; - } - } else { - addr = (struct sockaddr *)&thlds->spt_address; - } -#else - addr = (struct sockaddr *)&thlds->spt_address; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, - &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - if ((stcb != NULL) && (net == NULL)) { -#ifdef INET - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr != INADDR_ANY) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)addr; - if (sconn->sconn_addr != NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif - { - error = EAFNOSUPPORT; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - if (thlds->spt_pathcpthld != 0xffff) { - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - if (stcb != NULL) { - if (net != NULL) { - net->failure_threshold = thlds->spt_pathmaxrxt; - net->pf_threshold = thlds->spt_pathpfthld; - if (net->dest_state & SCTP_ADDR_PF) { - if ((net->error_count > net->failure_threshold) || - (net->error_count <= net->pf_threshold)) { - net->dest_state &= ~SCTP_ADDR_PF; - } - } else { - if ((net->error_count > net->pf_threshold) && - (net->error_count <= net->failure_threshold)) { - net->dest_state |= SCTP_ADDR_PF; - sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - } - } - if (net->dest_state & SCTP_ADDR_REACHABLE) { - if (net->error_count > net->failure_threshold) { - net->dest_state &= ~SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); - } - } else { - if (net->error_count <= net->failure_threshold) { - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); - } - } - } else { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - net->failure_threshold = thlds->spt_pathmaxrxt; - net->pf_threshold = thlds->spt_pathpfthld; - if (net->dest_state & SCTP_ADDR_PF) { - if ((net->error_count > net->failure_threshold) || - (net->error_count <= net->pf_threshold)) { - net->dest_state &= ~SCTP_ADDR_PF; - } - } else { - if ((net->error_count > net->pf_threshold) && - (net->error_count <= net->failure_threshold)) { - net->dest_state |= SCTP_ADDR_PF; - sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); - } - } - if (net->dest_state & SCTP_ADDR_REACHABLE) { - if (net->error_count > net->failure_threshold) { - net->dest_state &= ~SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); - } - } else { - if (net->error_count <= net->failure_threshold) { - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); - } - } - } - stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; - stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; - inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_REMOTE_UDP_ENCAPS_PORT: - { - struct sctp_udpencaps *encaps; - struct sctp_nets *net; - struct sockaddr *addr; -#if defined(INET) && defined(INET6) - struct sockaddr_in sin_store; -#endif - - SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); - SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); - -#if defined(INET) && defined(INET6) - if (encaps->sue_address.ss_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)&encaps->sue_address; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - in6_sin6_2_sin(&sin_store, sin6); - addr = (struct sockaddr *)&sin_store; - } else { - addr = (struct sockaddr *)&encaps->sue_address; - } - } else { - addr = (struct sockaddr *)&encaps->sue_address; - } -#else - addr = (struct sockaddr *)&encaps->sue_address; -#endif - if (stcb != NULL) { - net = sctp_findnet(stcb, addr); - } else { - /* We increment here since sctp_findassociation_ep_addr() wil - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - net = NULL; - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } - } - if ((stcb != NULL) && (net == NULL)) { -#ifdef INET - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr != INADDR_ANY) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)addr; - if (sconn->sconn_addr != NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - SCTP_TCB_UNLOCK(stcb); - error = EINVAL; - break; - } - } else -#endif - { - error = EAFNOSUPPORT; - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - break; - } - } - - if (stcb != NULL) { - if (net != NULL) { - net->port = encaps->sue_port; - } else { - stcb->asoc.port = encaps->sue_port; - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - inp->sctp_ep.port = encaps->sue_port; - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_ECN_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->ecn_supported = 0; - } else { - inp->ecn_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_PR_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->prsctp_supported = 0; - } else { - inp->prsctp_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_AUTH_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - if ((av->assoc_value == 0) && - (inp->asconf_supported == 1)) { - /* AUTH is required for ASCONF */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } else { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->auth_supported = 0; - } else { - inp->auth_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_ASCONF_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - if ((av->assoc_value != 0) && - (inp->auth_supported == 0)) { - /* AUTH is required for ASCONF */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } else { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->asconf_supported = 0; - sctp_auth_delete_chunk(SCTP_ASCONF, - inp->sctp_ep.local_auth_chunks); - sctp_auth_delete_chunk(SCTP_ASCONF_ACK, - inp->sctp_ep.local_auth_chunks); - } else { - inp->asconf_supported = 1; - sctp_auth_add_chunk(SCTP_ASCONF, - inp->sctp_ep.local_auth_chunks); - sctp_auth_add_chunk(SCTP_ASCONF_ACK, - inp->sctp_ep.local_auth_chunks); - } - SCTP_INP_WUNLOCK(inp); - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_RECONFIG_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->reconfig_supported = 0; - } else { - inp->reconfig_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_NRSACK_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->nrsack_supported = 0; - } else { - inp->nrsack_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_PKTDROP_SUPPORTED: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - if (av->assoc_value == 0) { - inp->pktdrop_supported = 0; - } else { - inp->pktdrop_supported = 1; - } - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_MAX_CWND: - { - struct sctp_assoc_value *av; - struct sctp_nets *net; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - - if (stcb) { - stcb->asoc.max_cwnd = av->assoc_value; - if (stcb->asoc.max_cwnd > 0) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if ((net->cwnd > stcb->asoc.max_cwnd) && - (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) { - net->cwnd = stcb->asoc.max_cwnd; - if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { - net->cwnd = net->mtu - sizeof(struct sctphdr); - } - } - } - } - SCTP_TCB_UNLOCK(stcb); - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && - (av->assoc_id == SCTP_FUTURE_ASSOC))) { - SCTP_INP_WLOCK(inp); - inp->max_cwnd = av->assoc_value; - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - } - break; - } - case SCTP_ACCEPT_ZERO_CHECKSUM: - { - uint32_t *value; - - SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); - if ((*value == SCTP_EDMID_NONE) || - (*value == SCTP_EDMID_LOWER_LAYER_DTLS)) { - SCTP_INP_WLOCK(inp); - inp->rcv_edmid = *value; - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - break; - } - - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; - break; - } /* end switch (opt) */ - return (error); -} - -#if !defined(__Userspace__) -int -sctp_ctloutput(struct socket *so, struct sockopt *sopt) -{ -#if defined(__FreeBSD__) - struct epoch_tracker et; - struct sctp_inpcb *inp; -#endif - void *optval = NULL; - void *p; - size_t optsize = 0; - int error = 0; - -#if defined(__FreeBSD__) - if ((sopt->sopt_level == SOL_SOCKET) && - (sopt->sopt_name == SO_SETFIB)) { - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); - return (EINVAL); - } - SCTP_INP_WLOCK(inp); - inp->fibnum = so->so_fibnum; - SCTP_INP_WUNLOCK(inp); - return (0); - } -#endif - if (sopt->sopt_level != IPPROTO_SCTP) { - /* wrong proto level... send back up to IP */ -#ifdef INET6 - if (INP_CHECK_SOCKAF(so, AF_INET6)) - error = ip6_ctloutput(so, sopt); -#endif /* INET6 */ -#if defined(INET) && defined(INET6) - else -#endif -#ifdef INET - error = ip_ctloutput(so, sopt); -#endif - return (error); - } - optsize = sopt->sopt_valsize; - if (optsize > SCTP_SOCKET_OPTION_LIMIT) { - SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); - return (ENOBUFS); - } - if (optsize) { - SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); - if (optval == NULL) { - SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); - return (ENOBUFS); - } - error = sooptcopyin(sopt, optval, optsize, optsize); - if (error) { - SCTP_FREE(optval, SCTP_M_SOCKOPT); - goto out; - } - } -#if defined(__FreeBSD__) || defined(_WIN32) - p = (void *)sopt->sopt_td; -#else - p = (void *)sopt->sopt_p; -#endif - if (sopt->sopt_dir == SOPT_SET) { -#if defined(__FreeBSD__) - NET_EPOCH_ENTER(et); -#endif - error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); -#if defined(__FreeBSD__) - NET_EPOCH_EXIT(et); -#endif - } else if (sopt->sopt_dir == SOPT_GET) { - error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); - } else { - SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - } - if ((error == 0) && (optval != NULL)) { - error = sooptcopyout(sopt, optval, optsize); - SCTP_FREE(optval, SCTP_M_SOCKOPT); - } else if (optval != NULL) { - SCTP_FREE(optval, SCTP_M_SOCKOPT); - } -out: - return (error); -} -#endif - -#ifdef INET -#if defined(__Userspace__) -int -sctp_connect(struct socket *so, struct sockaddr *addr) -{ - void *p = NULL; -#elif defined(__FreeBSD__) -static int -sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) -{ -#elif defined(__APPLE__) -static int -sctp_connect(struct socket *so, struct sockaddr *addr, struct proc *p) -{ -#elif defined(_WIN32) -static int -sctp_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p) -{ -#else -static int -sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p) -{ - struct sockaddr *addr = mtod(nam, struct sockaddr *); - -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif -#ifdef SCTP_MVRF - int i, fnd = 0; -#endif - int error = 0; - int create_lock_on = 0; - uint32_t vrf_id; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb = NULL; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - /* I made the same as TCP since we are not setup? */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - if (addr == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return EINVAL; - } - -#if defined(__Userspace__) - /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */ -#endif -#if !defined(_WIN32) && !defined(__linux__) && !defined(__EMSCRIPTEN__) - switch (addr->sa_family) { -#ifdef INET6 - case AF_INET6: - { -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct sockaddr_in6 *sin6; - -#endif - if (addr->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - sin6 = (struct sockaddr_in6 *)addr; - if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6->sin6_addr)) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - return (error); - } -#endif - break; - } -#endif -#ifdef INET - case AF_INET: - { -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct sockaddr_in *sin; - -#endif -#if !defined(_WIN32) - if (addr->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - sin = (struct sockaddr_in *)addr; - if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sin->sin_addr)) != 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - return (error); - } -#endif - break; - } -#endif - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); - return (EAFNOSUPPORT); - } -#endif - SCTP_INP_INCR_REF(inp); - SCTP_ASOC_CREATE_LOCK(inp); - create_lock_on = 1; -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { - /* Should I really unlock ? */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); - error = EFAULT; - goto out_now; - } -#ifdef INET6 - if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && - (addr->sa_family == AF_INET6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } -#endif -#if defined(__Userspace__) - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) && - (addr->sa_family != AF_CONN)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } -#endif - if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { - /* Bind a ephemeral port */ - error = sctp_inpcb_bind(so, NULL, NULL, p); - if (error) { - goto out_now; - } - } - /* Now do we connect? */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && - (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { - /* We are already connected AND the TCP model */ - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); - error = EADDRINUSE; - goto out_now; - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - SCTP_INP_RUNLOCK(inp); - } else { - /* We increment here since sctp_findassociation_ep_addr() will - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else { - SCTP_TCB_UNLOCK(stcb); - } - } - if (stcb != NULL) { - /* Already have or am bring up an association */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - goto out_now; - } - - vrf_id = inp->def_vrf_id; -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (vrf_id == inp->m_vrf_ids[i]) { - fnd = 1; - break; - } - } - if (!fnd) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } -#endif - /* We are GOOD to go */ - stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, p, - SCTP_INITIALIZE_AUTH_PARAMS); - if (stcb == NULL) { - /* Gak! no memory */ - goto out_now; - } - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - SCTP_TCB_UNLOCK(stcb); - out_now: -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - if (create_lock_on) { - SCTP_ASOC_CREATE_UNLOCK(inp); - } - SCTP_INP_DECR_REF(inp); - return (error); -} -#endif - -#if defined(__Userspace__) -int -sctpconn_connect(struct socket *so, struct sockaddr *addr) -{ -#ifdef SCTP_MVRF - int i, fnd = 0; -#endif - void *p = NULL; - int error = 0; - int create_lock_on = 0; - uint32_t vrf_id; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb = NULL; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - /* I made the same as TCP since we are not setup? */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - if (addr == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return EINVAL; - } - switch (addr->sa_family) { -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif - case AF_CONN: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_conn)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); - return (EAFNOSUPPORT); - } - SCTP_INP_INCR_REF(inp); - SCTP_ASOC_CREATE_LOCK(inp); - create_lock_on = 1; - - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { - /* Should I really unlock ? */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); - error = EFAULT; - goto out_now; - } -#ifdef INET6 - if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && - (addr->sa_family == AF_INET6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } -#endif - if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { - /* Bind a ephemeral port */ - error = sctp_inpcb_bind(so, NULL, NULL, p); - if (error) { - goto out_now; - } - } - /* Now do we connect? */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && - (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { - /* We are already connected AND the TCP model */ - SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); - error = EADDRINUSE; - goto out_now; - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - SCTP_INP_RUNLOCK(inp); - } else { - /* We increment here since sctp_findassociation_ep_addr() will - * do a decrement if it finds the stcb as long as the locked - * tcb (last argument) is NOT a TCB.. aka NULL. - */ - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_DECR_REF(inp); - } else { - SCTP_TCB_UNLOCK(stcb); - } - } - if (stcb != NULL) { - /* Already have or am bring up an association */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); - error = EALREADY; - goto out_now; - } - - vrf_id = inp->def_vrf_id; -#ifdef SCTP_MVRF - for (i = 0; i < inp->num_vrfs; i++) { - if (vrf_id == inp->m_vrf_ids[i]) { - fnd = 1; - break; - } - } - if (!fnd) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - goto out_now; - } -#endif - /* We are GOOD to go */ - stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, p, - SCTP_INITIALIZE_AUTH_PARAMS); - if (stcb == NULL) { - /* Gak! no memory */ - goto out_now; - } - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - SCTP_TCB_UNLOCK(stcb); - out_now: - if (create_lock_on) { - SCTP_ASOC_CREATE_UNLOCK(inp); - } - - SCTP_INP_DECR_REF(inp); - return (error); -} -#endif -int -#if defined(__Userspace__) -sctp_listen(struct socket *so, int backlog, struct proc *p) -#elif defined(__FreeBSD__) -sctp_listen(struct socket *so, int backlog, struct thread *p) -#elif defined(_WIN32) -sctp_listen(struct socket *so, int backlog, PKTHREAD p) -#else -sctp_listen(struct socket *so, struct proc *p) -#endif -{ - /* - * Note this module depends on the protocol processing being called - * AFTER any socket level flags and backlog are applied to the - * socket. The traditional way that the socket flags are applied is - * AFTER protocol processing. We have made a change to the - * sys/kern/uipc_socket.c module to reverse this but this MUST be in - * place if the socket API for SCTP is to work properly. - */ - - int error = 0; - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - /* I made the same as TCP since we are not setup? */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { - /* See if we have a listener */ - struct sctp_inpcb *tinp; - union sctp_sockstore store; - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { - /* not bound all */ - struct sctp_laddr *laddr; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - memcpy(&store, &laddr->ifa->address, sizeof(store)); - switch (store.sa.sa_family) { -#ifdef INET - case AF_INET: - store.sin.sin_port = inp->sctp_lport; - break; -#endif -#ifdef INET6 - case AF_INET6: - store.sin6.sin6_port = inp->sctp_lport; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - store.sconn.sconn_port = inp->sctp_lport; - break; -#endif - default: - break; - } - tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); - if (tinp && (tinp != inp) && - ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && - ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (SCTP_IS_LISTENING(tinp))) { - /* we have a listener already and its not this inp. */ - SCTP_INP_DECR_REF(tinp); - return (EADDRINUSE); - } else if (tinp) { - SCTP_INP_DECR_REF(tinp); - } - } - } else { - /* Setup a local addr bound all */ - memset(&store, 0, sizeof(store)); -#ifdef INET6 - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - store.sa.sa_family = AF_INET6; -#ifdef HAVE_SA_LEN - store.sa.sa_len = sizeof(struct sockaddr_in6); -#endif - } -#endif -#if defined(__Userspace__) - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - store.sa.sa_family = AF_CONN; -#ifdef HAVE_SA_LEN - store.sa.sa_len = sizeof(struct sockaddr_conn); -#endif - } -#endif -#ifdef INET -#if defined(__Userspace__) - if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && - ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) == 0)) { -#else - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { -#endif - store.sa.sa_family = AF_INET; -#ifdef HAVE_SA_LEN - store.sa.sa_len = sizeof(struct sockaddr_in); -#endif - } -#endif - switch (store.sa.sa_family) { -#ifdef INET - case AF_INET: - store.sin.sin_port = inp->sctp_lport; - break; -#endif -#ifdef INET6 - case AF_INET6: - store.sin6.sin6_port = inp->sctp_lport; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - store.sconn.sconn_port = inp->sctp_lport; - break; -#endif - default: - break; - } - tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); - if (tinp && (tinp != inp) && - ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && - ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (SCTP_IS_LISTENING(tinp))) { - /* we have a listener already and its not this inp. */ - SCTP_INP_DECR_REF(tinp); - return (EADDRINUSE); - } else if (tinp) { - SCTP_INP_DECR_REF(tinp); - } - } - } - SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); -#ifdef SCTP_LOCK_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { - sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); - } -#endif - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* The unlucky case - * - We are in the tcp pool with this guy. - * - Someone else is in the main inp slot. - * - We must move this guy (the listener) to the main slot - * - We must then move the guy that was listener to the TCP Pool. - */ - if (sctp_swap_inpcb_for_listen(inp)) { - error = EADDRINUSE; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - goto out; - } - } -#if defined(__FreeBSD__) || defined(__Userspace__) - SOCK_LOCK(so); - error = solisten_proto_check(so); - if (error) { - SOCK_UNLOCK(so); - goto out; - } -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { - SOCK_UNLOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - solisten_proto_abort(so); -#endif - error = EADDRINUSE; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - goto out; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || - (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED))) { - SOCK_UNLOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - solisten_proto_abort(so); -#endif - error = EINVAL; - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - goto out; - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { - if ((error = sctp_inpcb_bind_locked(inp, NULL, NULL, p))) { - SOCK_UNLOCK(so); -#if defined(__FreeBSD__) && !defined(__Userspace__) - solisten_proto_abort(so); -#endif - /* bind error, probably perm */ - goto out; - } - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) { - solisten_proto(so, backlog); - SOCK_UNLOCK(so); - inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING; - } else { - solisten_proto_abort(so); - SOCK_UNLOCK(so); - if (backlog > 0) { - inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING; - } else { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING; - } - } -#elif defined(_WIN32) || defined(__Userspace__) - solisten_proto(so, backlog); -#endif -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { - /* remove the ACCEPTCONN flag for one-to-many sockets */ -#if defined(__Userspace__) - so->so_options &= ~SCTP_SO_ACCEPTCONN; -#else - so->so_options &= ~SO_ACCEPTCONN; -#endif - } - SOCK_UNLOCK(so); - if (backlog > 0) { - inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING; - } else { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING; - } -#endif -out: - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - return (error); -} - -static int sctp_defered_wakeup_cnt = 0; - -int -sctp_accept(struct socket *so, struct sockaddr **addr) -{ - struct sctp_tcb *stcb; - struct sctp_inpcb *inp; - union sctp_sockstore store; -#ifdef INET6 -#if defined(SCTP_KAME) && defined(SCTP_EMBEDDED_V6_SCOPE) - int error; -#endif -#endif - inp = (struct sctp_inpcb *)so->so_pcb; - - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - SCTP_INP_WLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { - SCTP_INP_WUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - return (EOPNOTSUPP); - } - if (so->so_state & SS_ISDISCONNECTED) { - SCTP_INP_WUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); - return (ECONNABORTED); - } - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_WUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - SCTP_TCB_LOCK(stcb); - store = stcb->asoc.primary_destination->ro._l_addr; - SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE); - /* Wake any delayed sleep action */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; - if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; - SOCKBUF_LOCK(&inp->sctp_socket->so_snd); - if (sowriteable(inp->sctp_socket)) { -#if defined(__Userspace__) - /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */ -#endif -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) - sowwakeup_locked(inp->sctp_socket); -#else -#if defined(__APPLE__) - /* socket is locked */ -#endif - sowwakeup(inp->sctp_socket); -#endif - } else { - SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); - } - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; - SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); - if (soreadable(inp->sctp_socket)) { - sctp_defered_wakeup_cnt++; -#if defined(__Userspace__) - /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */ -#endif -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) - sorwakeup_locked(inp->sctp_socket); -#else -#if defined(__APPLE__) - /* socket is locked */ -#endif - sorwakeup(inp->sctp_socket); -#endif - } else { - SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); - } - } - } - SCTP_INP_WUNLOCK(inp); - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19); - } else { - SCTP_TCB_UNLOCK(stcb); - } - switch (store.sa.sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); - if (sin == NULL) - return (ENOMEM); - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(*sin); -#endif - sin->sin_port = store.sin.sin_port; - sin->sin_addr = store.sin.sin_addr; - *addr = (struct sockaddr *)sin; - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); - if (sin6 == NULL) - return (ENOMEM); - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(*sin6); -#endif - sin6->sin6_port = store.sin6.sin6_port; - sin6->sin6_addr = store.sin6.sin6_addr; -#if defined(SCTP_EMBEDDED_V6_SCOPE) -#ifdef SCTP_KAME - if ((error = sa6_recoverscope(sin6)) != 0) { - SCTP_FREE_SONAME(sin6); - return (error); - } -#else - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) - /* - * sin6->sin6_scope_id = - * ntohs(sin6->sin6_addr.s6_addr16[1]); - */ - in6_recoverscope(sin6, &sin6->sin6_addr, NULL); /* skip ifp check */ - else - sin6->sin6_scope_id = 0; /* XXX */ -#endif /* SCTP_KAME */ -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - *addr = (struct sockaddr *)sin6; - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn; - - SCTP_MALLOC_SONAME(sconn, struct sockaddr_conn *, sizeof(struct sockaddr_conn)); - if (sconn == NULL) { - return (ENOMEM); - } - sconn->sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - sconn->sconn_len = sizeof(struct sockaddr_conn); -#endif - sconn->sconn_port = store.sconn.sconn_port; - sconn->sconn_addr = store.sconn.sconn_addr; - *addr = (struct sockaddr *)sconn; - break; - } -#endif - default: - /* TSNH */ - break; - } - return (0); -} - -#ifdef INET -int -#if !defined(__Userspace__) -sctp_ingetaddr(struct socket *so, struct sockaddr **addr) -{ - struct sockaddr_in *sin; -#else -sctp_ingetaddr(struct socket *so, struct mbuf *nam) -{ - struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); -#endif - uint32_t vrf_id; - struct sctp_inpcb *inp; - struct sctp_ifa *sctp_ifa; - - /* - * Do the malloc first in case it blocks. - */ -#if !defined(__Userspace__) - SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); - if (sin == NULL) - return (ENOMEM); -#else - SCTP_BUF_LEN(nam) = sizeof(*sin); - memset(sin, 0, sizeof(*sin)); -#endif - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(*sin); -#endif - inp = (struct sctp_inpcb *)so->so_pcb; - if (!inp) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - SCTP_INP_RLOCK(inp); - sin->sin_port = inp->sctp_lport; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - struct sctp_tcb *stcb; - struct sockaddr_in *sin_a; - struct sctp_nets *net; - int fnd; - - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - goto notConn; - } - fnd = 0; - sin_a = NULL; - SCTP_TCB_LOCK(stcb); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sin_a = (struct sockaddr_in *)&net->ro._l_addr; - if (sin_a == NULL) - /* this will make coverity happy */ - continue; - - if (sin_a->sin_family == AF_INET) { - fnd = 1; - break; - } - } - if ((!fnd) || (sin_a == NULL)) { - /* punt */ - SCTP_TCB_UNLOCK(stcb); - goto notConn; - } - - vrf_id = inp->def_vrf_id; - sctp_ifa = sctp_source_address_selection(inp, - stcb, - (sctp_route_t *)&net->ro, - net, 0, vrf_id); - if (sctp_ifa) { - sin->sin_addr = sctp_ifa->address.sin.sin_addr; - sctp_free_ifa(sctp_ifa); - } - SCTP_TCB_UNLOCK(stcb); - } else { - /* For the bound all case you get back 0 */ - notConn: - sin->sin_addr.s_addr = 0; - } - - } else { - /* Take the first IPv4 address in the list */ - struct sctp_laddr *laddr; - int fnd = 0; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa->address.sa.sa_family == AF_INET) { - struct sockaddr_in *sin_a; - - sin_a = &laddr->ifa->address.sin; - sin->sin_addr = sin_a->sin_addr; - fnd = 1; - break; - } - } - if (!fnd) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin); -#endif - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - return (ENOENT); - } - } - SCTP_INP_RUNLOCK(inp); -#if !defined(__Userspace__) - (*addr) = (struct sockaddr *)sin; -#endif - return (0); -} - -int -#if !defined(__Userspace__) -sctp_peeraddr(struct socket *so, struct sockaddr **addr) -{ - struct sockaddr_in *sin; -#else -sctp_peeraddr(struct socket *so, struct mbuf *nam) -{ - struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); - -#endif - int fnd; - struct sockaddr_in *sin_a; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - - /* Do the malloc first in case it blocks. */ -#if !defined(__Userspace__) - SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); - if (sin == NULL) - return (ENOMEM); -#else - SCTP_BUF_LEN(nam) = sizeof(*sin); - memset(sin, 0, sizeof(*sin)); -#endif - sin->sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(*sin); -#endif - - inp = (struct sctp_inpcb *)so->so_pcb; - if ((inp == NULL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { - /* UDP type and listeners will drop out here */ -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - return (ENOTCONN); - } - SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb) { - SCTP_TCB_LOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - if (stcb == NULL) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (ECONNRESET); - } - fnd = 0; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sin_a = (struct sockaddr_in *)&net->ro._l_addr; - if (sin_a->sin_family == AF_INET) { - fnd = 1; - sin->sin_port = stcb->rport; - sin->sin_addr = sin_a->sin_addr; - break; - } - } - SCTP_TCB_UNLOCK(stcb); - if (!fnd) { - /* No IPv4 address */ -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); - return (ENOENT); - } -#if !defined(__Userspace__) - (*addr) = (struct sockaddr *)sin; -#endif - return (0); -} - -#if !defined(__Userspace__) -#if defined(__FreeBSD__) -#define SCTP_PROTOSW \ - .pr_protocol = IPPROTO_SCTP, \ - .pr_ctloutput = sctp_ctloutput, \ - .pr_abort = sctp_abort, \ - .pr_accept = sctp_accept, \ - .pr_attach = sctp_attach, \ - .pr_bind = sctp_bind, \ - .pr_connect = sctp_connect, \ - .pr_control = in_control, \ - .pr_close = sctp_close, \ - .pr_detach = sctp_close, \ - .pr_sopoll = sopoll_generic, \ - .pr_flush = sctp_flush, \ - .pr_disconnect = sctp_disconnect, \ - .pr_listen = sctp_listen, \ - .pr_peeraddr = sctp_peeraddr, \ - .pr_send = sctp_sendm, \ - .pr_shutdown = sctp_shutdown, \ - .pr_sockaddr = sctp_ingetaddr, \ - .pr_sosend = sctp_sosend, \ - .pr_soreceive = sctp_soreceive \ - -struct protosw sctp_seqpacket_protosw = { - .pr_type = SOCK_SEQPACKET, - .pr_flags = PR_WANTRCVD, - SCTP_PROTOSW -}; - -struct protosw sctp_stream_protosw = { - .pr_type = SOCK_STREAM, - .pr_flags = PR_CONNREQUIRED | PR_WANTRCVD, - SCTP_PROTOSW -}; -#else -struct pr_usrreqs sctp_usrreqs = { -#if defined(__APPLE__) - .pru_abort = sctp_abort, - .pru_accept = sctp_accept, - .pru_attach = sctp_attach, - .pru_bind = sctp_bind, - .pru_connect = sctp_connect, - .pru_connect2 = pru_connect2_notsupp, - .pru_control = in_control, - .pru_detach = sctp_detach, - .pru_disconnect = sctp_disconnect, - .pru_listen = sctp_listen, - .pru_peeraddr = sctp_peeraddr, - .pru_rcvd = NULL, - .pru_rcvoob = pru_rcvoob_notsupp, - .pru_send = sctp_sendm, - .pru_sense = pru_sense_null, - .pru_shutdown = sctp_shutdown, - .pru_sockaddr = sctp_ingetaddr, - .pru_sosend = sctp_sosend, - .pru_soreceive = sctp_soreceive, - .pru_sopoll = sopoll -#elif defined(_WIN32) && !defined(__Userspace__) - sctp_abort, - sctp_accept, - sctp_attach, - sctp_bind, - sctp_connect, - pru_connect2_notsupp, - NULL, - NULL, - sctp_disconnect, - sctp_listen, - sctp_peeraddr, - NULL, - pru_rcvoob_notsupp, - NULL, - pru_sense_null, - sctp_shutdown, - sctp_flush, - sctp_ingetaddr, - sctp_sosend, - sctp_soreceive, - sopoll_generic, - NULL, - sctp_close -#endif -}; -#endif -#endif -#endif - -#if defined(__Userspace__) -int -register_recv_cb(struct socket *so, - int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data, - size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info)) -{ - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *) so->so_pcb; - if (inp == NULL) { - return (0); - } - SCTP_INP_WLOCK(inp); - inp->recv_callback = receive_cb; - SCTP_INP_WUNLOCK(inp); - return (1); -} - -int -register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info)) -{ - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *) so->so_pcb; - if (inp == NULL) { - return (0); - } - SCTP_INP_WLOCK(inp); - inp->send_callback = send_cb; - inp->send_sb_threshold = sb_threshold; - SCTP_INP_WUNLOCK(inp); - /* FIXME change to current amount free. This will be the full buffer - * the first time this is registered but it could be only a portion - * of the send buffer if this is called a second time e.g. if the - * threshold changes. - */ - return (1); -} - -int -register_ulp_info (struct socket *so, void *ulp_info) -{ - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *) so->so_pcb; - if (inp == NULL) { - return (0); - } - SCTP_INP_WLOCK(inp); - inp->ulp_info = ulp_info; - SCTP_INP_WUNLOCK(inp); - return (1); -} - -int -retrieve_ulp_info (struct socket *so, void **pulp_info) -{ - struct sctp_inpcb *inp; - - if (pulp_info == NULL) { - return (0); - } - - inp = (struct sctp_inpcb *) so->so_pcb; - if (inp == NULL) { - return (0); - } - SCTP_INP_RLOCK(inp); - *pulp_info = inp->ulp_info; - SCTP_INP_RUNLOCK(inp); - return (1); -} -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_var.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_var.h deleted file mode 100644 index 6613b586..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctp_var.h +++ /dev/null @@ -1,458 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_VAR_H_ -#define _NETINET_SCTP_VAR_H_ - -#include - -#if defined(_KERNEL) || defined(__Userspace__) - -#if !defined(__Userspace__) -#if defined(__FreeBSD__) -extern struct protosw sctp_seqpacket_protosw, sctp_stream_protosw; -#else -extern struct pr_usrreqs sctp_usrreqs; -#endif -#endif - -#define sctp_feature_on(inp, feature) (inp->sctp_features |= feature) -#define sctp_feature_off(inp, feature) (inp->sctp_features &= ~feature) -#define sctp_is_feature_on(inp, feature) ((inp->sctp_features & feature) == feature) -#define sctp_is_feature_off(inp, feature) ((inp->sctp_features & feature) == 0) - -#define sctp_stcb_feature_on(inp, stcb, feature) {\ - if (stcb) { \ - stcb->asoc.sctp_features |= feature; \ - } else if (inp) { \ - inp->sctp_features |= feature; \ - } \ -} -#define sctp_stcb_feature_off(inp, stcb, feature) {\ - if (stcb) { \ - stcb->asoc.sctp_features &= ~feature; \ - } else if (inp) { \ - inp->sctp_features &= ~feature; \ - } \ -} -#define sctp_stcb_is_feature_on(inp, stcb, feature) \ - (((stcb != NULL) && \ - ((stcb->asoc.sctp_features & feature) == feature)) || \ - ((stcb == NULL) && (inp != NULL) && \ - ((inp->sctp_features & feature) == feature))) -#define sctp_stcb_is_feature_off(inp, stcb, feature) \ - (((stcb != NULL) && \ - ((stcb->asoc.sctp_features & feature) == 0)) || \ - ((stcb == NULL) && (inp != NULL) && \ - ((inp->sctp_features & feature) == 0)) || \ - ((stcb == NULL) && (inp == NULL))) - -/* managing mobility_feature in inpcb (by micchie) */ -#define sctp_mobility_feature_on(inp, feature) (inp->sctp_mobility_features |= feature) -#define sctp_mobility_feature_off(inp, feature) (inp->sctp_mobility_features &= ~feature) -#define sctp_is_mobility_feature_on(inp, feature) (inp->sctp_mobility_features & feature) -#define sctp_is_mobility_feature_off(inp, feature) ((inp->sctp_mobility_features & feature) == 0) - -#define sctp_maxspace(sb) (max((sb)->sb_hiwat,SCTP_MINIMAL_RWND)) - -#define sctp_sbspace(asoc, sb) ((long) ((sctp_maxspace(sb) > (asoc)->sb_cc) ? (sctp_maxspace(sb) - (asoc)->sb_cc) : 0)) - -#define sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > SCTP_SBAVAIL(sb)) ? (sctp_maxspace(sb) - SCTP_SBAVAIL(sb)) : 0)) - -#define sctp_sbspace_sub(a,b) (((a) > (b)) ? ((a) - (b)) : 0) - -/* - * I tried to cache the readq entries at one point. But the reality - * is that it did not add any performance since this meant we had to - * lock the STCB on read. And at that point once you have to do an - * extra lock, it really does not matter if the lock is in the ZONE - * stuff or in our code. Note that this same problem would occur with - * an mbuf cache as well so it is not really worth doing, at least - * right now :-D - */ -#ifdef INVARIANTS -#define sctp_free_a_readq(_stcb, _readq) { \ - if ((_readq)->on_strm_q) \ - panic("On strm q stcb:%p readq:%p", (_stcb), (_readq)); \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \ - SCTP_DECR_READQ_COUNT(); \ -} -#else -#define sctp_free_a_readq(_stcb, _readq) { \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \ - SCTP_DECR_READQ_COUNT(); \ -} -#endif - -#define sctp_alloc_a_readq(_stcb, _readq) { \ - (_readq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_readq), struct sctp_queued_to_read); \ - if ((_readq)) { \ - SCTP_INCR_READQ_COUNT(); \ - } \ -} - -#define sctp_free_a_strmoq(_stcb, _strmoq, _so_locked) { \ - if ((_strmoq)->holds_key_ref) { \ - sctp_auth_key_release(stcb, sp->auth_keyid, _so_locked); \ - (_strmoq)->holds_key_ref = 0; \ - } \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_strmoq), (_strmoq)); \ - SCTP_DECR_STRMOQ_COUNT(); \ -} - -#define sctp_alloc_a_strmoq(_stcb, _strmoq) { \ - (_strmoq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_strmoq), struct sctp_stream_queue_pending); \ - if ((_strmoq)) { \ - memset(_strmoq, 0, sizeof(struct sctp_stream_queue_pending)); \ - SCTP_INCR_STRMOQ_COUNT(); \ - (_strmoq)->holds_key_ref = 0; \ - } \ -} - -#define sctp_free_a_chunk(_stcb, _chk, _so_locked) { \ - if ((_chk)->holds_key_ref) {\ - sctp_auth_key_release((_stcb), (_chk)->auth_keyid, _so_locked); \ - (_chk)->holds_key_ref = 0; \ - } \ - if (_stcb) { \ - SCTP_TCB_LOCK_ASSERT((_stcb)); \ - if ((_chk)->whoTo) { \ - sctp_free_remote_addr((_chk)->whoTo); \ - (_chk)->whoTo = NULL; \ - } \ - if (((_stcb)->asoc.free_chunk_cnt > SCTP_BASE_SYSCTL(sctp_asoc_free_resc_limit)) || \ - (SCTP_BASE_INFO(ipi_free_chunks) > SCTP_BASE_SYSCTL(sctp_system_free_resc_limit))) { \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), (_chk)); \ - SCTP_DECR_CHK_COUNT(); \ - } else { \ - TAILQ_INSERT_TAIL(&(_stcb)->asoc.free_chunks, (_chk), sctp_next); \ - (_stcb)->asoc.free_chunk_cnt++; \ - atomic_add_int(&SCTP_BASE_INFO(ipi_free_chunks), 1); \ - } \ - } else { \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), (_chk)); \ - SCTP_DECR_CHK_COUNT(); \ - } \ -} - -#define sctp_alloc_a_chunk(_stcb, _chk) { \ - if (TAILQ_EMPTY(&(_stcb)->asoc.free_chunks)) { \ - (_chk) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_chunk), struct sctp_tmit_chunk); \ - if ((_chk)) { \ - SCTP_INCR_CHK_COUNT(); \ - (_chk)->whoTo = NULL; \ - (_chk)->holds_key_ref = 0; \ - } \ - } else { \ - (_chk) = TAILQ_FIRST(&(_stcb)->asoc.free_chunks); \ - TAILQ_REMOVE(&(_stcb)->asoc.free_chunks, (_chk), sctp_next); \ - atomic_subtract_int(&SCTP_BASE_INFO(ipi_free_chunks), 1); \ - (_chk)->holds_key_ref = 0; \ - SCTP_STAT_INCR(sctps_cached_chk); \ - (_stcb)->asoc.free_chunk_cnt--; \ - } \ -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#define sctp_free_remote_addr(__net) { \ - if ((__net)) { \ - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \ - RO_NHFREE(&(__net)->ro); \ - if ((__net)->src_addr_selected) { \ - sctp_free_ifa((__net)->ro._s_addr); \ - (__net)->ro._s_addr = NULL; \ - } \ - (__net)->src_addr_selected = 0; \ - (__net)->dest_state &= ~SCTP_ADDR_REACHABLE; \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_net), (__net)); \ - SCTP_DECR_RADDR_COUNT(); \ - } \ - } \ -} - -#define sctp_sbfree(ctl, stcb, sb, m) { \ - SCTP_SB_DECR(sb, SCTP_BUF_LEN((m))); \ - SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \ - if (((ctl)->do_not_ref_stcb == 0) && stcb) {\ - SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ - SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \ - } \ - if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \ - SCTP_BUF_TYPE(m) != MT_OOBDATA) \ - atomic_subtract_int(&(sb)->sb_ctl,SCTP_BUF_LEN((m))); \ -} - -#define sctp_sballoc(stcb, sb, m) { \ - SCTP_SB_INCR(sb, SCTP_BUF_LEN((m))); \ - atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \ - if (stcb) { \ - atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ - atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \ - } \ - if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \ - SCTP_BUF_TYPE(m) != MT_OOBDATA) \ - atomic_add_int(&(sb)->sb_ctl,SCTP_BUF_LEN((m))); \ -} -#else /* FreeBSD Version <= 500000 or non-FreeBSD */ -#define sctp_free_remote_addr(__net) { \ - if ((__net)) { \ - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \ - if ((__net)->ro.ro_rt) { \ - RTFREE((__net)->ro.ro_rt); \ - (__net)->ro.ro_rt = NULL; \ - } \ - if ((__net)->src_addr_selected) { \ - sctp_free_ifa((__net)->ro._s_addr); \ - (__net)->ro._s_addr = NULL; \ - } \ - (__net)->src_addr_selected = 0; \ - (__net)->dest_state &=~SCTP_ADDR_REACHABLE; \ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_net), (__net)); \ - SCTP_DECR_RADDR_COUNT(); \ - } \ - } \ -} - -#define sctp_sbfree(ctl, stcb, sb, m) { \ - SCTP_SB_DECR(sb, SCTP_BUF_LEN((m))); \ - SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \ - if (((ctl)->do_not_ref_stcb == 0) && stcb) { \ - SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ - SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \ - } \ -} - -#define sctp_sballoc(stcb, sb, m) { \ - SCTP_SB_INCR(sb, SCTP_BUF_LEN((m))); \ - atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \ - if (stcb) { \ - atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ - atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \ - } \ -} -#endif - -#define sctp_ucount_incr(val) { \ - val++; \ -} - -#define sctp_ucount_decr(val) { \ - if (val > 0) { \ - val--; \ - } else { \ - val = 0; \ - } \ -} - -#define sctp_mbuf_crush(data) do { \ - struct mbuf *_m; \ - _m = (data); \ - while (_m && (SCTP_BUF_LEN(_m) == 0)) { \ - (data) = SCTP_BUF_NEXT(_m); \ - SCTP_BUF_NEXT(_m) = NULL; \ - sctp_m_free(_m); \ - _m = (data); \ - } \ -} while (0) - -#define sctp_flight_size_decrease(tp1) do { \ - if (tp1->whoTo->flight_size >= tp1->book_size) \ - tp1->whoTo->flight_size -= tp1->book_size; \ - else \ - tp1->whoTo->flight_size = 0; \ -} while (0) - -#define sctp_flight_size_increase(tp1) do { \ - (tp1)->whoTo->flight_size += (tp1)->book_size; \ -} while (0) - -#ifdef SCTP_FS_SPEC_LOG -#define sctp_total_flight_decrease(stcb, tp1) do { \ - if (stcb->asoc.fs_index > SCTP_FS_SPEC_LOG_SIZE) \ - stcb->asoc.fs_index = 0;\ - stcb->asoc.fslog[stcb->asoc.fs_index].total_flight = stcb->asoc.total_flight; \ - stcb->asoc.fslog[stcb->asoc.fs_index].tsn = tp1->rec.data.tsn; \ - stcb->asoc.fslog[stcb->asoc.fs_index].book = tp1->book_size; \ - stcb->asoc.fslog[stcb->asoc.fs_index].sent = tp1->sent; \ - stcb->asoc.fslog[stcb->asoc.fs_index].incr = 0; \ - stcb->asoc.fslog[stcb->asoc.fs_index].decr = 1; \ - stcb->asoc.fs_index++; \ - tp1->window_probe = 0; \ - if (stcb->asoc.total_flight >= tp1->book_size) { \ - stcb->asoc.total_flight -= tp1->book_size; \ - if (stcb->asoc.total_flight_count > 0) \ - stcb->asoc.total_flight_count--; \ - } else { \ - stcb->asoc.total_flight = 0; \ - stcb->asoc.total_flight_count = 0; \ - } \ -} while (0) - -#define sctp_total_flight_increase(stcb, tp1) do { \ - if (stcb->asoc.fs_index > SCTP_FS_SPEC_LOG_SIZE) \ - stcb->asoc.fs_index = 0;\ - stcb->asoc.fslog[stcb->asoc.fs_index].total_flight = stcb->asoc.total_flight; \ - stcb->asoc.fslog[stcb->asoc.fs_index].tsn = tp1->rec.data.tsn; \ - stcb->asoc.fslog[stcb->asoc.fs_index].book = tp1->book_size; \ - stcb->asoc.fslog[stcb->asoc.fs_index].sent = tp1->sent; \ - stcb->asoc.fslog[stcb->asoc.fs_index].incr = 1; \ - stcb->asoc.fslog[stcb->asoc.fs_index].decr = 0; \ - stcb->asoc.fs_index++; \ - (stcb)->asoc.total_flight_count++; \ - (stcb)->asoc.total_flight += (tp1)->book_size; \ -} while (0) - -#else - -#define sctp_total_flight_decrease(stcb, tp1) do { \ - tp1->window_probe = 0; \ - if (stcb->asoc.total_flight >= tp1->book_size) { \ - stcb->asoc.total_flight -= tp1->book_size; \ - if (stcb->asoc.total_flight_count > 0) \ - stcb->asoc.total_flight_count--; \ - } else { \ - stcb->asoc.total_flight = 0; \ - stcb->asoc.total_flight_count = 0; \ - } \ -} while (0) - -#define sctp_total_flight_increase(stcb, tp1) do { \ - (stcb)->asoc.total_flight_count++; \ - (stcb)->asoc.total_flight += (tp1)->book_size; \ -} while (0) - -#endif - -#define SCTP_PF_ENABLED(_net) (_net->pf_threshold < _net->failure_threshold) -#define SCTP_NET_IS_PF(_net) (_net->pf_threshold < _net->error_count) - -struct sctp_nets; -struct sctp_inpcb; -struct sctp_tcb; -struct sctphdr; - -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -void sctp_close(struct socket *so); -#else -int sctp_detach(struct socket *so); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -void sctp_abort(struct socket *so); -#else -int sctp_abort(struct socket *so); -#endif -int sctp_disconnect(struct socket *so); -#if !defined(__Userspace__) -#if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN) -void sctp_ctlinput(int, struct sockaddr *, void *, struct ifnet * SCTP_UNUSED); -#elif defined(__FreeBSD__) -ipproto_ctlinput_t sctp_ctlinput; -#else -void sctp_ctlinput(int, struct sockaddr *, void *); -#endif -int sctp_ctloutput(struct socket *, struct sockopt *); -#ifdef INET -void sctp_input_with_port(struct mbuf *, int, uint16_t); -#if defined(__FreeBSD__) && !defined(__Userspace__) -int sctp_input(struct mbuf **, int *, int); -#else -void sctp_input(struct mbuf *, int); -#endif -#endif -void sctp_pathmtu_adjustment(struct sctp_tcb *, uint32_t, bool); -#else -#if defined(__Userspace__) -void sctp_pathmtu_adjustment(struct sctp_tcb *, uint32_t, bool); -#else -void sctp_input(struct mbuf *,...); -#endif -void *sctp_ctlinput(int, struct sockaddr *, void *); -int sctp_ctloutput(int, struct socket *, int, int, struct mbuf **); -#endif -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) -void sctp_drain(void); -#endif -#if defined(__Userspace__) -void sctp_init(uint16_t, - int (*)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), - void (*)(const char *, ...), int start_threads); -#elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) -void sctp_init(struct protosw *pp, struct domain *dp); -#else -#if !defined(__FreeBSD__) -void sctp_init(void); -#endif -void sctp_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, - uint8_t, uint8_t, uint16_t, uint32_t); -#endif -#if !defined(__FreeBSD__) && !defined(__Userspace__) -void sctp_finish(void); -#endif -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -int sctp_flush(struct socket *, int); -#endif -int sctp_shutdown(struct socket *); -int sctp_bindx(struct socket *, int, struct sockaddr_storage *, - int, int, struct proc *); -/* can't use sctp_assoc_t here */ -int sctp_peeloff(struct socket *, struct socket *, int, caddr_t, int *); -#if !defined(__Userspace__) -int sctp_ingetaddr(struct socket *, struct sockaddr **); -#else -int sctp_ingetaddr(struct socket *, struct mbuf *); -#endif -#if !defined(__Userspace__) -int sctp_peeraddr(struct socket *, struct sockaddr **); -#else -int sctp_peeraddr(struct socket *, struct mbuf *); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -int sctp_listen(struct socket *, int, struct thread *); -#elif defined(_WIN32) && !defined(__Userspace__) -int sctp_listen(struct socket *, int, PKTHREAD); -#elif defined(__Userspace__) -int sctp_listen(struct socket *, int, struct proc *); -#else -int sctp_listen(struct socket *, struct proc *); -#endif -int sctp_accept(struct socket *, struct sockaddr **); - -#endif /* _KERNEL */ - -#endif /* !_NETINET_SCTP_VAR_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.c deleted file mode 100644 index a4cfdff3..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.c +++ /dev/null @@ -1,8707 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include -#ifdef INET6 -#if defined(__Userspace__) || defined(__FreeBSD__) -#include -#endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__Userspace__) -#include -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#if defined(INET6) || defined(INET) -#include -#endif -#include -#include -#include -#ifdef INET6 -#include -#endif -#endif - -#if defined(_WIN32) && !defined(__Userspace__) -#if !defined(SCTP_LOCAL_TRACE_BUF) -#include "eventrace_netinet.h" -#include "sctputil.tmh" /* this is the file that will be auto generated */ -#endif -#else -#ifndef KTR_SCTP -#define KTR_SCTP KTR_SUBSYS -#endif -#endif - -extern const struct sctp_cc_functions sctp_cc_functions[]; -extern const struct sctp_ss_functions sctp_ss_functions[]; - -void -sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.sb.stcb = stcb; - sctp_clog.x.sb.so_sbcc = SCTP_SBAVAIL(sb); - if (stcb) - sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc; - else - sctp_clog.x.sb.stcb_sbcc = 0; - sctp_clog.x.sb.incr = incr; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_SB, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.close.inp = (void *)inp; - sctp_clog.x.close.sctp_flags = inp->sctp_flags; - if (stcb) { - sctp_clog.x.close.stcb = (void *)stcb; - sctp_clog.x.close.state = (uint16_t)stcb->asoc.state; - } else { - sctp_clog.x.close.stcb = 0; - sctp_clog.x.close.state = 0; - } - sctp_clog.x.close.loc = loc; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_CLOSE, - 0, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -rto_logging(struct sctp_nets *net, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - memset(&sctp_clog, 0, sizeof(sctp_clog)); - sctp_clog.x.rto.net = (void *) net; - sctp_clog.x.rto.rtt = net->rtt / 1000; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_RTT, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.strlog.stcb = stcb; - sctp_clog.x.strlog.n_tsn = tsn; - sctp_clog.x.strlog.n_sseq = sseq; - sctp_clog.x.strlog.e_tsn = 0; - sctp_clog.x.strlog.e_sseq = 0; - sctp_clog.x.strlog.strm = stream; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_STRM, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_nagle_event(struct sctp_tcb *stcb, int action) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.nagle.stcb = (void *)stcb; - sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight; - sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size; - sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue; - sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_NAGLE, - action, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.sack.cumack = cumack; - sctp_clog.x.sack.oldcumack = old_cumack; - sctp_clog.x.sack.tsn = tsn; - sctp_clog.x.sack.numGaps = gaps; - sctp_clog.x.sack.numDups = dups; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_SACK, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - memset(&sctp_clog, 0, sizeof(sctp_clog)); - sctp_clog.x.map.base = map; - sctp_clog.x.map.cum = cum; - sctp_clog.x.map.high = high; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_MAP, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - memset(&sctp_clog, 0, sizeof(sctp_clog)); - sctp_clog.x.fr.largest_tsn = biggest_tsn; - sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn; - sctp_clog.x.fr.tsn = tsn; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_FR, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -#ifdef SCTP_MBUF_LOGGING -void -sctp_log_mb(struct mbuf *m, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.mb.mp = m; - sctp_clog.x.mb.mbuf_flags = (uint8_t)(SCTP_BUF_GET_FLAGS(m)); - sctp_clog.x.mb.size = (uint16_t)(SCTP_BUF_LEN(m)); - sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0); - if (SCTP_BUF_IS_EXTENDED(m)) { - sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m); -#if defined(__APPLE__) && !defined(__Userspace__) - /* APPLE does not use a ref_cnt, but a forward/backward ref queue */ -#else - sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m)); -#endif - } else { - sctp_clog.x.mb.ext = 0; - sctp_clog.x.mb.refcnt = 0; - } - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_MBUF, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_mbc(struct mbuf *m, int from) -{ - struct mbuf *mat; - - for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { - sctp_log_mb(mat, from); - } -} -#endif - -void -sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - if (control == NULL) { - SCTP_PRINTF("Gak log of NULL?\n"); - return; - } - sctp_clog.x.strlog.stcb = control->stcb; - sctp_clog.x.strlog.n_tsn = control->sinfo_tsn; - sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid; - sctp_clog.x.strlog.strm = control->sinfo_stream; - if (poschk != NULL) { - sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn; - sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid; - } else { - sctp_clog.x.strlog.e_tsn = 0; - sctp_clog.x.strlog.e_sseq = 0; - } - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_STRM, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.cwnd.net = net; - if (stcb->asoc.send_queue_cnt > 255) - sctp_clog.x.cwnd.cnt_in_send = 255; - else - sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; - if (stcb->asoc.stream_queue_cnt > 255) - sctp_clog.x.cwnd.cnt_in_str = 255; - else - sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; - - if (net) { - sctp_clog.x.cwnd.cwnd_new_value = net->cwnd; - sctp_clog.x.cwnd.inflight = net->flight_size; - sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack; - sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack; - sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack; - } - if (SCTP_CWNDLOG_PRESEND == from) { - sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd; - } - sctp_clog.x.cwnd.cwnd_augment = augment; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_CWND, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -#if !defined(__APPLE__) && !defined(__Userspace__) -void -sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - memset(&sctp_clog, 0, sizeof(sctp_clog)); - if (inp) { - sctp_clog.x.lock.sock = (void *) inp->sctp_socket; - - } else { - sctp_clog.x.lock.sock = (void *) NULL; - } - sctp_clog.x.lock.inp = (void *) inp; -#if defined(__FreeBSD__) - if (stcb) { - sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx); - } else { - sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN; - } - if (inp) { - sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx); - sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx); - } else { - sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN; - sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN; - } - sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); - if (inp && (inp->sctp_socket)) { - sctp_clog.x.lock.sock_lock = mtx_owned(SOCK_MTX(inp->sctp_socket)); - sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(SOCKBUF_MTX(&inp->sctp_socket->so_rcv)); - sctp_clog.x.lock.socksndbuf_lock = mtx_owned(SOCKBUF_MTX(&inp->sctp_socket->so_snd)); - } else { - sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN; - sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; - sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN; - } -#endif - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_LOCK_EVENT, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} -#endif - -void -sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - memset(&sctp_clog, 0, sizeof(sctp_clog)); - sctp_clog.x.cwnd.net = net; - sctp_clog.x.cwnd.cwnd_new_value = error; - sctp_clog.x.cwnd.inflight = net->flight_size; - sctp_clog.x.cwnd.cwnd_augment = burst; - if (stcb->asoc.send_queue_cnt > 255) - sctp_clog.x.cwnd.cnt_in_send = 255; - else - sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; - if (stcb->asoc.stream_queue_cnt > 255) - sctp_clog.x.cwnd.cnt_in_str = 255; - else - sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_MAXBURST, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.rwnd.rwnd = peers_rwnd; - sctp_clog.x.rwnd.send_size = snd_size; - sctp_clog.x.rwnd.overhead = overhead; - sctp_clog.x.rwnd.new_rwnd = 0; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_RWND, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.rwnd.rwnd = peers_rwnd; - sctp_clog.x.rwnd.send_size = flight_size; - sctp_clog.x.rwnd.overhead = overhead; - sctp_clog.x.rwnd.new_rwnd = a_rwndval; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_RWND, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -#ifdef SCTP_MBCNT_LOGGING -static void -sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.mbcnt.total_queue_size = total_oq; - sctp_clog.x.mbcnt.size_change = book; - sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q; - sctp_clog.x.mbcnt.mbcnt_change = mbcnt; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_MBCNT, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} -#endif - -void -sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_MISC_EVENT, - from, - a, b, c, d); -#endif -} - -void -sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.wake.stcb = (void *)stcb; - sctp_clog.x.wake.wake_cnt = wake_cnt; - sctp_clog.x.wake.flight = stcb->asoc.total_flight_count; - sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt; - sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt; - - if (stcb->asoc.stream_queue_cnt < 0xff) - sctp_clog.x.wake.stream_qcnt = (uint8_t) stcb->asoc.stream_queue_cnt; - else - sctp_clog.x.wake.stream_qcnt = 0xff; - - if (stcb->asoc.chunks_on_out_queue < 0xff) - sctp_clog.x.wake.chunks_on_oque = (uint8_t) stcb->asoc.chunks_on_out_queue; - else - sctp_clog.x.wake.chunks_on_oque = 0xff; - - sctp_clog.x.wake.sctpflags = 0; - /* set in the defered mode stuff */ - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) - sctp_clog.x.wake.sctpflags |= 1; - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) - sctp_clog.x.wake.sctpflags |= 2; - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) - sctp_clog.x.wake.sctpflags |= 4; - /* what about the sb */ - if (stcb->sctp_socket) { - struct socket *so = stcb->sctp_socket; - - sctp_clog.x.wake.sbflags = (uint8_t)((so->so_snd.sb_flags & 0x00ff)); - } else { - sctp_clog.x.wake.sbflags = 0xff; - } - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_WAKE, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -void -sctp_log_block(uint8_t from, struct sctp_association *asoc, ssize_t sendlen) -{ -#if defined(SCTP_LOCAL_TRACE_BUF) - struct sctp_cwnd_log sctp_clog; - - sctp_clog.x.blk.onsb = asoc->total_output_queue_size; - sctp_clog.x.blk.send_sent_qcnt = (uint16_t) (asoc->send_queue_cnt + asoc->sent_queue_cnt); - sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd; - sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt; - sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue; - sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight/1024); - sctp_clog.x.blk.sndlen = (uint32_t)sendlen; - SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", - SCTP_LOG_EVENT_BLOCK, - from, - sctp_clog.x.misc.log1, - sctp_clog.x.misc.log2, - sctp_clog.x.misc.log3, - sctp_clog.x.misc.log4); -#endif -} - -int -sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED) -{ - /* May need to fix this if ktrdump does not work */ - return (0); -} - -#ifdef SCTP_AUDITING_ENABLED -uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2]; -static int sctp_audit_indx = 0; - -static -void -sctp_print_audit_report(void) -{ - int i; - int cnt; - - cnt = 0; - for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) { - if ((sctp_audit_data[i][0] == 0xe0) && - (sctp_audit_data[i][1] == 0x01)) { - cnt = 0; - SCTP_PRINTF("\n"); - } else if (sctp_audit_data[i][0] == 0xf0) { - cnt = 0; - SCTP_PRINTF("\n"); - } else if ((sctp_audit_data[i][0] == 0xc0) && - (sctp_audit_data[i][1] == 0x01)) { - SCTP_PRINTF("\n"); - cnt = 0; - } - SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0], - (uint32_t) sctp_audit_data[i][1]); - cnt++; - if ((cnt % 14) == 0) - SCTP_PRINTF("\n"); - } - for (i = 0; i < sctp_audit_indx; i++) { - if ((sctp_audit_data[i][0] == 0xe0) && - (sctp_audit_data[i][1] == 0x01)) { - cnt = 0; - SCTP_PRINTF("\n"); - } else if (sctp_audit_data[i][0] == 0xf0) { - cnt = 0; - SCTP_PRINTF("\n"); - } else if ((sctp_audit_data[i][0] == 0xc0) && - (sctp_audit_data[i][1] == 0x01)) { - SCTP_PRINTF("\n"); - cnt = 0; - } - SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0], - (uint32_t) sctp_audit_data[i][1]); - cnt++; - if ((cnt % 14) == 0) - SCTP_PRINTF("\n"); - } - SCTP_PRINTF("\n"); -} - -void -sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - int resend_cnt, tot_out, rep, tot_book_cnt; - struct sctp_nets *lnet; - struct sctp_tmit_chunk *chk; - - sctp_audit_data[sctp_audit_indx][0] = 0xAA; - sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - if (inp == NULL) { - sctp_audit_data[sctp_audit_indx][0] = 0xAF; - sctp_audit_data[sctp_audit_indx][1] = 0x01; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - return; - } - if (stcb == NULL) { - sctp_audit_data[sctp_audit_indx][0] = 0xAF; - sctp_audit_data[sctp_audit_indx][1] = 0x02; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - return; - } - sctp_audit_data[sctp_audit_indx][0] = 0xA1; - sctp_audit_data[sctp_audit_indx][1] = - (0x000000ff & stcb->asoc.sent_queue_retran_cnt); - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - rep = 0; - tot_book_cnt = 0; - resend_cnt = tot_out = 0; - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->sent == SCTP_DATAGRAM_RESEND) { - resend_cnt++; - } else if (chk->sent < SCTP_DATAGRAM_RESEND) { - tot_out += chk->book_size; - tot_book_cnt++; - } - } - if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) { - sctp_audit_data[sctp_audit_indx][0] = 0xAF; - sctp_audit_data[sctp_audit_indx][1] = 0xA1; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n", - resend_cnt, stcb->asoc.sent_queue_retran_cnt); - rep = 1; - stcb->asoc.sent_queue_retran_cnt = resend_cnt; - sctp_audit_data[sctp_audit_indx][0] = 0xA2; - sctp_audit_data[sctp_audit_indx][1] = - (0x000000ff & stcb->asoc.sent_queue_retran_cnt); - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - } - if (tot_out != stcb->asoc.total_flight) { - sctp_audit_data[sctp_audit_indx][0] = 0xAF; - sctp_audit_data[sctp_audit_indx][1] = 0xA2; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - rep = 1; - SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out, - (int)stcb->asoc.total_flight); - stcb->asoc.total_flight = tot_out; - } - if (tot_book_cnt != stcb->asoc.total_flight_count) { - sctp_audit_data[sctp_audit_indx][0] = 0xAF; - sctp_audit_data[sctp_audit_indx][1] = 0xA5; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - rep = 1; - SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt); - - stcb->asoc.total_flight_count = tot_book_cnt; - } - tot_out = 0; - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - tot_out += lnet->flight_size; - } - if (tot_out != stcb->asoc.total_flight) { - sctp_audit_data[sctp_audit_indx][0] = 0xAF; - sctp_audit_data[sctp_audit_indx][1] = 0xA3; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } - rep = 1; - SCTP_PRINTF("real flight:%d net total was %d\n", - stcb->asoc.total_flight, tot_out); - /* now corrective action */ - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - tot_out = 0; - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if ((chk->whoTo == lnet) && - (chk->sent < SCTP_DATAGRAM_RESEND)) { - tot_out += chk->book_size; - } - } - if (lnet->flight_size != tot_out) { - SCTP_PRINTF("net:%p flight was %d corrected to %d\n", - (void *)lnet, lnet->flight_size, - tot_out); - lnet->flight_size = tot_out; - } - } - } - if (rep) { - sctp_print_audit_report(); - } -} - -void -sctp_audit_log(uint8_t ev, uint8_t fd) -{ - - sctp_audit_data[sctp_audit_indx][0] = ev; - sctp_audit_data[sctp_audit_indx][1] = fd; - sctp_audit_indx++; - if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { - sctp_audit_indx = 0; - } -} - -#endif - -/* - * The conversion from time to ticks and vice versa is done by rounding - * upwards. This way we can test in the code the time to be positive and - * know that this corresponds to a positive number of ticks. - */ - -uint32_t -sctp_msecs_to_ticks(uint32_t msecs) -{ - uint64_t temp; - uint32_t ticks; - - if (hz == 1000) { - ticks = msecs; - } else { - temp = (((uint64_t)msecs * hz) + 999) / 1000; - if (temp > UINT32_MAX) { - ticks = UINT32_MAX; - } else { - ticks = (uint32_t)temp; - } - } - return (ticks); -} - -uint32_t -sctp_ticks_to_msecs(uint32_t ticks) -{ - uint64_t temp; - uint32_t msecs; - - if (hz == 1000) { - msecs = ticks; - } else { - temp = (((uint64_t)ticks * 1000) + (hz - 1)) / hz; - if (temp > UINT32_MAX) { - msecs = UINT32_MAX; - } else { - msecs = (uint32_t)temp; - } - } - return (msecs); -} - -uint32_t -sctp_secs_to_ticks(uint32_t secs) -{ - uint64_t temp; - uint32_t ticks; - - temp = (uint64_t)secs * hz; - if (temp > UINT32_MAX) { - ticks = UINT32_MAX; - } else { - ticks = (uint32_t)temp; - } - return (ticks); -} - -uint32_t -sctp_ticks_to_secs(uint32_t ticks) -{ - uint64_t temp; - uint32_t secs; - - temp = ((uint64_t)ticks + (hz - 1)) / hz; - if (temp > UINT32_MAX) { - secs = UINT32_MAX; - } else { - secs = (uint32_t)temp; - } - return (secs); -} - -/* - * sctp_stop_timers_for_shutdown() should be called - * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT - * state to make sure that all timers are stopped. - */ -void -sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) -{ - struct sctp_inpcb *inp; - struct sctp_nets *net; - - inp = stcb->sctp_ep; - - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_12); - sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_13); - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_14); - sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_15); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_16); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_17); - } -} - -void -sctp_stop_association_timers(struct sctp_tcb *stcb, bool stop_assoc_kill_timer) -{ - struct sctp_inpcb *inp; - struct sctp_nets *net; - - inp = stcb->sctp_ep; - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_18); - sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_19); - if (stop_assoc_kill_timer) { - sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_20); - } - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_21); - sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_22); - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNGUARD, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_23); - /* Mobility adaptation */ - sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_24); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_25); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_26); - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_27); - sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_28); - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_29); - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_30); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTPUTIL + SCTP_LOC_31); - } -} - -/* - * A list of sizes based on typical mtu's, used only if next hop size not - * returned. These values MUST be multiples of 4 and MUST be ordered. - */ -static uint32_t sctp_mtu_sizes[] = { - 68, - 296, - 508, - 512, - 544, - 576, - 1004, - 1492, - 1500, - 1536, - 2000, - 2048, - 4352, - 4464, - 8168, - 17912, - 32000, - 65532 -}; - -/* - * Return the largest MTU in sctp_mtu_sizes smaller than val. - * If val is smaller than the minimum, just return the largest - * multiple of 4 smaller or equal to val. - * Ensure that the result is a multiple of 4. - */ -uint32_t -sctp_get_prev_mtu(uint32_t val) -{ - uint32_t i; - - val &= 0xfffffffc; - if (val <= sctp_mtu_sizes[0]) { - return (val); - } - for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { - if (val <= sctp_mtu_sizes[i]) { - break; - } - } - KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0, - ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1)); - return (sctp_mtu_sizes[i - 1]); -} - -/* - * Return the smallest MTU in sctp_mtu_sizes larger than val. - * If val is larger than the maximum, just return the largest multiple of 4 smaller - * or equal to val. - * Ensure that the result is a multiple of 4. - */ -uint32_t -sctp_get_next_mtu(uint32_t val) -{ - /* select another MTU that is just bigger than this one */ - uint32_t i; - - val &= 0xfffffffc; - for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { - if (val < sctp_mtu_sizes[i]) { - KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0, - ("sctp_mtu_sizes[%u] not a multiple of 4", i)); - return (sctp_mtu_sizes[i]); - } - } - return (val); -} - -void -sctp_fill_random_store(struct sctp_pcb *m) -{ - /* - * Here we use the MD5/SHA-1 to hash with our good randomNumbers and - * our counter. The result becomes our good random numbers and we - * then setup to give these out. Note that we do no locking to - * protect this. This is ok, since if competing folks call this we - * will get more gobbled gook in the random store which is what we - * want. There is a danger that two guys will use the same random - * numbers, but thats ok too since that is random as well :-> - */ - m->store_at = 0; -#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) - for (int i = 0; i < (int) (sizeof(m->random_store) / sizeof(m->random_store[0])); i++) { - m->random_store[i] = (uint8_t) rand(); - } -#else - (void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers, - sizeof(m->random_numbers), (uint8_t *)&m->random_counter, - sizeof(m->random_counter), (uint8_t *)m->random_store); -#endif - m->random_counter++; -} - -uint32_t -sctp_select_initial_TSN(struct sctp_pcb *inp) -{ - /* - * A true implementation should use random selection process to get - * the initial stream sequence number, using RFC1750 as a good - * guideline - */ - uint32_t x, *xp; - uint8_t *p; - int store_at, new_store; - - if (inp->initial_sequence_debug != 0) { - uint32_t ret; - - ret = inp->initial_sequence_debug; - inp->initial_sequence_debug++; - return (ret); - } - retry: - store_at = inp->store_at; - new_store = store_at + sizeof(uint32_t); - if (new_store >= (SCTP_SIGNATURE_SIZE-3)) { - new_store = 0; - } - if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) { - goto retry; - } - if (new_store == 0) { - /* Refill the random store */ - sctp_fill_random_store(inp); - } - p = &inp->random_store[store_at]; - xp = (uint32_t *)p; - x = *xp; - return (x); -} - -uint32_t -sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check) -{ - uint32_t x; - struct timeval now; - - if (check) { - (void)SCTP_GETTIME_TIMEVAL(&now); - } - for (;;) { - x = sctp_select_initial_TSN(&inp->sctp_ep); - if (x == 0) { - /* we never use 0 */ - continue; - } - if (!check || sctp_is_vtag_good(x, lport, rport, &now)) { - break; - } - } - return (x); -} - -int32_t -sctp_map_assoc_state(int kernel_state) -{ - int32_t user_state; - - if (kernel_state & SCTP_STATE_WAS_ABORTED) { - user_state = SCTP_CLOSED; - } else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) { - user_state = SCTP_SHUTDOWN_PENDING; - } else { - switch (kernel_state & SCTP_STATE_MASK) { - case SCTP_STATE_EMPTY: - user_state = SCTP_CLOSED; - break; - case SCTP_STATE_INUSE: - user_state = SCTP_CLOSED; - break; - case SCTP_STATE_COOKIE_WAIT: - user_state = SCTP_COOKIE_WAIT; - break; - case SCTP_STATE_COOKIE_ECHOED: - user_state = SCTP_COOKIE_ECHOED; - break; - case SCTP_STATE_OPEN: - user_state = SCTP_ESTABLISHED; - break; - case SCTP_STATE_SHUTDOWN_SENT: - user_state = SCTP_SHUTDOWN_SENT; - break; - case SCTP_STATE_SHUTDOWN_RECEIVED: - user_state = SCTP_SHUTDOWN_RECEIVED; - break; - case SCTP_STATE_SHUTDOWN_ACK_SENT: - user_state = SCTP_SHUTDOWN_ACK_SENT; - break; - default: - user_state = SCTP_CLOSED; - break; - } - } - return (user_state); -} - -int -sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - uint32_t override_tag, uint32_t initial_tsn, uint32_t vrf_id, - uint16_t o_strms) -{ - struct sctp_association *asoc; - /* - * Anything set to zero is taken care of by the allocation routine's - * bzero - */ - - /* - * Up front select what scoping to apply on addresses I tell my peer - * Not sure what to do with these right now, we will need to come up - * with a way to set them. We may need to pass them through from the - * caller in the sctp_aloc_assoc() function. - */ - int i; -#if defined(SCTP_DETAILED_STR_STATS) - int j; -#endif - - asoc = &stcb->asoc; - /* init all variables to a known value. */ - SCTP_SET_STATE(stcb, SCTP_STATE_INUSE); - asoc->max_burst = inp->sctp_ep.max_burst; - asoc->fr_max_burst = inp->sctp_ep.fr_max_burst; - asoc->heart_beat_delay = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); - asoc->cookie_life = inp->sctp_ep.def_cookie_life; - asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off; - asoc->ecn_supported = inp->ecn_supported; - asoc->prsctp_supported = inp->prsctp_supported; - asoc->auth_supported = inp->auth_supported; - asoc->asconf_supported = inp->asconf_supported; - asoc->reconfig_supported = inp->reconfig_supported; - asoc->nrsack_supported = inp->nrsack_supported; - asoc->pktdrop_supported = inp->pktdrop_supported; - asoc->idata_supported = inp->idata_supported; - asoc->rcv_edmid = inp->rcv_edmid; - asoc->snd_edmid = SCTP_EDMID_NONE; - asoc->sctp_cmt_pf = (uint8_t)0; - asoc->sctp_frag_point = inp->sctp_frag_point; - asoc->sctp_features = inp->sctp_features; - asoc->default_dscp = inp->sctp_ep.default_dscp; - asoc->max_cwnd = inp->max_cwnd; -#ifdef INET6 - if (inp->sctp_ep.default_flowlabel) { - asoc->default_flowlabel = inp->sctp_ep.default_flowlabel; - } else { - if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) { - asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep); - asoc->default_flowlabel &= 0x000fffff; - asoc->default_flowlabel |= 0x80000000; - } else { - asoc->default_flowlabel = 0; - } - } -#endif - asoc->sb_send_resv = 0; - if (override_tag) { - asoc->my_vtag = override_tag; - } else { - asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1); - } - /* Get the nonce tags */ - asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0); - asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0); - asoc->vrf_id = vrf_id; - -#ifdef SCTP_ASOCLOG_OF_TSNS - asoc->tsn_in_at = 0; - asoc->tsn_out_at = 0; - asoc->tsn_in_wrapped = 0; - asoc->tsn_out_wrapped = 0; - asoc->cumack_log_at = 0; - asoc->cumack_log_atsnt = 0; -#endif -#ifdef SCTP_FS_SPEC_LOG - asoc->fs_index = 0; -#endif - asoc->refcnt = 0; - asoc->assoc_up_sent = 0; - if (override_tag) { - asoc->init_seq_number = initial_tsn; - } else { - asoc->init_seq_number = sctp_select_initial_TSN(&inp->sctp_ep); - } - asoc->asconf_seq_out = asoc->init_seq_number; - asoc->str_reset_seq_out = asoc->init_seq_number; - asoc->sending_seq = asoc->init_seq_number; - asoc->asconf_seq_out_acked = asoc->init_seq_number - 1; - /* we are optimistic here */ - asoc->peer_supports_nat = 0; - asoc->sent_queue_retran_cnt = 0; - - /* for CMT */ - asoc->last_net_cmt_send_started = NULL; - - asoc->last_acked_seq = asoc->init_seq_number - 1; - asoc->advanced_peer_ack_point = asoc->init_seq_number - 1; - asoc->asconf_seq_in = asoc->init_seq_number - 1; - - /* here we are different, we hold the next one we expect */ - asoc->str_reset_seq_in = asoc->init_seq_number; - - asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max; - asoc->initial_rto = inp->sctp_ep.initial_rto; - - asoc->default_mtu = inp->sctp_ep.default_mtu; - asoc->max_init_times = inp->sctp_ep.max_init_times; - asoc->max_send_times = inp->sctp_ep.max_send_times; - asoc->def_net_failure = inp->sctp_ep.def_net_failure; - asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold; - asoc->free_chunk_cnt = 0; - - asoc->iam_blocking = 0; - asoc->context = inp->sctp_context; - asoc->local_strreset_support = inp->local_strreset_support; - asoc->def_send = inp->def_send; - asoc->delayed_ack = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); - asoc->sack_freq = inp->sctp_ep.sctp_sack_freq; - asoc->pr_sctp_cnt = 0; - asoc->total_output_queue_size = 0; - - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - asoc->scope.ipv6_addr_legal = 1; - if (SCTP_IPV6_V6ONLY(inp) == 0) { - asoc->scope.ipv4_addr_legal = 1; - } else { - asoc->scope.ipv4_addr_legal = 0; - } -#if defined(__Userspace__) - asoc->scope.conn_addr_legal = 0; -#endif - } else { - asoc->scope.ipv6_addr_legal = 0; -#if defined(__Userspace__) - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { - asoc->scope.conn_addr_legal = 1; - asoc->scope.ipv4_addr_legal = 0; - } else { - asoc->scope.conn_addr_legal = 0; - asoc->scope.ipv4_addr_legal = 1; - } -#else - asoc->scope.ipv4_addr_legal = 1; -#endif - } - - asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND); - asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket); - - asoc->smallest_mtu = 0; - asoc->minrto = inp->sctp_ep.sctp_minrto; - asoc->maxrto = inp->sctp_ep.sctp_maxrto; - - asoc->stream_locked_on = 0; - asoc->ecn_echo_cnt_onq = 0; - asoc->stream_locked = 0; - - asoc->send_sack = 1; - - LIST_INIT(&asoc->sctp_restricted_addrs); - - TAILQ_INIT(&asoc->nets); - TAILQ_INIT(&asoc->pending_reply_queue); - TAILQ_INIT(&asoc->asconf_ack_sent); - /* Setup to fill the hb random cache at first HB */ - asoc->hb_random_idx = 4; - - asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time; - - stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module; - stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module]; - - stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module; - stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module]; - - /* - * Now the stream parameters, here we allocate space for all streams - * that we request by default. - */ - asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams = - o_strms; - SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *, - asoc->streamoutcnt * sizeof(struct sctp_stream_out), - SCTP_M_STRMO); - if (asoc->strmout == NULL) { - /* big trouble no memory */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); - return (ENOMEM); - } - SCTP_TCB_LOCK(stcb); - for (i = 0; i < asoc->streamoutcnt; i++) { - /* - * inbound side must be set to 0xffff, also NOTE when we get - * the INIT-ACK back (for INIT sender) we MUST reduce the - * count (streamoutcnt) but first check if we sent to any of - * the upper streams that were dropped (if some were). Those - * that were dropped must be notified to the upper layer as - * failed to send. - */ - TAILQ_INIT(&asoc->strmout[i].outqueue); - asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL); - asoc->strmout[i].chunks_on_queues = 0; -#if defined(SCTP_DETAILED_STR_STATS) - for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { - asoc->strmout[i].abandoned_sent[j] = 0; - asoc->strmout[i].abandoned_unsent[j] = 0; - } -#else - asoc->strmout[i].abandoned_sent[0] = 0; - asoc->strmout[i].abandoned_unsent[0] = 0; -#endif - asoc->strmout[i].next_mid_ordered = 0; - asoc->strmout[i].next_mid_unordered = 0; - asoc->strmout[i].sid = i; - asoc->strmout[i].last_msg_incomplete = 0; - asoc->strmout[i].state = SCTP_STREAM_OPENING; - } - asoc->ss_functions.sctp_ss_init(stcb, asoc); - SCTP_TCB_UNLOCK(stcb); - - /* Now the mapping array */ - asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; - SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size, - SCTP_M_MAP); - if (asoc->mapping_array == NULL) { - SCTP_FREE(asoc->strmout, SCTP_M_STRMO); - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); - return (ENOMEM); - } - memset(asoc->mapping_array, 0, asoc->mapping_array_size); - SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size, - SCTP_M_MAP); - if (asoc->nr_mapping_array == NULL) { - SCTP_FREE(asoc->strmout, SCTP_M_STRMO); - SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); - return (ENOMEM); - } - memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); - - /* Now the init of the other outqueues */ - TAILQ_INIT(&asoc->free_chunks); - TAILQ_INIT(&asoc->control_send_queue); - TAILQ_INIT(&asoc->asconf_send_queue); - TAILQ_INIT(&asoc->send_queue); - TAILQ_INIT(&asoc->sent_queue); - TAILQ_INIT(&asoc->resetHead); - asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome; - TAILQ_INIT(&asoc->asconf_queue); - /* authentication fields */ - asoc->authinfo.random = NULL; - asoc->authinfo.active_keyid = 0; - asoc->authinfo.assoc_key = NULL; - asoc->authinfo.assoc_keyid = 0; - asoc->authinfo.recv_key = NULL; - asoc->authinfo.recv_keyid = 0; - LIST_INIT(&asoc->shared_keys); - asoc->marked_retrans = 0; - asoc->port = inp->sctp_ep.port; - asoc->timoinit = 0; - asoc->timodata = 0; - asoc->timosack = 0; - asoc->timoshutdown = 0; - asoc->timoheartbeat = 0; - asoc->timocookie = 0; - asoc->timoshutdownack = 0; - (void)SCTP_GETTIME_TIMEVAL(&asoc->start_time); - asoc->discontinuity_time = asoc->start_time; - for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) { - asoc->abandoned_unsent[i] = 0; - asoc->abandoned_sent[i] = 0; - } - /* sa_ignore MEMLEAK {memory is put in the assoc mapping array and freed later when - * the association is freed. - */ - return (0); -} - -void -sctp_print_mapping_array(struct sctp_association *asoc) -{ - unsigned int i, limit; - - SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n", - asoc->mapping_array_size, - asoc->mapping_array_base_tsn, - asoc->cumulative_tsn, - asoc->highest_tsn_inside_map, - asoc->highest_tsn_inside_nr_map); - for (limit = asoc->mapping_array_size; limit > 1; limit--) { - if (asoc->mapping_array[limit - 1] != 0) { - break; - } - } - SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); - for (i = 0; i < limit; i++) { - SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); - } - if (limit % 16) - SCTP_PRINTF("\n"); - for (limit = asoc->mapping_array_size; limit > 1; limit--) { - if (asoc->nr_mapping_array[limit - 1]) { - break; - } - } - SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); - for (i = 0; i < limit; i++) { - SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ': '\n'); - } - if (limit % 16) - SCTP_PRINTF("\n"); -} - -int -sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed) -{ - /* mapping array needs to grow */ - uint8_t *new_array1, *new_array2; - uint32_t new_size; - - new_size = asoc->mapping_array_size + ((needed+7)/8 + SCTP_MAPPING_ARRAY_INCR); - SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP); - SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP); - if ((new_array1 == NULL) || (new_array2 == NULL)) { - /* can't get more, forget it */ - SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size); - if (new_array1) { - SCTP_FREE(new_array1, SCTP_M_MAP); - } - if (new_array2) { - SCTP_FREE(new_array2, SCTP_M_MAP); - } - return (-1); - } - memset(new_array1, 0, new_size); - memset(new_array2, 0, new_size); - memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size); - memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size); - SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); - SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); - asoc->mapping_array = new_array1; - asoc->nr_mapping_array = new_array2; - asoc->mapping_array_size = new_size; - return (0); -} - -static void -sctp_iterator_work(struct sctp_iterator *it) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct sctp_inpcb *tinp; - int iteration_count = 0; - int inp_skip = 0; - int first_in = 1; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - SCTP_INP_INFO_RLOCK(); - SCTP_ITERATOR_LOCK(); - sctp_it_ctl.cur_it = it; - if (it->inp) { - SCTP_INP_RLOCK(it->inp); - SCTP_INP_DECR_REF(it->inp); - } - if (it->inp == NULL) { - /* iterator is complete */ -done_with_iterator: - sctp_it_ctl.cur_it = NULL; - SCTP_ITERATOR_UNLOCK(); - SCTP_INP_INFO_RUNLOCK(); - if (it->function_atend != NULL) { - (*it->function_atend) (it->pointer, it->val); - } - SCTP_FREE(it, SCTP_M_ITER); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - return; - } -select_a_new_ep: - if (first_in) { - first_in = 0; - } else { - SCTP_INP_RLOCK(it->inp); - } - while (((it->pcb_flags) && - ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || - ((it->pcb_features) && - ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { - /* endpoint flags or features don't match, so keep looking */ - if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { - SCTP_INP_RUNLOCK(it->inp); - goto done_with_iterator; - } - tinp = it->inp; - it->inp = LIST_NEXT(it->inp, sctp_list); - it->stcb = NULL; - SCTP_INP_RUNLOCK(tinp); - if (it->inp == NULL) { - goto done_with_iterator; - } - SCTP_INP_RLOCK(it->inp); - } - /* now go through each assoc which is in the desired state */ - if (it->done_current_ep == 0) { - if (it->function_inp != NULL) - inp_skip = (*it->function_inp)(it->inp, it->pointer, it->val); - it->done_current_ep = 1; - } - if (it->stcb == NULL) { - /* run the per instance function */ - it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); - } - if ((inp_skip) || it->stcb == NULL) { - if (it->function_inp_end != NULL) { - inp_skip = (*it->function_inp_end)(it->inp, - it->pointer, - it->val); - } - SCTP_INP_RUNLOCK(it->inp); - goto no_stcb; - } - while (it->stcb != NULL) { - SCTP_TCB_LOCK(it->stcb); - if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { - /* not in the right state... keep looking */ - SCTP_TCB_UNLOCK(it->stcb); - goto next_assoc; - } - /* see if we have limited out the iterator loop */ - iteration_count++; - if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { - /* Pause to let others grab the lock */ - atomic_add_int(&it->stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(it->stcb); - SCTP_INP_INCR_REF(it->inp); - SCTP_INP_RUNLOCK(it->inp); - SCTP_ITERATOR_UNLOCK(); - SCTP_INP_INFO_RUNLOCK(); - SCTP_INP_INFO_RLOCK(); - SCTP_ITERATOR_LOCK(); - if (sctp_it_ctl.iterator_flags) { - /* We won't be staying here */ - SCTP_INP_DECR_REF(it->inp); - atomic_subtract_int(&it->stcb->asoc.refcnt, 1); -#if !(defined(__FreeBSD__) && !defined(__Userspace__)) - if (sctp_it_ctl.iterator_flags & - SCTP_ITERATOR_MUST_EXIT) { - goto done_with_iterator; - } -#endif - if (sctp_it_ctl.iterator_flags & - SCTP_ITERATOR_STOP_CUR_IT) { - sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT; - goto done_with_iterator; - } - if (sctp_it_ctl.iterator_flags & - SCTP_ITERATOR_STOP_CUR_INP) { - sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP; - goto no_stcb; - } - /* If we reach here huh? */ - SCTP_PRINTF("Unknown it ctl flag %x\n", - sctp_it_ctl.iterator_flags); - sctp_it_ctl.iterator_flags = 0; - } - SCTP_INP_RLOCK(it->inp); - SCTP_INP_DECR_REF(it->inp); - SCTP_TCB_LOCK(it->stcb); - atomic_subtract_int(&it->stcb->asoc.refcnt, 1); - iteration_count = 0; - } - KASSERT(it->inp == it->stcb->sctp_ep, - ("%s: stcb %p does not belong to inp %p, but inp %p", - __func__, it->stcb, it->inp, it->stcb->sctp_ep)); - SCTP_INP_RLOCK_ASSERT(it->inp); - SCTP_TCB_LOCK_ASSERT(it->stcb); - - /* run function on this one */ - (*it->function_assoc)(it->inp, it->stcb, it->pointer, it->val); - SCTP_INP_RLOCK_ASSERT(it->inp); - SCTP_TCB_LOCK_ASSERT(it->stcb); - - /* - * we lie here, it really needs to have its own type but - * first I must verify that this won't effect things :-0 - */ - if (it->no_chunk_output == 0) { - sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); - SCTP_INP_RLOCK_ASSERT(it->inp); - SCTP_TCB_LOCK_ASSERT(it->stcb); - } - - SCTP_TCB_UNLOCK(it->stcb); - next_assoc: - it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); - if (it->stcb == NULL) { - /* Run last function */ - if (it->function_inp_end != NULL) { - inp_skip = (*it->function_inp_end)(it->inp, - it->pointer, - it->val); - } - } - } - SCTP_INP_RUNLOCK(it->inp); - no_stcb: - /* done with all assocs on this endpoint, move on to next endpoint */ - it->done_current_ep = 0; - if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { - it->inp = NULL; - } else { - it->inp = LIST_NEXT(it->inp, sctp_list); - } - it->stcb = NULL; - if (it->inp == NULL) { - goto done_with_iterator; - } - goto select_a_new_ep; -} - -void -sctp_iterator_worker(void) -{ - struct sctp_iterator *it; - - /* This function is called with the WQ lock in place */ - sctp_it_ctl.iterator_running = 1; - while ((it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead)) != NULL) { - /* now lets work on this one */ - TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); - SCTP_IPI_ITERATOR_WQ_UNLOCK(); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_SET(it->vn); -#endif - sctp_iterator_work(it); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_RESTORE(); -#endif - SCTP_IPI_ITERATOR_WQ_LOCK(); -#if !defined(__FreeBSD__) && !defined(__Userspace__) - if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) { - break; - } -#endif - /*sa_ignore FREED_MEMORY*/ - } - sctp_it_ctl.iterator_running = 0; - return; -} - -static void -sctp_handle_addr_wq(void) -{ - /* deal with the ADDR wq from the rtsock calls */ - struct sctp_laddr *wi, *nwi; - struct sctp_asconf_iterator *asc; - - SCTP_MALLOC(asc, struct sctp_asconf_iterator *, - sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT); - if (asc == NULL) { - /* Try later, no memory */ - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, - (struct sctp_inpcb *)NULL, - (struct sctp_tcb *)NULL, - (struct sctp_nets *)NULL); - return; - } - LIST_INIT(&asc->list_of_work); - asc->cnt = 0; - - LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { - LIST_REMOVE(wi, sctp_nxt_addr); - LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); - asc->cnt++; - } - - if (asc->cnt == 0) { - SCTP_FREE(asc, SCTP_M_ASC_IT); - } else { - int ret; - - ret = sctp_initiate_iterator(sctp_asconf_iterator_ep, - sctp_asconf_iterator_stcb, - NULL, /* No ep end for boundall */ - SCTP_PCB_FLAGS_BOUNDALL, - SCTP_PCB_ANY_FEATURES, - SCTP_ASOC_ANY_STATE, - (void *)asc, 0, - sctp_asconf_iterator_end, NULL, 0); - if (ret) { - SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n"); - /* Freeing if we are stopping or put back on the addr_wq. */ - if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { - sctp_asconf_iterator_end(asc, 0); - } else { - LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) { - LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - } - SCTP_FREE(asc, SCTP_M_ASC_IT); - } - } - } -} - -/*- - * The following table shows which pointers for the inp, stcb, or net are - * stored for each timer after it was started. - * - *|Name |Timer |inp |stcb|net | - *|-----------------------------|-----------------------------|----|----|----| - *|SCTP_TIMER_TYPE_SEND |net->rxt_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_INIT |net->rxt_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_RECV |stcb->asoc.dack_timer |Yes |Yes |No | - *|SCTP_TIMER_TYPE_SHUTDOWN |net->rxt_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_HEARTBEAT |net->hb_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_COOKIE |net->rxt_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_NEWCOOKIE |inp->sctp_ep.signature_change|Yes |No |No | - *|SCTP_TIMER_TYPE_PATHMTURAISE |net->pmtu_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_SHUTDOWNACK |net->rxt_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_ASCONF |stcb->asoc.asconf_timer |Yes |Yes |Yes | - *|SCTP_TIMER_TYPE_SHUTDOWNGUARD|stcb->asoc.shut_guard_timer |Yes |Yes |No | - *|SCTP_TIMER_TYPE_AUTOCLOSE |stcb->asoc.autoclose_timer |Yes |Yes |No | - *|SCTP_TIMER_TYPE_STRRESET |stcb->asoc.strreset_timer |Yes |Yes |No | - *|SCTP_TIMER_TYPE_INPKILL |inp->sctp_ep.signature_change|Yes |No |No | - *|SCTP_TIMER_TYPE_ASOCKILL |stcb->asoc.strreset_timer |Yes |Yes |No | - *|SCTP_TIMER_TYPE_ADDR_WQ |SCTP_BASE_INFO(addr_wq_timer)|No |No |No | - *|SCTP_TIMER_TYPE_PRIM_DELETED |stcb->asoc.delete_prim_timer |Yes |Yes |No | - */ - -void -sctp_timeout_handler(void *t) -{ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - struct timeval tv; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sctp_timer *tmr; - struct mbuf *op_err; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif -#if defined(__Userspace__) - struct socket *upcall_socket = NULL; -#endif - int type; - int i, secret; - bool did_output, released_asoc_reference; - - /* - * If inp, stcb or net are not NULL, then references to these were - * added when the timer was started, and must be released before this - * function returns. - */ - tmr = (struct sctp_timer *)t; - inp = (struct sctp_inpcb *)tmr->ep; - stcb = (struct sctp_tcb *)tmr->tcb; - net = (struct sctp_nets *)tmr->net; -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_SET((struct vnet *)tmr->vnet); - NET_EPOCH_ENTER(et); -#endif - released_asoc_reference = false; - -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xF0, (uint8_t) tmr->type); - sctp_auditing(3, inp, stcb, net); -#endif - - /* sanity checks... */ - KASSERT(tmr->self == NULL || tmr->self == tmr, - ("sctp_timeout_handler: tmr->self corrupted")); - KASSERT(SCTP_IS_TIMER_TYPE_VALID(tmr->type), - ("sctp_timeout_handler: invalid timer type %d", tmr->type)); - type = tmr->type; - KASSERT(stcb == NULL || stcb->sctp_ep == inp, - ("sctp_timeout_handler of type %d: inp = %p, stcb->sctp_ep %p", - type, stcb, stcb->sctp_ep)); - tmr->stopped_from = 0xa001; - if ((stcb != NULL) && (stcb->asoc.state == SCTP_STATE_EMPTY)) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d handler exiting due to CLOSED association.\n", - type); - goto out_decr; - } - tmr->stopped_from = 0xa002; - SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d goes off.\n", type); - if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d handler exiting due to not being active.\n", - type); - goto out_decr; - } - - tmr->stopped_from = 0xa003; - if (stcb) { - SCTP_TCB_LOCK(stcb); - /* - * Release reference so that association can be freed if - * necessary below. - * This is safe now that we have acquired the lock. - */ - atomic_subtract_int(&stcb->asoc.refcnt, 1); - released_asoc_reference = true; - if ((type != SCTP_TIMER_TYPE_ASOCKILL) && - ((stcb->asoc.state == SCTP_STATE_EMPTY) || - (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d handler exiting due to CLOSED association.\n", - type); - goto out; - } - } else if (inp != NULL) { - SCTP_INP_WLOCK(inp); - } else { - SCTP_WQ_ADDR_LOCK(); - } - - /* Record in stopped_from which timeout occurred. */ - tmr->stopped_from = type; - /* mark as being serviced now */ - if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { - /* - * Callout has been rescheduled. - */ - goto out; - } - if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { - /* - * Not active, so no action. - */ - goto out; - } - SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); - -#if defined(__Userspace__) - if ((stcb != NULL) && - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - upcall_socket = stcb->sctp_socket; - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - } -#endif - /* call the handler for the appropriate timer type */ - switch (type) { - case SCTP_TIMER_TYPE_SEND: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timodata); - stcb->asoc.timodata++; - stcb->asoc.num_send_timers_up--; - if (stcb->asoc.num_send_timers_up < 0) { - stcb->asoc.num_send_timers_up = 0; - } - SCTP_TCB_LOCK_ASSERT(stcb); - if (sctp_t3rxt_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - - goto out_decr; - } - SCTP_TCB_LOCK_ASSERT(stcb); -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, net); -#endif - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); - did_output = true; - if ((stcb->asoc.num_send_timers_up == 0) && - (stcb->asoc.sent_queue_cnt > 0)) { - struct sctp_tmit_chunk *chk; - - /* - * Safeguard. If there on some on the sent queue - * somewhere but no timers running something is - * wrong... so we start a timer on the first chunk - * on the send queue on whatever net it is sent to. - */ - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if (chk->whoTo != NULL) { - break; - } - } - if (chk != NULL) { - sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo); - } - } - break; - case SCTP_TIMER_TYPE_INIT: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoinit); - stcb->asoc.timoinit++; - if (sctp_t1init_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } - did_output = false; - break; - case SCTP_TIMER_TYPE_RECV: - KASSERT(inp != NULL && stcb != NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timosack); - stcb->asoc.timosack++; - sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, NULL); -#endif - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_SHUTDOWN: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoshutdown); - stcb->asoc.timoshutdown++; - if (sctp_shutdown_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, net); -#endif - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_HEARTBEAT: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoheartbeat); - stcb->asoc.timoheartbeat++; - if (sctp_heartbeat_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, net); -#endif - if ((net->dest_state & SCTP_ADDR_NOHB) == 0) { - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - } else { - did_output = false; - } - break; - case SCTP_TIMER_TYPE_COOKIE: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timocookie); - stcb->asoc.timocookie++; - if (sctp_cookie_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, net); -#endif - /* - * We consider T3 and Cookie timer pretty much the same with - * respect to where from in chunk_output. - */ - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_NEWCOOKIE: - KASSERT(inp != NULL && stcb == NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timosecret); - (void)SCTP_GETTIME_TIMEVAL(&tv); - inp->sctp_ep.time_of_secret_change = (unsigned int)tv.tv_sec; - inp->sctp_ep.last_secret_number = - inp->sctp_ep.current_secret_number; - inp->sctp_ep.current_secret_number++; - if (inp->sctp_ep.current_secret_number >= - SCTP_HOW_MANY_SECRETS) { - inp->sctp_ep.current_secret_number = 0; - } - secret = (int)inp->sctp_ep.current_secret_number; - for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) { - inp->sctp_ep.secret_key[secret][i] = - sctp_select_initial_TSN(&inp->sctp_ep); - } - sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL); - did_output = false; - break; - case SCTP_TIMER_TYPE_PATHMTURAISE: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timopathmtu); - sctp_pathmtu_timer(inp, stcb, net); - did_output = false; - break; - case SCTP_TIMER_TYPE_SHUTDOWNACK: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - if (sctp_shutdownack_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } - SCTP_STAT_INCR(sctps_timoshutdownack); - stcb->asoc.timoshutdownack++; -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, net); -#endif - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_ASCONF: - KASSERT(inp != NULL && stcb != NULL && net != NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoasconf); - if (sctp_asconf_timer(inp, stcb, net)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } -#ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, net); -#endif - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_SHUTDOWNGUARD: - KASSERT(inp != NULL && stcb != NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoshutdownguard); - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Shutdown guard timer expired"); - sctp_abort_an_association(inp, stcb, op_err, true, SCTP_SO_NOT_LOCKED); - /* no need to unlock on tcb its gone */ - goto out_decr; - case SCTP_TIMER_TYPE_AUTOCLOSE: - KASSERT(inp != NULL && stcb != NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoautoclose); - sctp_autoclose_timer(inp, stcb); - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_STRRESET: - KASSERT(inp != NULL && stcb != NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timostrmrst); - if (sctp_strreset_timer(inp, stcb)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); - did_output = true; - break; - case SCTP_TIMER_TYPE_INPKILL: - KASSERT(inp != NULL && stcb == NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoinpkill); - /* - * special case, take away our increment since WE are the - * killer - */ - sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_3); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 1); -#endif - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_FROM_INPKILL_TIMER); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1); -#endif - inp = NULL; - goto out_decr; - case SCTP_TIMER_TYPE_ASOCKILL: - KASSERT(inp != NULL && stcb != NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timoassockill); - /* Can we free it yet? */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_1); -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_2); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - /* - * free asoc, always unlocks (or destroy's) so prevent - * duplicate unlock or unlock of a free mtx :-0 - */ - stcb = NULL; - goto out_decr; - case SCTP_TIMER_TYPE_ADDR_WQ: - KASSERT(inp == NULL && stcb == NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - sctp_handle_addr_wq(); - did_output = true; - break; - case SCTP_TIMER_TYPE_PRIM_DELETED: - KASSERT(inp != NULL && stcb != NULL && net == NULL, - ("timeout of type %d: inp = %p, stcb = %p, net = %p", - type, inp, stcb, net)); - SCTP_STAT_INCR(sctps_timodelprim); - sctp_delete_prim_timer(inp, stcb); - did_output = false; - break; - default: -#ifdef INVARIANTS - panic("Unknown timer type %d", type); -#else - goto out; -#endif - } -#ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xF1, (uint8_t) type); - if (inp != NULL) - sctp_auditing(5, inp, stcb, net); -#endif - if (did_output && (stcb != NULL)) { - /* - * Now we need to clean up the control chunk chain if an - * ECNE is on it. It must be marked as UNSENT again so next - * call will continue to send it until such time that we get - * a CWR, to remove it. It is, however, less likely that we - * will find a ecn echo on the chain though. - */ - sctp_fix_ecn_echo(&stcb->asoc); - } -out: - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } else if (inp != NULL) { - SCTP_INP_WUNLOCK(inp); - } else { - SCTP_WQ_ADDR_UNLOCK(); - } - -out_decr: -#if defined(__Userspace__) - if (upcall_socket != NULL) { - if ((upcall_socket->so_upcall != NULL) && - (upcall_socket->so_error != 0)) { - (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); - } - ACCEPT_LOCK(); - SOCK_LOCK(upcall_socket); - sorele(upcall_socket); - } -#endif - /* These reference counts were incremented in sctp_timer_start(). */ - if (inp != NULL) { - SCTP_INP_DECR_REF(inp); - } - if ((stcb != NULL) && !released_asoc_reference) { - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (net != NULL) { - sctp_free_remote_addr(net); - } - SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler finished.\n", type); -#if defined(__FreeBSD__) && !defined(__Userspace__) - CURVNET_RESTORE(); - NET_EPOCH_EXIT(et); -#endif -} - -/*- - * The following table shows which parameters must be provided - * when calling sctp_timer_start(). For parameters not being - * provided, NULL must be used. - * - * |Name |inp |stcb|net | - * |-----------------------------|----|----|----| - * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No | - * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No | - * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No | - * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No | - * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No | - * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No | - * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No | - * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No | - * - */ - -void -sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_timer *tmr; - uint32_t to_ticks; - uint32_t rndval, jitter; - - KASSERT(stcb == NULL || stcb->sctp_ep == inp, - ("sctp_timer_start of type %d: inp = %p, stcb->sctp_ep %p", - t_type, stcb, stcb->sctp_ep)); - tmr = NULL; - if (stcb != NULL) { - SCTP_TCB_LOCK_ASSERT(stcb); - } else if (inp != NULL) { - SCTP_INP_WLOCK_ASSERT(inp); - } else { - SCTP_WQ_ADDR_LOCK_ASSERT(); - } - if (stcb != NULL) { - /* Don't restart timer on association that's about to be killed. */ - if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) && - (t_type != SCTP_TIMER_TYPE_ASOCKILL)) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d not started: inp=%p, stcb=%p, net=%p (stcb deleted).\n", - t_type, inp, stcb, net); - return; - } - /* Don't restart timer on net that's been removed. */ - if (net != NULL && (net->dest_state & SCTP_ADDR_BEING_DELETED)) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d not started: inp=%p, stcb=%p, net=%p (net deleted).\n", - t_type, inp, stcb, net); - return; - } - } - switch (t_type) { - case SCTP_TIMER_TYPE_SEND: - /* Here we use the RTO timer. */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_INIT: - /* - * Here we use the INIT timer default usually about 1 - * second. - */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_RECV: - /* - * Here we use the Delayed-Ack timer value from the inp, - * usually about 200ms. - */ - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.dack_timer; - to_ticks = sctp_msecs_to_ticks(stcb->asoc.delayed_ack); - break; - case SCTP_TIMER_TYPE_SHUTDOWN: - /* Here we use the RTO of the destination. */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_HEARTBEAT: - /* - * The net is used here so that we can add in the RTO. Even - * though we use a different timer. We also add the HB timer - * PLUS a random jitter. - */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - if ((net->dest_state & SCTP_ADDR_NOHB) && - ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n", - t_type, inp, stcb, net); - return; - } - tmr = &net->hb_timer; - if (net->RTO == 0) { - to_ticks = stcb->asoc.initial_rto; - } else { - to_ticks = net->RTO; - } - rndval = sctp_select_initial_TSN(&inp->sctp_ep); - jitter = rndval % to_ticks; - if (to_ticks > 1) { - to_ticks >>= 1; - } - if (jitter < (UINT32_MAX - to_ticks)) { - to_ticks += jitter; - } else { - to_ticks = UINT32_MAX; - } - if (!((net->dest_state & SCTP_ADDR_UNCONFIRMED) && - (net->dest_state & SCTP_ADDR_REACHABLE)) && - ((net->dest_state & SCTP_ADDR_PF) == 0)) { - if (net->heart_beat_delay < (UINT32_MAX - to_ticks)) { - to_ticks += net->heart_beat_delay; - } else { - to_ticks = UINT32_MAX; - } - } - /* - * Now we must convert the to_ticks that are now in - * ms to ticks. - */ - to_ticks = sctp_msecs_to_ticks(to_ticks); - break; - case SCTP_TIMER_TYPE_COOKIE: - /* - * Here we can use the RTO timer from the network since one - * RTT was complete. If a retransmission happened then we will - * be using the RTO initial value. - */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_NEWCOOKIE: - /* - * Nothing needed but the endpoint here usually about 60 - * minutes. - */ - if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &inp->sctp_ep.signature_change; - to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE]; - break; - case SCTP_TIMER_TYPE_PATHMTURAISE: - /* - * Here we use the value found in the EP for PMTUD, usually - * about 10 minutes. - */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - if (net->dest_state & SCTP_ADDR_NO_PMTUD) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n", - t_type, inp, stcb, net); - return; - } - tmr = &net->pmtu_timer; - to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU]; - break; - case SCTP_TIMER_TYPE_SHUTDOWNACK: - /* Here we use the RTO of the destination. */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_ASCONF: - /* - * Here the timer comes from the stcb but its value is from - * the net's RTO. - */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.asconf_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_SHUTDOWNGUARD: - /* - * Here we use the endpoints shutdown guard timer usually - * about 3 minutes. - */ - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.shut_guard_timer; - if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) { - if (stcb->asoc.maxrto < UINT32_MAX / 5) { - to_ticks = sctp_msecs_to_ticks(5 * stcb->asoc.maxrto); - } else { - to_ticks = sctp_msecs_to_ticks(UINT32_MAX); - } - } else { - to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN]; - } - break; - case SCTP_TIMER_TYPE_AUTOCLOSE: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.autoclose_timer; - to_ticks = stcb->asoc.sctp_autoclose_ticks; - break; - case SCTP_TIMER_TYPE_STRRESET: - /* - * Here the timer comes from the stcb but its value is from - * the net's RTO. - */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.strreset_timer; - if (net->RTO == 0) { - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - } else { - to_ticks = sctp_msecs_to_ticks(net->RTO); - } - break; - case SCTP_TIMER_TYPE_INPKILL: - /* - * The inp is setup to die. We re-use the signature_change - * timer since that has stopped and we are in the GONE - * state. - */ - if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &inp->sctp_ep.signature_change; - to_ticks = sctp_msecs_to_ticks(SCTP_INP_KILL_TIMEOUT); - break; - case SCTP_TIMER_TYPE_ASOCKILL: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.strreset_timer; - to_ticks = sctp_msecs_to_ticks(SCTP_ASOC_KILL_TIMEOUT); - break; - case SCTP_TIMER_TYPE_ADDR_WQ: - if ((inp != NULL) || (stcb != NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - /* Only 1 tick away :-) */ - tmr = &SCTP_BASE_INFO(addr_wq_timer); - to_ticks = SCTP_ADDRESS_TICK_DELAY; - break; - case SCTP_TIMER_TYPE_PRIM_DELETED: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.delete_prim_timer; - to_ticks = sctp_msecs_to_ticks(stcb->asoc.initial_rto); - break; - default: -#ifdef INVARIANTS - panic("Unknown timer type %d", t_type); -#else - return; -#endif - } - KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type)); - KASSERT(to_ticks > 0, ("to_ticks == 0 for timer type %d", t_type)); - if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { - /* - * We do NOT allow you to have it already running. If it is, - * we leave the current one up unchanged. - */ - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d already running: inp=%p, stcb=%p, net=%p.\n", - t_type, inp, stcb, net); - return; - } - /* At this point we can proceed. */ - if (t_type == SCTP_TIMER_TYPE_SEND) { - stcb->asoc.num_send_timers_up++; - } - tmr->stopped_from = 0; - tmr->type = t_type; - tmr->ep = (void *)inp; - tmr->tcb = (void *)stcb; - if (t_type == SCTP_TIMER_TYPE_STRRESET) { - tmr->net = NULL; - } else { - tmr->net = (void *)net; - } - tmr->self = (void *)tmr; -#if defined(__FreeBSD__) && !defined(__Userspace__) - tmr->vnet = (void *)curvnet; -#endif - tmr->ticks = sctp_get_tick_count(); - if (SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr) == 0) { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d started: ticks=%u, inp=%p, stcb=%p, net=%p.\n", - t_type, to_ticks, inp, stcb, net); - /* - * If this is a newly scheduled callout, as opposed to a - * rescheduled one, increment relevant reference counts. - */ - if (tmr->ep != NULL) { - SCTP_INP_INCR_REF(inp); - } - if (tmr->tcb != NULL) { - atomic_add_int(&stcb->asoc.refcnt, 1); - } - if (tmr->net != NULL) { - atomic_add_int(&net->ref_count, 1); - } - } else { - /* - * This should not happen, since we checked for pending - * above. - */ - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d restarted: ticks=%u, inp=%p, stcb=%p, net=%p.\n", - t_type, to_ticks, inp, stcb, net); - } - return; -} - -/*- - * The following table shows which parameters must be provided - * when calling sctp_timer_stop(). For parameters not being - * provided, NULL must be used. - * - * |Name |inp |stcb|net | - * |-----------------------------|----|----|----| - * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No | - * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No | - * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes | - * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |No | - * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No | - * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No | - * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |No | - * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No | - * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No | - * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No | - * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No | - * - */ - -void -sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net, uint32_t from) -{ - struct sctp_timer *tmr; - - KASSERT(stcb == NULL || stcb->sctp_ep == inp, - ("sctp_timer_stop of type %d: inp = %p, stcb->sctp_ep %p", - t_type, stcb, stcb->sctp_ep)); - if (stcb != NULL) { - SCTP_TCB_LOCK_ASSERT(stcb); - } else if (inp != NULL) { - SCTP_INP_WLOCK_ASSERT(inp); - } else { - SCTP_WQ_ADDR_LOCK_ASSERT(); - } - tmr = NULL; - switch (t_type) { - case SCTP_TIMER_TYPE_SEND: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - break; - case SCTP_TIMER_TYPE_INIT: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - break; - case SCTP_TIMER_TYPE_RECV: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.dack_timer; - break; - case SCTP_TIMER_TYPE_SHUTDOWN: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - break; - case SCTP_TIMER_TYPE_HEARTBEAT: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->hb_timer; - break; - case SCTP_TIMER_TYPE_COOKIE: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - break; - case SCTP_TIMER_TYPE_NEWCOOKIE: - if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &inp->sctp_ep.signature_change; - break; - case SCTP_TIMER_TYPE_PATHMTURAISE: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->pmtu_timer; - break; - case SCTP_TIMER_TYPE_SHUTDOWNACK: - if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &net->rxt_timer; - break; - case SCTP_TIMER_TYPE_ASCONF: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.asconf_timer; - break; - case SCTP_TIMER_TYPE_SHUTDOWNGUARD: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.shut_guard_timer; - break; - case SCTP_TIMER_TYPE_AUTOCLOSE: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.autoclose_timer; - break; - case SCTP_TIMER_TYPE_STRRESET: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.strreset_timer; - break; - case SCTP_TIMER_TYPE_INPKILL: - /* - * The inp is setup to die. We re-use the signature_change - * timer since that has stopped and we are in the GONE - * state. - */ - if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &inp->sctp_ep.signature_change; - break; - case SCTP_TIMER_TYPE_ASOCKILL: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.strreset_timer; - break; - case SCTP_TIMER_TYPE_ADDR_WQ: - if ((inp != NULL) || (stcb != NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &SCTP_BASE_INFO(addr_wq_timer); - break; - case SCTP_TIMER_TYPE_PRIM_DELETED: - if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { -#ifdef INVARIANTS - panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", - t_type, inp, stcb, net); -#else - return; -#endif - } - tmr = &stcb->asoc.delete_prim_timer; - break; - default: -#ifdef INVARIANTS - panic("Unknown timer type %d", t_type); -#else - return; -#endif - } - KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type)); - if ((tmr->type != SCTP_TIMER_TYPE_NONE) && - (tmr->type != t_type)) { - /* - * Ok we have a timer that is under joint use. Cookie timer - * per chance with the SEND timer. We therefore are NOT - * running the timer that the caller wants stopped. So just - * return. - */ - SCTPDBG(SCTP_DEBUG_TIMER2, - "Shared timer type %d not running: inp=%p, stcb=%p, net=%p.\n", - t_type, inp, stcb, net); - return; - } - if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) { - stcb->asoc.num_send_timers_up--; - if (stcb->asoc.num_send_timers_up < 0) { - stcb->asoc.num_send_timers_up = 0; - } - } - tmr->self = NULL; - tmr->stopped_from = from; - if (SCTP_OS_TIMER_STOP(&tmr->timer) == 1) { - KASSERT(tmr->ep == inp, - ("sctp_timer_stop of type %d: inp = %p, tmr->inp = %p", - t_type, inp, tmr->ep)); - KASSERT(tmr->tcb == stcb, - ("sctp_timer_stop of type %d: stcb = %p, tmr->stcb = %p", - t_type, stcb, tmr->tcb)); - KASSERT(((t_type == SCTP_TIMER_TYPE_ASCONF) && (tmr->net != NULL)) || - ((t_type != SCTP_TIMER_TYPE_ASCONF) && (tmr->net == net)), - ("sctp_timer_stop of type %d: net = %p, tmr->net = %p", - t_type, net, tmr->net)); - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d stopped: inp=%p, stcb=%p, net=%p.\n", - t_type, inp, stcb, net); - /* - * If the timer was actually stopped, decrement reference counts - * that were incremented in sctp_timer_start(). - */ - if (tmr->ep != NULL) { - tmr->ep = NULL; - SCTP_INP_DECR_REF(inp); - } - if (tmr->tcb != NULL) { - tmr->tcb = NULL; - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (tmr->net != NULL) { - struct sctp_nets *tmr_net; - - /* - * Can't use net, since it doesn't work for - * SCTP_TIMER_TYPE_ASCONF. - */ - tmr_net = tmr->net; - tmr->net = NULL; - sctp_free_remote_addr(tmr_net); - } - } else { - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d not stopped: inp=%p, stcb=%p, net=%p.\n", - t_type, inp, stcb, net); - } - return; -} - -uint32_t -sctp_calculate_len(struct mbuf *m) -{ - struct mbuf *at; - uint32_t tlen; - - tlen = 0; - for (at = m; at != NULL; at = SCTP_BUF_NEXT(at)) { - tlen += SCTP_BUF_LEN(at); - } - return (tlen); -} - -/* - * Given an association and starting time of the current RTT period, update - * RTO in number of msecs. net should point to the current network. - * Return 1, if an RTO update was performed, return 0 if no update was - * performed due to invalid starting point. - */ - -int -sctp_calculate_rto(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_nets *net, - struct timeval *old, - int rtt_from_sack) -{ - struct timeval now; - uint64_t rtt_us; /* RTT in us */ - int32_t rtt; /* RTT in ms */ - uint32_t new_rto; - int first_measure = 0; - - /************************/ - /* 1. calculate new RTT */ - /************************/ - /* get the current time */ - if (stcb->asoc.use_precise_time) { - (void)SCTP_GETPTIME_TIMEVAL(&now); - } else { - (void)SCTP_GETTIME_TIMEVAL(&now); - } - if ((old->tv_sec > now.tv_sec) || - ((old->tv_sec == now.tv_sec) && (old->tv_usec > now.tv_usec))) { - /* The starting point is in the future. */ - return (0); - } - timevalsub(&now, old); - rtt_us = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec; - if (rtt_us > SCTP_RTO_UPPER_BOUND * 1000) { - /* The RTT is larger than a sane value. */ - return (0); - } - /* store the current RTT in us */ - net->rtt = rtt_us; - /* compute rtt in ms */ - rtt = (int32_t)(net->rtt / 1000); - if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) { - /* Tell the CC module that a new update has just occurred from a sack */ - (*asoc->cc_functions.sctp_rtt_calculated)(stcb, net, &now); - } - /* Do we need to determine the lan? We do this only - * on sacks i.e. RTT being determined from data not - * non-data (HB/INIT->INITACK). - */ - if ((rtt_from_sack == SCTP_RTT_FROM_DATA) && - (net->lan_type == SCTP_LAN_UNKNOWN)) { - if (net->rtt > SCTP_LOCAL_LAN_RTT) { - net->lan_type = SCTP_LAN_INTERNET; - } else { - net->lan_type = SCTP_LAN_LOCAL; - } - } - - /***************************/ - /* 2. update RTTVAR & SRTT */ - /***************************/ - /*- - * Compute the scaled average lastsa and the - * scaled variance lastsv as described in van Jacobson - * Paper "Congestion Avoidance and Control", Annex A. - * - * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt - * (net->lastsv >> SCTP_RTT_VAR_SHIFT) is the rttvar - */ - if (net->RTO_measured) { - rtt -= (net->lastsa >> SCTP_RTT_SHIFT); - net->lastsa += rtt; - if (rtt < 0) { - rtt = -rtt; - } - rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); - net->lastsv += rtt; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { - rto_logging(net, SCTP_LOG_RTTVAR); - } - } else { - /* First RTO measurement */ - net->RTO_measured = 1; - first_measure = 1; - net->lastsa = rtt << SCTP_RTT_SHIFT; - net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { - rto_logging(net, SCTP_LOG_INITIAL_RTT); - } - } - if (net->lastsv == 0) { - net->lastsv = SCTP_CLOCK_GRANULARITY; - } - new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - if ((new_rto > SCTP_SAT_NETWORK_MIN) && - (stcb->asoc.sat_network_lockout == 0)) { - stcb->asoc.sat_network = 1; - } else if ((!first_measure) && stcb->asoc.sat_network) { - stcb->asoc.sat_network = 0; - stcb->asoc.sat_network_lockout = 1; - } - /* bound it, per C6/C7 in Section 5.3.1 */ - if (new_rto < stcb->asoc.minrto) { - new_rto = stcb->asoc.minrto; - } - if (new_rto > stcb->asoc.maxrto) { - new_rto = stcb->asoc.maxrto; - } - net->RTO = new_rto; - return (1); -} - -/* - * return a pointer to a contiguous piece of data from the given mbuf chain - * starting at 'off' for 'len' bytes. If the desired piece spans more than - * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size - * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain. - */ -caddr_t -sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t * in_ptr) -{ - uint32_t count; - uint8_t *ptr; - - ptr = in_ptr; - if ((off < 0) || (len <= 0)) - return (NULL); - - /* find the desired start location */ - while ((m != NULL) && (off > 0)) { - if (off < SCTP_BUF_LEN(m)) - break; - off -= SCTP_BUF_LEN(m); - m = SCTP_BUF_NEXT(m); - } - if (m == NULL) - return (NULL); - - /* is the current mbuf large enough (eg. contiguous)? */ - if ((SCTP_BUF_LEN(m) - off) >= len) { - return (mtod(m, caddr_t) + off); - } else { - /* else, it spans more than one mbuf, so save a temp copy... */ - while ((m != NULL) && (len > 0)) { - count = min(SCTP_BUF_LEN(m) - off, len); - memcpy(ptr, mtod(m, caddr_t) + off, count); - len -= count; - ptr += count; - off = 0; - m = SCTP_BUF_NEXT(m); - } - if ((m == NULL) && (len > 0)) - return (NULL); - else - return ((caddr_t)in_ptr); - } -} - -struct sctp_paramhdr * -sctp_get_next_param(struct mbuf *m, - int offset, - struct sctp_paramhdr *pull, - int pull_limit) -{ - /* This just provides a typed signature to Peter's Pull routine */ - return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit, - (uint8_t *) pull)); -} - -struct mbuf * -sctp_add_pad_tombuf(struct mbuf *m, int padlen) -{ - struct mbuf *m_last; - caddr_t dp; - - if (padlen > 3) { - return (NULL); - } - if (padlen <= M_TRAILINGSPACE(m)) { - /* - * The easy way. We hope the majority of the time we hit - * here :) - */ - m_last = m; - } else { - /* Hard way we must grow the mbuf chain */ - m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA); - if (m_last == NULL) { - return (NULL); - } - SCTP_BUF_LEN(m_last) = 0; - SCTP_BUF_NEXT(m_last) = NULL; - SCTP_BUF_NEXT(m) = m_last; - } - dp = mtod(m_last, caddr_t) + SCTP_BUF_LEN(m_last); - SCTP_BUF_LEN(m_last) += padlen; - memset(dp, 0, padlen); - return (m_last); -} - -struct mbuf * -sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) -{ - /* find the last mbuf in chain and pad it */ - struct mbuf *m_at; - - if (last_mbuf != NULL) { - return (sctp_add_pad_tombuf(last_mbuf, padval)); - } else { - for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) { - if (SCTP_BUF_NEXT(m_at) == NULL) { - return (sctp_add_pad_tombuf(m_at, padval)); - } - } - } - return (NULL); -} - -static void -sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, - uint16_t error, struct sctp_abort_chunk *abort, - bool from_peer, bool timedout, int so_locked) -{ - struct mbuf *m_notify; - struct sctp_assoc_change *sac; - struct sctp_queued_to_read *control; - unsigned int notif_len; - uint16_t abort_len; - unsigned int i; -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - - KASSERT(abort == NULL || from_peer, - ("sctp_notify_assoc_change: ABORT chunk provided for local termination")); - KASSERT(!from_peer || !timedout, - ("sctp_notify_assoc_change: timeouts can only be local")); - if (stcb == NULL) { - return; - } - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { - notif_len = (unsigned int)sizeof(struct sctp_assoc_change); - if (abort != NULL) { - abort_len = ntohs(abort->ch.chunk_length); - /* - * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be - * contiguous. - */ - if (abort_len > SCTP_CHUNK_BUFFER_SIZE) { - abort_len = SCTP_CHUNK_BUFFER_SIZE; - } - } else { - abort_len = 0; - } - if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { - notif_len += SCTP_ASSOC_SUPPORTS_MAX; - } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { - notif_len += abort_len; - } - m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) { - /* Retry with smaller value. */ - notif_len = (unsigned int)sizeof(struct sctp_assoc_change); - m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) { - goto set_error; - } - } - SCTP_BUF_NEXT(m_notify) = NULL; - sac = mtod(m_notify, struct sctp_assoc_change *); - memset(sac, 0, notif_len); - sac->sac_type = SCTP_ASSOC_CHANGE; - sac->sac_flags = 0; - sac->sac_length = sizeof(struct sctp_assoc_change); - sac->sac_state = state; - sac->sac_error = error; - if (state == SCTP_CANT_STR_ASSOC) { - sac->sac_outbound_streams = 0; - sac->sac_inbound_streams = 0; - } else { - sac->sac_outbound_streams = stcb->asoc.streamoutcnt; - sac->sac_inbound_streams = stcb->asoc.streamincnt; - } - sac->sac_assoc_id = sctp_get_associd(stcb); - if (notif_len > sizeof(struct sctp_assoc_change)) { - if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { - i = 0; - if (stcb->asoc.prsctp_supported == 1) { - sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR; - } - if (stcb->asoc.auth_supported == 1) { - sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH; - } - if (stcb->asoc.asconf_supported == 1) { - sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; - } - if (stcb->asoc.idata_supported == 1) { - sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING; - } - sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; - if (stcb->asoc.reconfig_supported == 1) { - sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; - } - sac->sac_length += i; - } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { - memcpy(sac->sac_info, abort, abort_len); - sac->sac_length += abort_len; - } - } - SCTP_BUF_LEN(m_notify) = sac->sac_length; - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control != NULL) { - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, - so_locked); - } else { - sctp_m_freem(m_notify); - } - } - /* - * For 1-to-1 style sockets, we send up and error when an ABORT - * comes in. - */ -set_error: - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && - ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { - SOCK_LOCK(stcb->sctp_socket); - if (from_peer) { - if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); - stcb->sctp_socket->so_error = ECONNREFUSED; - } else { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); - stcb->sctp_socket->so_error = ECONNRESET; - } - } else { - if (timedout) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT); - stcb->sctp_socket->so_error = ETIMEDOUT; - } else { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED); - stcb->sctp_socket->so_error = ECONNABORTED; - } - } - SOCK_UNLOCK(stcb->sctp_socket); - } - /* Wake ANY sleepers */ -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(stcb->sctp_ep); - if (!so_locked) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } - } -#endif - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && - ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { - socantrcvmore(stcb->sctp_socket); - } - sorwakeup(stcb->sctp_socket); - sowwakeup(stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif -} - -static void -sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, - struct sockaddr *sa, uint32_t error, int so_locked) -{ - struct mbuf *m_notify; - struct sctp_paddr_change *spc; - struct sctp_queued_to_read *control; - - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { - /* event not enabled */ - return; - } - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - return; - SCTP_BUF_LEN(m_notify) = 0; - spc = mtod(m_notify, struct sctp_paddr_change *); - memset(spc, 0, sizeof(struct sctp_paddr_change)); - spc->spc_type = SCTP_PEER_ADDR_CHANGE; - spc->spc_flags = 0; - spc->spc_length = sizeof(struct sctp_paddr_change); - switch (sa->sa_family) { -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { - in6_sin_2_v4mapsin6((struct sockaddr_in *)sa, - (struct sockaddr_in6 *)&spc->spc_aaddr); - } else { - memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); - } -#else - memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - { -#ifdef SCTP_EMBEDDED_V6_SCOPE - struct sockaddr_in6 *sin6; -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6)); - -#ifdef SCTP_EMBEDDED_V6_SCOPE - sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { - if (sin6->sin6_scope_id == 0) { - /* recover scope_id for user */ -#ifdef SCTP_KAME - (void)sa6_recoverscope(sin6); -#else - (void)in6_recoverscope(sin6, &sin6->sin6_addr, - NULL); -#endif - } else { - /* clear embedded scope_id for user */ - in6_clearscope(&sin6->sin6_addr); - } - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_conn)); - break; -#endif - default: - /* TSNH */ - break; - } - spc->spc_state = state; - spc->spc_error = error; - spc->spc_assoc_id = sctp_get_associd(stcb); - - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change); - SCTP_BUF_NEXT(m_notify) = NULL; - - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, - so_locked); -} - -static void -sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, - struct sctp_tmit_chunk *chk, int so_locked) -{ - struct mbuf *m_notify; - struct sctp_send_failed *ssf; - struct sctp_send_failed_event *ssfe; - struct sctp_queued_to_read *control; - struct sctp_chunkhdr *chkhdr; - int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len; - - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { - /* event not enabled */ - return; - } - - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - notifhdr_len = sizeof(struct sctp_send_failed_event); - } else { - notifhdr_len = sizeof(struct sctp_send_failed); - } - m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - SCTP_BUF_LEN(m_notify) = notifhdr_len; - if (stcb->asoc.idata_supported) { - chkhdr_len = sizeof(struct sctp_idata_chunk); - } else { - chkhdr_len = sizeof(struct sctp_data_chunk); - } - /* Use some defaults in case we can't access the chunk header */ - if (chk->send_size >= chkhdr_len) { - payload_len = chk->send_size - chkhdr_len; - } else { - payload_len = 0; - } - padding_len = 0; - if (chk->data != NULL) { - chkhdr = mtod(chk->data, struct sctp_chunkhdr *); - if (chkhdr != NULL) { - chk_len = ntohs(chkhdr->chunk_length); - if ((chk_len >= chkhdr_len) && - (chk->send_size >= chk_len) && - (chk->send_size - chk_len < 4)) { - padding_len = chk->send_size - chk_len; - payload_len = chk->send_size - chkhdr_len - padding_len; - } - } - } - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - ssfe = mtod(m_notify, struct sctp_send_failed_event *); - memset(ssfe, 0, notifhdr_len); - ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; - if (sent) { - ssfe->ssfe_flags = SCTP_DATA_SENT; - } else { - ssfe->ssfe_flags = SCTP_DATA_UNSENT; - } - ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len); - ssfe->ssfe_error = error; - /* not exactly what the user sent in, but should be close :) */ - ssfe->ssfe_info.snd_sid = chk->rec.data.sid; - ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags; - ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid; - ssfe->ssfe_info.snd_context = chk->rec.data.context; - ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); - ssfe->ssfe_assoc_id = sctp_get_associd(stcb); - } else { - ssf = mtod(m_notify, struct sctp_send_failed *); - memset(ssf, 0, notifhdr_len); - ssf->ssf_type = SCTP_SEND_FAILED; - if (sent) { - ssf->ssf_flags = SCTP_DATA_SENT; - } else { - ssf->ssf_flags = SCTP_DATA_UNSENT; - } - ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len); - ssf->ssf_error = error; - /* not exactly what the user sent in, but should be close :) */ - ssf->ssf_info.sinfo_stream = chk->rec.data.sid; - ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid; - ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; - ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid; - ssf->ssf_info.sinfo_context = chk->rec.data.context; - ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); - ssf->ssf_assoc_id = sctp_get_associd(stcb); - } - if (chk->data != NULL) { - /* Trim off the sctp chunk header (it should be there) */ - if (chk->send_size == chkhdr_len + payload_len + padding_len) { - m_adj(chk->data, chkhdr_len); - m_adj(chk->data, -padding_len); - sctp_mbuf_crush(chk->data); - chk->send_size -= (chkhdr_len + padding_len); - } - } - SCTP_BUF_NEXT(m_notify) = chk->data; - /* Steal off the mbuf */ - chk->data = NULL; - /* - * For this case, we check the actual socket buffer, since the assoc - * is going away we don't want to overfill the socket buffer for a - * non-reader - */ - if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { - sctp_m_freem(m_notify); - return; - } - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, - so_locked); -} - -static void -sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, - struct sctp_stream_queue_pending *sp, int so_locked) -{ - struct mbuf *m_notify; - struct sctp_send_failed *ssf; - struct sctp_send_failed_event *ssfe; - struct sctp_queued_to_read *control; - int notifhdr_len; - - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { - /* event not enabled */ - return; - } - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - notifhdr_len = sizeof(struct sctp_send_failed_event); - } else { - notifhdr_len = sizeof(struct sctp_send_failed); - } - m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) { - /* no space left */ - return; - } - SCTP_BUF_LEN(m_notify) = notifhdr_len; - if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - ssfe = mtod(m_notify, struct sctp_send_failed_event *); - memset(ssfe, 0, notifhdr_len); - ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; - ssfe->ssfe_flags = SCTP_DATA_UNSENT; - ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length); - ssfe->ssfe_error = error; - /* not exactly what the user sent in, but should be close :) */ - ssfe->ssfe_info.snd_sid = sp->sid; - if (sp->some_taken) { - ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG; - } else { - ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG; - } - ssfe->ssfe_info.snd_ppid = sp->ppid; - ssfe->ssfe_info.snd_context = sp->context; - ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); - ssfe->ssfe_assoc_id = sctp_get_associd(stcb); - } else { - ssf = mtod(m_notify, struct sctp_send_failed *); - memset(ssf, 0, notifhdr_len); - ssf->ssf_type = SCTP_SEND_FAILED; - ssf->ssf_flags = SCTP_DATA_UNSENT; - ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length); - ssf->ssf_error = error; - /* not exactly what the user sent in, but should be close :) */ - ssf->ssf_info.sinfo_stream = sp->sid; - ssf->ssf_info.sinfo_ssn = 0; - if (sp->some_taken) { - ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG; - } else { - ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG; - } - ssf->ssf_info.sinfo_ppid = sp->ppid; - ssf->ssf_info.sinfo_context = sp->context; - ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); - ssf->ssf_assoc_id = sctp_get_associd(stcb); - } - SCTP_BUF_NEXT(m_notify) = sp->data; - - /* Steal off the mbuf */ - sp->data = NULL; - /* - * For this case, we check the actual socket buffer, since the assoc - * is going away we don't want to overfill the socket buffer for a - * non-reader - */ - if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { - sctp_m_freem(m_notify); - return; - } - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); -} - -static void -sctp_notify_adaptation_layer(struct sctp_tcb *stcb) -{ - struct mbuf *m_notify; - struct sctp_adaptation_event *sai; - struct sctp_queued_to_read *control; - - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { - /* event not enabled */ - return; - } - - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - SCTP_BUF_LEN(m_notify) = 0; - sai = mtod(m_notify, struct sctp_adaptation_event *); - memset(sai, 0, sizeof(struct sctp_adaptation_event)); - sai->sai_type = SCTP_ADAPTATION_INDICATION; - sai->sai_flags = 0; - sai->sai_length = sizeof(struct sctp_adaptation_event); - sai->sai_adaptation_ind = stcb->asoc.peers_adaptation; - sai->sai_assoc_id = sctp_get_associd(stcb); - - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event); - SCTP_BUF_NEXT(m_notify) = NULL; - - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); -} - -static void -sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, - struct sctp_queued_to_read *aborted_control, - int so_locked) -{ - struct mbuf *m_notify; - struct sctp_pdapi_event *pdapi; - struct sctp_queued_to_read *control; - struct sockbuf *sb; - - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { - /* event not enabled */ - return; - } - - KASSERT(aborted_control != NULL, ("aborted_control is NULL")); - SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep); - - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - SCTP_BUF_LEN(m_notify) = 0; - pdapi = mtod(m_notify, struct sctp_pdapi_event *); - memset(pdapi, 0, sizeof(struct sctp_pdapi_event)); - pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; - pdapi->pdapi_flags = 0; - pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); - pdapi->pdapi_indication = error; - pdapi->pdapi_stream = aborted_control->sinfo_stream; - pdapi->pdapi_seq = (uint16_t)aborted_control->mid; - pdapi->pdapi_assoc_id = sctp_get_associd(stcb); - - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); - SCTP_BUF_NEXT(m_notify) = NULL; - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sb = &stcb->sctp_socket->so_rcv; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify)); - } - sctp_sballoc(stcb, sb, m_notify); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - control->end_added = 1; - TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, aborted_control, control, next); - if (stcb->sctp_ep && stcb->sctp_socket) { - /* This should always be the case */ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - if (!so_locked) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } - } -#endif - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif - } -} - -static void -sctp_notify_shutdown_event(struct sctp_tcb *stcb) -{ - struct mbuf *m_notify; - struct sctp_shutdown_event *sse; - struct sctp_queued_to_read *control; - - /* - * For TCP model AND UDP connected sockets we will send an error up - * when an SHUTDOWN completes - */ - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* mark socket closed for read/write and wakeup! */ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } -#endif - socantsendmore(stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { - /* event not enabled */ - return; - } - - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - sse = mtod(m_notify, struct sctp_shutdown_event *); - memset(sse, 0, sizeof(struct sctp_shutdown_event)); - sse->sse_type = SCTP_SHUTDOWN_EVENT; - sse->sse_flags = 0; - sse->sse_length = sizeof(struct sctp_shutdown_event); - sse->sse_assoc_id = sctp_get_associd(stcb); - - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event); - SCTP_BUF_NEXT(m_notify) = NULL; - - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); -} - -static void -sctp_notify_sender_dry_event(struct sctp_tcb *stcb, - int so_locked) -{ - struct mbuf *m_notify; - struct sctp_sender_dry_event *event; - struct sctp_queued_to_read *control; - - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { - /* event not enabled */ - return; - } - - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) { - /* no space left */ - return; - } - SCTP_BUF_LEN(m_notify) = 0; - event = mtod(m_notify, struct sctp_sender_dry_event *); - memset(event, 0, sizeof(struct sctp_sender_dry_event)); - event->sender_dry_type = SCTP_SENDER_DRY_EVENT; - event->sender_dry_flags = 0; - event->sender_dry_length = sizeof(struct sctp_sender_dry_event); - event->sender_dry_assoc_id = sctp_get_associd(stcb); - - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event); - SCTP_BUF_NEXT(m_notify) = NULL; - - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); -} - -void -sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag) -{ - struct mbuf *m_notify; - struct sctp_queued_to_read *control; - struct sctp_stream_change_event *stradd; - - if ((stcb == NULL) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* If the socket is gone we are out of here. */ - return; - } - if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT)) { - /* event not enabled */ - return; - } - - if ((stcb->asoc.peer_req_out) && flag) { - /* Peer made the request, don't tell the local user */ - stcb->asoc.peer_req_out = 0; - return; - } - stcb->asoc.peer_req_out = 0; - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - SCTP_BUF_LEN(m_notify) = 0; - stradd = mtod(m_notify, struct sctp_stream_change_event *); - memset(stradd, 0, sizeof(struct sctp_stream_change_event)); - stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT; - stradd->strchange_flags = flag; - stradd->strchange_length = sizeof(struct sctp_stream_change_event); - stradd->strchange_assoc_id = sctp_get_associd(stcb); - stradd->strchange_instrms = numberin; - stradd->strchange_outstrms = numberout; - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event); - SCTP_BUF_NEXT(m_notify) = NULL; - if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { - /* no space */ - sctp_m_freem(m_notify); - return; - } - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); -} - -void -sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag) -{ - struct mbuf *m_notify; - struct sctp_queued_to_read *control; - struct sctp_assoc_reset_event *strasoc; - - if ((stcb == NULL) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* If the socket is gone we are out of here. */ - return; - } - if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT)) { - /* event not enabled */ - return; - } - - m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - SCTP_BUF_LEN(m_notify) = 0; - strasoc = mtod(m_notify, struct sctp_assoc_reset_event *); - memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event)); - strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT; - strasoc->assocreset_flags = flag; - strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event); - strasoc->assocreset_assoc_id= sctp_get_associd(stcb); - strasoc->assocreset_local_tsn = sending_tsn; - strasoc->assocreset_remote_tsn = recv_tsn; - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event); - SCTP_BUF_NEXT(m_notify) = NULL; - if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { - /* no space */ - sctp_m_freem(m_notify); - return; - } - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); -} - -static void -sctp_notify_stream_reset(struct sctp_tcb *stcb, - int number_entries, uint16_t * list, int flag) -{ - struct mbuf *m_notify; - struct sctp_queued_to_read *control; - struct sctp_stream_reset_event *strreset; - int len; - - if ((stcb == NULL) || - (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) { - /* event not enabled */ - return; - } - - m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) - /* no space left */ - return; - SCTP_BUF_LEN(m_notify) = 0; - len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); - if (len > M_TRAILINGSPACE(m_notify)) { - /* never enough room */ - sctp_m_freem(m_notify); - return; - } - strreset = mtod(m_notify, struct sctp_stream_reset_event *); - memset(strreset, 0, len); - strreset->strreset_type = SCTP_STREAM_RESET_EVENT; - strreset->strreset_flags = flag; - strreset->strreset_length = len; - strreset->strreset_assoc_id = sctp_get_associd(stcb); - if (number_entries) { - int i; - - for (i = 0; i < number_entries; i++) { - strreset->strreset_stream_list[i] = ntohs(list[i]); - } - } - SCTP_BUF_LEN(m_notify) = len; - SCTP_BUF_NEXT(m_notify) = NULL; - if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { - /* no space */ - sctp_m_freem(m_notify); - return; - } - /* append to socket */ - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control == NULL) { - /* no memory */ - sctp_m_freem(m_notify); - return; - } - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); -} - -static void -sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk) -{ - struct mbuf *m_notify; - struct sctp_remote_error *sre; - struct sctp_queued_to_read *control; - unsigned int notif_len; - uint16_t chunk_len; - - if ((stcb == NULL) || - sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { - return; - } - if (chunk != NULL) { - chunk_len = ntohs(chunk->ch.chunk_length); - /* - * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be - * contiguous. - */ - if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) { - chunk_len = SCTP_CHUNK_BUFFER_SIZE; - } - } else { - chunk_len = 0; - } - notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len); - m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) { - /* Retry with smaller value. */ - notif_len = (unsigned int)sizeof(struct sctp_remote_error); - m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); - if (m_notify == NULL) { - return; - } - } - SCTP_BUF_NEXT(m_notify) = NULL; - sre = mtod(m_notify, struct sctp_remote_error *); - memset(sre, 0, notif_len); - sre->sre_type = SCTP_REMOTE_ERROR; - sre->sre_flags = 0; - sre->sre_length = sizeof(struct sctp_remote_error); - sre->sre_error = error; - sre->sre_assoc_id = sctp_get_associd(stcb); - if (notif_len > sizeof(struct sctp_remote_error)) { - memcpy(sre->sre_data, chunk, chunk_len); - sre->sre_length += chunk_len; - } - SCTP_BUF_LEN(m_notify) = sre->sre_length; - control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, - 0, 0, stcb->asoc.context, 0, 0, 0, - m_notify); - if (control != NULL) { - control->length = SCTP_BUF_LEN(m_notify); - control->spec_flags = M_NOTIFICATION; - /* not that we need this */ - control->tail_mbuf = m_notify; - sctp_add_to_readq(stcb->sctp_ep, stcb, - control, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - } else { - sctp_m_freem(m_notify); - } -} - -void -sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, - uint32_t error, void *data, int so_locked) -{ - if ((stcb == NULL) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* If the socket is gone we are out of here */ - return; - } -#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__) - if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { -#else - if (stcb->sctp_socket->so_state & SS_CANTRCVMORE) { -#endif - return; - } -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } else { - sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } -#endif - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || - (notification == SCTP_NOTIFY_INTERFACE_UP) || - (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { - /* Don't report these in front states */ - return; - } - } - switch (notification) { - case SCTP_NOTIFY_ASSOC_UP: - if (stcb->asoc.assoc_up_sent == 0) { - sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, false, false, so_locked); - stcb->asoc.assoc_up_sent = 1; - } - if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { - sctp_notify_adaptation_layer(stcb); - } - if (stcb->asoc.auth_supported == 0) { - sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, - NULL, so_locked); - } - break; - case SCTP_NOTIFY_ASSOC_DOWN: - sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, false, false, so_locked); -#if defined(__Userspace__) - if (stcb->sctp_ep->recv_callback) { - if (stcb->sctp_socket) { - union sctp_sockstore addr; - struct sctp_rcvinfo rcv; - - memset(&addr, 0, sizeof(union sctp_sockstore)); - memset(&rcv, 0, sizeof(struct sctp_rcvinfo)); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - stcb->sctp_ep->recv_callback(stcb->sctp_socket, addr, NULL, 0, rcv, 0, stcb->sctp_ep->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - } -#endif - break; - case SCTP_NOTIFY_INTERFACE_DOWN: - { - struct sctp_nets *net; - - net = (struct sctp_nets *)data; - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, - (struct sockaddr *)&net->ro._l_addr, error, so_locked); - break; - } - case SCTP_NOTIFY_INTERFACE_UP: - { - struct sctp_nets *net; - - net = (struct sctp_nets *)data; - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, - (struct sockaddr *)&net->ro._l_addr, error, so_locked); - break; - } - case SCTP_NOTIFY_INTERFACE_CONFIRMED: - { - struct sctp_nets *net; - - net = (struct sctp_nets *)data; - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, - (struct sockaddr *)&net->ro._l_addr, error, so_locked); - break; - } - case SCTP_NOTIFY_SPECIAL_SP_FAIL: - sctp_notify_send_failed2(stcb, error, - (struct sctp_stream_queue_pending *)data, so_locked); - break; - case SCTP_NOTIFY_SENT_DG_FAIL: - sctp_notify_send_failed(stcb, 1, error, - (struct sctp_tmit_chunk *)data, so_locked); - break; - case SCTP_NOTIFY_UNSENT_DG_FAIL: - sctp_notify_send_failed(stcb, 0, error, - (struct sctp_tmit_chunk *)data, so_locked); - break; - case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: - sctp_notify_partial_delivery_indication(stcb, error, - (struct sctp_queued_to_read *)data, - so_locked); - break; - case SCTP_NOTIFY_ASSOC_LOC_ABORTED: - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, false, false, so_locked); - } else { - sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, false, false, so_locked); - } - break; - case SCTP_NOTIFY_ASSOC_REM_ABORTED: - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, true, false, so_locked); - } else { - sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, true, false, so_locked); - } - break; - case SCTP_NOTIFY_ASSOC_TIMEDOUT: - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, false, true, so_locked); - } else { - sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, false, true, so_locked); - } - break; - case SCTP_NOTIFY_ASSOC_RESTART: - sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, false, false, so_locked); - if (stcb->asoc.auth_supported == 0) { - sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, - NULL, so_locked); - } - break; - case SCTP_NOTIFY_STR_RESET_SEND: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING_SSN); - break; - case SCTP_NOTIFY_STR_RESET_RECV: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING); - break; - case SCTP_NOTIFY_STR_RESET_FAILED_OUT: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_OUTGOING_SSN|SCTP_STREAM_RESET_FAILED)); - break; - case SCTP_NOTIFY_STR_RESET_DENIED_OUT: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_OUTGOING_SSN|SCTP_STREAM_RESET_DENIED)); - break; - case SCTP_NOTIFY_STR_RESET_FAILED_IN: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_INCOMING|SCTP_STREAM_RESET_FAILED)); - break; - case SCTP_NOTIFY_STR_RESET_DENIED_IN: - sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), - (SCTP_STREAM_RESET_INCOMING|SCTP_STREAM_RESET_DENIED)); - break; - case SCTP_NOTIFY_ASCONF_ADD_IP: - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, - error, so_locked); - break; - case SCTP_NOTIFY_ASCONF_DELETE_IP: - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, - error, so_locked); - break; - case SCTP_NOTIFY_ASCONF_SET_PRIMARY: - sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data, - error, so_locked); - break; - case SCTP_NOTIFY_PEER_SHUTDOWN: - sctp_notify_shutdown_event(stcb); - break; - case SCTP_NOTIFY_AUTH_NEW_KEY: - sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error, - (uint16_t)(uintptr_t)data, - so_locked); - break; - case SCTP_NOTIFY_AUTH_FREE_KEY: - sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, - (uint16_t)(uintptr_t)data, - so_locked); - break; - case SCTP_NOTIFY_NO_PEER_AUTH: - sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, - (uint16_t)(uintptr_t)data, - so_locked); - break; - case SCTP_NOTIFY_SENDER_DRY: - sctp_notify_sender_dry_event(stcb, so_locked); - break; - case SCTP_NOTIFY_REMOTE_ERROR: - sctp_notify_remote_error(stcb, error, data); - break; - default: - SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", - __func__, notification, notification); - break; - } /* end switch */ -} - -void -sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int so_locked) -{ - struct sctp_association *asoc; - struct sctp_stream_out *outs; - struct sctp_tmit_chunk *chk, *nchk; - struct sctp_stream_queue_pending *sp, *nsp; - int i; - - if (stcb == NULL) { - return; - } - asoc = &stcb->asoc; - if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { - /* already being freed */ - return; - } -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } else { - sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } -#endif - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (asoc->state & SCTP_STATE_CLOSED_SOCKET)) { - return; - } - /* now through all the gunk freeing chunks */ - /* sent queue SHOULD be empty */ - TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); - asoc->sent_queue_cnt--; - if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { - if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[chk->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", chk->rec.data.sid); -#endif - } - } - if (chk->data != NULL) { - sctp_free_bufspace(stcb, asoc, chk, 1); - sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, - error, chk, so_locked); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - } - sctp_free_a_chunk(stcb, chk, so_locked); - /*sa_ignore FREED_MEMORY*/ - } - /* pending send queue SHOULD be empty */ - TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); - asoc->send_queue_cnt--; - if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { - asoc->strmout[chk->rec.data.sid].chunks_on_queues--; -#ifdef INVARIANTS - } else { - panic("No chunks on the queues for sid %u.", chk->rec.data.sid); -#endif - } - if (chk->data != NULL) { - sctp_free_bufspace(stcb, asoc, chk, 1); - sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, - error, chk, so_locked); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - } - sctp_free_a_chunk(stcb, chk, so_locked); - /*sa_ignore FREED_MEMORY*/ - } - for (i = 0; i < asoc->streamoutcnt; i++) { - /* For each stream */ - outs = &asoc->strmout[i]; - /* clean up any sends there */ - TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { - atomic_subtract_int(&asoc->stream_queue_cnt, 1); - TAILQ_REMOVE(&outs->outqueue, sp, next); - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp); - sctp_free_spbufspace(stcb, asoc, sp); - if (sp->data) { - sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, - error, (void *)sp, so_locked); - if (sp->data) { - sctp_m_freem(sp->data); - sp->data = NULL; - sp->tail_mbuf = NULL; - sp->length = 0; - } - } - if (sp->net) { - sctp_free_remote_addr(sp->net); - sp->net = NULL; - } - /* Free the chunk */ - sctp_free_a_strmoq(stcb, sp, so_locked); - /*sa_ignore FREED_MEMORY*/ - } - } -} - -void -sctp_abort_notification(struct sctp_tcb *stcb, bool from_peer, bool timeout, - uint16_t error, struct sctp_abort_chunk *abort, - int so_locked) -{ - if (stcb == NULL) { - return; - } -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } else { - sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } -#endif - SCTP_TCB_LOCK_ASSERT(stcb); - - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { - sctp_pcb_add_flags(stcb->sctp_ep, SCTP_PCB_FLAGS_WAS_ABORTED); - } - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - return; - } - SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED); - /* Tell them we lost the asoc */ - sctp_report_all_outbound(stcb, error, so_locked); - if (from_peer) { - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); - } else { - if (timeout) { - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_TIMEDOUT, stcb, error, abort, so_locked); - } else { - sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); - } - } -} - -void -sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct mbuf *m, int iphlen, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct mbuf *op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, -#endif - uint32_t vrf_id, uint16_t port) -{ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - struct sctp_gen_error_cause* cause; - uint32_t vtag; - uint16_t cause_code; - - if (stcb != NULL) { - vtag = stcb->asoc.peer_vtag; - vrf_id = stcb->asoc.vrf_id; - if (op_err != NULL) { - /* Read the cause code from the error cause. */ - cause = mtod(op_err, struct sctp_gen_error_cause *); - cause_code = ntohs(cause->code); - } else { - cause_code = 0; - } - } else { - vtag = 0; - } - sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, inp->fibnum, -#endif - vrf_id, port); - if (stcb != NULL) { - /* We have a TCB to abort, send notification too */ - sctp_abort_notification(stcb, false, false, cause_code, NULL, SCTP_SO_NOT_LOCKED); - /* Ok, now lets free it */ -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_4); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } -} -#ifdef SCTP_ASOCLOG_OF_TSNS -void -sctp_print_out_track_log(struct sctp_tcb *stcb) -{ -#ifdef NOSIY_PRINTS - int i; - SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code); - SCTP_PRINTF("IN bound TSN log-aaa\n"); - if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) { - SCTP_PRINTF("None rcvd\n"); - goto none_in; - } - if (stcb->asoc.tsn_in_wrapped) { - for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) { - SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", - stcb->asoc.in_tsnlog[i].tsn, - stcb->asoc.in_tsnlog[i].strm, - stcb->asoc.in_tsnlog[i].seq, - stcb->asoc.in_tsnlog[i].flgs, - stcb->asoc.in_tsnlog[i].sz); - } - } - if (stcb->asoc.tsn_in_at) { - for (i = 0; i < stcb->asoc.tsn_in_at; i++) { - SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", - stcb->asoc.in_tsnlog[i].tsn, - stcb->asoc.in_tsnlog[i].strm, - stcb->asoc.in_tsnlog[i].seq, - stcb->asoc.in_tsnlog[i].flgs, - stcb->asoc.in_tsnlog[i].sz); - } - } - none_in: - SCTP_PRINTF("OUT bound TSN log-aaa\n"); - if ((stcb->asoc.tsn_out_at == 0) && - (stcb->asoc.tsn_out_wrapped == 0)) { - SCTP_PRINTF("None sent\n"); - } - if (stcb->asoc.tsn_out_wrapped) { - for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) { - SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", - stcb->asoc.out_tsnlog[i].tsn, - stcb->asoc.out_tsnlog[i].strm, - stcb->asoc.out_tsnlog[i].seq, - stcb->asoc.out_tsnlog[i].flgs, - stcb->asoc.out_tsnlog[i].sz); - } - } - if (stcb->asoc.tsn_out_at) { - for (i = 0; i < stcb->asoc.tsn_out_at; i++) { - SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", - stcb->asoc.out_tsnlog[i].tsn, - stcb->asoc.out_tsnlog[i].strm, - stcb->asoc.out_tsnlog[i].seq, - stcb->asoc.out_tsnlog[i].flgs, - stcb->asoc.out_tsnlog[i].sz); - } - } -#endif -} -#endif - -void -sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct mbuf *op_err, bool timedout, int so_locked) -{ -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; -#endif - struct sctp_gen_error_cause* cause; - uint16_t cause_code; - -#if defined(__APPLE__) && !defined(__Userspace__) - so = SCTP_INP_SO(inp); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - if (stcb == NULL) { - /* Got to have a TCB */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - if (LIST_EMPTY(&inp->sctp_asoc_list)) { -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_LOCK(so, 1); - } -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_DIRECTLY_NOCMPSET); -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif - } - } - return; - } - if (op_err != NULL) { - /* Read the cause code from the error cause. */ - cause = mtod(op_err, struct sctp_gen_error_cause *); - cause_code = ntohs(cause->code); - } else { - cause_code = 0; - } - /* notify the peer */ - sctp_send_abort_tcb(stcb, op_err, so_locked); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - /* notify the ulp */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - sctp_abort_notification(stcb, false, timedout, cause_code, NULL, so_locked); - } - /* now free the asoc */ -#ifdef SCTP_ASOCLOG_OF_TSNS - sctp_print_out_track_log(stcb); -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_5); -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif -} - -void -sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, - struct sockaddr *src, struct sockaddr *dst, - struct sctphdr *sh, struct sctp_inpcb *inp, - struct mbuf *cause, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, -#endif - uint32_t vrf_id, uint16_t port) -{ - struct sctp_chunkhdr *ch, chunk_buf; - unsigned int chk_length; - int contains_init_chunk; - - SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue); - /* Generate a TO address for future reference */ - if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { - if (LIST_EMPTY(&inp->sctp_asoc_list)) { -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 1); -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, - SCTP_CALLED_DIRECTLY_NOCMPSET); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1); -#endif - } - } - contains_init_chunk = 0; - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, - sizeof(*ch), (uint8_t *) & chunk_buf); - while (ch != NULL) { - chk_length = ntohs(ch->chunk_length); - if (chk_length < sizeof(*ch)) { - /* break to abort land */ - break; - } - switch (ch->chunk_type) { - case SCTP_INIT: - contains_init_chunk = 1; - break; - case SCTP_PACKET_DROPPED: - /* we don't respond to pkt-dropped */ - return; - case SCTP_ABORT_ASSOCIATION: - /* we don't respond with an ABORT to an ABORT */ - return; - case SCTP_SHUTDOWN_COMPLETE: - /* - * we ignore it since we are not waiting for it and - * peer is gone - */ - return; - case SCTP_SHUTDOWN_ACK: - sctp_send_shutdown_complete2(src, dst, sh, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - return; - default: - break; - } - offset += SCTP_SIZE32(chk_length); - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, - sizeof(*ch), (uint8_t *) & chunk_buf); - } - if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || - ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && - (contains_init_chunk == 0))) { - sctp_send_abort(m, iphlen, src, dst, sh, 0, cause, -#if defined(__FreeBSD__) && !defined(__Userspace__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - } -} - -/* - * check the inbound datagram to make sure there is not an abort inside it, - * if there is return 1, else return 0. - */ -int -sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtag) -{ - struct sctp_chunkhdr *ch; - struct sctp_init_chunk *init_chk, chunk_buf; - int offset; - unsigned int chk_length; - - offset = iphlen + sizeof(struct sctphdr); - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), - (uint8_t *) & chunk_buf); - while (ch != NULL) { - chk_length = ntohs(ch->chunk_length); - if (chk_length < sizeof(*ch)) { - /* packet is probably corrupt */ - break; - } - /* we seem to be ok, is it an abort? */ - if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) { - /* yep, tell them */ - return (1); - } - if ((ch->chunk_type == SCTP_INITIATION) || - (ch->chunk_type == SCTP_INITIATION_ACK)) { - /* need to update the Vtag */ - init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, - offset, sizeof(struct sctp_init_chunk), (uint8_t *) & chunk_buf); - if (init_chk != NULL) { - *vtag = ntohl(init_chk->init.initiate_tag); - } - } - /* Nope, move to the next chunk */ - offset += SCTP_SIZE32(chk_length); - ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, - sizeof(*ch), (uint8_t *) & chunk_buf); - } - return (0); -} - -/* - * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id - * set (i.e. it's 0) so, create this function to compare link local scopes - */ -#ifdef INET6 -uint32_t -sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2) -{ -#if defined(__Userspace__) - /*__Userspace__ Returning 1 here always */ -#endif -#if defined(SCTP_EMBEDDED_V6_SCOPE) - struct sockaddr_in6 a, b; - - /* save copies */ - a = *addr1; - b = *addr2; - - if (a.sin6_scope_id == 0) -#ifdef SCTP_KAME - if (sa6_recoverscope(&a)) { -#else - if (in6_recoverscope(&a, &a.sin6_addr, NULL)) { -#endif /* SCTP_KAME */ - /* can't get scope, so can't match */ - return (0); - } - if (b.sin6_scope_id == 0) -#ifdef SCTP_KAME - if (sa6_recoverscope(&b)) { -#else - if (in6_recoverscope(&b, &b.sin6_addr, NULL)) { -#endif /* SCTP_KAME */ - /* can't get scope, so can't match */ - return (0); - } - if (a.sin6_scope_id != b.sin6_scope_id) - return (0); -#else - if (addr1->sin6_scope_id != addr2->sin6_scope_id) - return (0); -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - - return (1); -} - -#if defined(SCTP_EMBEDDED_V6_SCOPE) -/* - * returns a sockaddr_in6 with embedded scope recovered and removed - */ -struct sockaddr_in6 * -sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store) -{ - /* check and strip embedded scope junk */ - if (addr->sin6_family == AF_INET6) { - if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) { - if (addr->sin6_scope_id == 0) { - *store = *addr; -#ifdef SCTP_KAME - if (!sa6_recoverscope(store)) { -#else - if (!in6_recoverscope(store, &store->sin6_addr, - NULL)) { -#endif /* SCTP_KAME */ - /* use the recovered scope */ - addr = store; - } - } else { - /* else, return the original "to" addr */ - in6_clearscope(&addr->sin6_addr); - } - } - } - return (addr); -} -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#endif - -/* - * are the two addresses the same? currently a "scopeless" check returns: 1 - * if same, 0 if not - */ -int -sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2) -{ - - /* must be valid */ - if (sa1 == NULL || sa2 == NULL) - return (0); - - /* must be the same family */ - if (sa1->sa_family != sa2->sa_family) - return (0); - - switch (sa1->sa_family) { -#ifdef INET6 - case AF_INET6: - { - /* IPv6 addresses */ - struct sockaddr_in6 *sin6_1, *sin6_2; - - sin6_1 = (struct sockaddr_in6 *)sa1; - sin6_2 = (struct sockaddr_in6 *)sa2; - return (SCTP6_ARE_ADDR_EQUAL(sin6_1, - sin6_2)); - } -#endif -#ifdef INET - case AF_INET: - { - /* IPv4 addresses */ - struct sockaddr_in *sin_1, *sin_2; - - sin_1 = (struct sockaddr_in *)sa1; - sin_2 = (struct sockaddr_in *)sa2; - return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr); - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn_1, *sconn_2; - - sconn_1 = (struct sockaddr_conn *)sa1; - sconn_2 = (struct sockaddr_conn *)sa2; - return (sconn_1->sconn_addr == sconn_2->sconn_addr); - } -#endif - default: - /* we don't do these... */ - return (0); - } -} - -void -sctp_print_address(struct sockaddr *sa) -{ -#ifdef INET6 -#if defined(__FreeBSD__) && !defined(__Userspace__) - char ip6buf[INET6_ADDRSTRLEN]; -#endif -#endif - - switch (sa->sa_family) { -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)sa; -#if defined(__Userspace__) - SCTP_PRINTF("IPv6 address: %x:%x:%x:%x:%x:%x:%x:%x:port:%d scope:%u\n", - ntohs(sin6->sin6_addr.s6_addr16[0]), - ntohs(sin6->sin6_addr.s6_addr16[1]), - ntohs(sin6->sin6_addr.s6_addr16[2]), - ntohs(sin6->sin6_addr.s6_addr16[3]), - ntohs(sin6->sin6_addr.s6_addr16[4]), - ntohs(sin6->sin6_addr.s6_addr16[5]), - ntohs(sin6->sin6_addr.s6_addr16[6]), - ntohs(sin6->sin6_addr.s6_addr16[7]), - ntohs(sin6->sin6_port), - sin6->sin6_scope_id); -#else -#if defined(__FreeBSD__) && !defined(__Userspace__) - SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", - ip6_sprintf(ip6buf, &sin6->sin6_addr), - ntohs(sin6->sin6_port), - sin6->sin6_scope_id); -#else - SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", - ip6_sprintf(&sin6->sin6_addr), - ntohs(sin6->sin6_port), - sin6->sin6_scope_id); -#endif -#endif - break; - } -#endif -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - unsigned char *p; - - sin = (struct sockaddr_in *)sa; - p = (unsigned char *)&sin->sin_addr; - SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n", - p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); - break; - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn; - - sconn = (struct sockaddr_conn *)sa; - SCTP_PRINTF("AF_CONN address: %p\n", sconn->sconn_addr); - break; - } -#endif - default: - SCTP_PRINTF("?\n"); - break; - } -} - -void -sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, - struct sctp_inpcb *new_inp, - struct sctp_tcb *stcb, - int waitflags) -{ - /* - * go through our old INP and pull off any control structures that - * belong to stcb and move then to the new inp. - */ - struct socket *old_so, *new_so; - struct sctp_queued_to_read *control, *nctl; - struct sctp_readhead tmp_queue; - struct mbuf *m; -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) - int error = 0; -#endif - - old_so = old_inp->sctp_socket; - new_so = new_inp->sctp_socket; - TAILQ_INIT(&tmp_queue); -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) -#if defined(__FreeBSD__) - error = SOCK_IO_RECV_LOCK(old_so, waitflags); -#else - error = sblock(&old_so->so_rcv, waitflags); -#endif - if (error) { - /* Gak, can't get I/O lock, we have a problem. - * data will be left stranded.. and we - * don't dare look at it since the - * other thread may be reading something. - * Oh well, its a screwed up app that does - * a peeloff OR a accept while reading - * from the main socket... actually its - * only the peeloff() case, since I think - * read will fail on a listening socket.. - */ - return; - } -#endif - /* lock the socket buffers */ - SCTP_INP_READ_LOCK(old_inp); - TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) { - /* Pull off all for out target stcb */ - if (control->stcb == stcb) { - /* remove it we want it */ - TAILQ_REMOVE(&old_inp->read_queue, control, next); - TAILQ_INSERT_TAIL(&tmp_queue, control, next); - m = control->data; - while (m) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE,SCTP_BUF_LEN(m)); - } - sctp_sbfree(control, stcb, &old_so->so_rcv, m); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - m = SCTP_BUF_NEXT(m); - } - } - } - SCTP_INP_READ_UNLOCK(old_inp); - /* Remove the recv-lock on the old socket */ -#if defined(__APPLE__) && !defined(__Userspace__) - sbunlock(&old_so->so_rcv, 1); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - SOCK_IO_RECV_UNLOCK(old_so); -#endif - /* Now we move them over to the new socket buffer */ - SCTP_INP_READ_LOCK(new_inp); - TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) { - TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next); - m = control->data; - while (m) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); - } - sctp_sballoc(stcb, &new_so->so_rcv, m); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - m = SCTP_BUF_NEXT(m); - } - } - SCTP_INP_READ_UNLOCK(new_inp); -} - -void -sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - int so_locked -#if !(defined(__APPLE__) && !defined(__Userspace__)) - SCTP_UNUSED -#endif -) -{ - if ((inp != NULL) && - (inp->sctp_socket != NULL) && - (((inp->sctp_flags & (SCTP_PCB_FLAGS_TCPTYPE | SCTP_PCB_FLAGS_IN_TCPPOOL)) == 0) || - !SCTP_IS_LISTENING(inp))) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(inp); - if (!so_locked) { - if (stcb) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_SOCKET_LOCK(so, 1); - if (stcb) { - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } - } -#endif - sctp_sorwakeup(inp, inp->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif - } -} -#if defined(__Userspace__) - -void -sctp_invoke_recv_callback(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_queued_to_read *control, - int inp_read_lock_held) -{ - uint32_t pd_point, length; - - if ((inp->recv_callback == NULL) || - (stcb == NULL) || - (stcb->sctp_socket == NULL)) { - return; - } - - length = control->length; - if (stcb != NULL && stcb->sctp_socket != NULL) { - pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, - stcb->sctp_ep->partial_delivery_point); - } else { - pd_point = inp->partial_delivery_point; - } - if ((control->end_added == 1) || (length >= pd_point)) { - struct socket *so; - struct mbuf *m; - char *buffer; - struct sctp_rcvinfo rcv; - union sctp_sockstore addr; - int flags; - - if ((buffer = malloc(length)) == NULL) { - return; - } - if (inp_read_lock_held == 0) { - SCTP_INP_READ_LOCK(inp); - } - so = stcb->sctp_socket; - for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { - sctp_sbfree(control, control->stcb, &so->so_rcv, m); - } - m_copydata(control->data, 0, length, buffer); - memset(&rcv, 0, sizeof(struct sctp_rcvinfo)); - rcv.rcv_sid = control->sinfo_stream; - rcv.rcv_ssn = (uint16_t)control->mid; - rcv.rcv_flags = control->sinfo_flags; - rcv.rcv_ppid = control->sinfo_ppid; - rcv.rcv_tsn = control->sinfo_tsn; - rcv.rcv_cumtsn = control->sinfo_cumtsn; - rcv.rcv_context = control->sinfo_context; - rcv.rcv_assoc_id = control->sinfo_assoc_id; - memset(&addr, 0, sizeof(union sctp_sockstore)); - switch (control->whoFrom->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - addr.sin = control->whoFrom->ro._l_addr.sin; - break; -#endif -#ifdef INET6 - case AF_INET6: - addr.sin6 = control->whoFrom->ro._l_addr.sin6; - break; -#endif - case AF_CONN: - addr.sconn = control->whoFrom->ro._l_addr.sconn; - break; - default: - addr.sa = control->whoFrom->ro._l_addr.sa; - break; - } - flags = 0; - if (control->end_added == 1) { - flags |= MSG_EOR; - } - if (control->spec_flags & M_NOTIFICATION) { - flags |= MSG_NOTIFICATION; - } - sctp_m_freem(control->data); - control->data = NULL; - control->tail_mbuf = NULL; - control->length = 0; - if (control->end_added) { - TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next); - control->on_read_q = 0; - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; - sctp_free_a_readq(stcb, control); - } - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - if (inp_read_lock_held == 0) { - SCTP_INP_READ_UNLOCK(inp); - } - inp->recv_callback(so, addr, buffer, length, rcv, flags, inp->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } -} -#endif - -void -sctp_add_to_readq(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_queued_to_read *control, - struct sockbuf *sb, - int end, - int inp_read_lock_held, - int so_locked) -{ - /* - * Here we must place the control on the end of the socket read - * queue AND increment sb_cc so that select will work properly on - * read. - */ - struct mbuf *m, *prev = NULL; - - if (inp == NULL) { - /* Gak, TSNH!! */ -#ifdef INVARIANTS - panic("Gak, inp NULL on add_to_readq"); -#endif - return; - } -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(inp)); - } else { - sctp_unlock_assert(SCTP_INP_SO(inp)); - } -#endif - if (inp_read_lock_held == SCTP_READ_LOCK_NOT_HELD) { - SCTP_INP_READ_LOCK(inp); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { - if (!control->on_strm_q) { - sctp_free_remote_addr(control->whoFrom); - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_free_a_readq(stcb, control); - } - if (inp_read_lock_held == SCTP_READ_LOCK_NOT_HELD) { - SCTP_INP_READ_UNLOCK(inp); - } - return; - } - if ((control->spec_flags & M_NOTIFICATION) == 0) { - atomic_add_int(&inp->total_recvs, 1); - if (!control->do_not_ref_stcb) { - atomic_add_int(&stcb->total_recvs, 1); - } - } - m = control->data; - control->held_length = 0; - control->length = 0; - while (m != NULL) { - if (SCTP_BUF_LEN(m) == 0) { - /* Skip mbufs with NO length */ - if (prev == NULL) { - /* First one */ - control->data = sctp_m_free(m); - m = control->data; - } else { - SCTP_BUF_NEXT(prev) = sctp_m_free(m); - m = SCTP_BUF_NEXT(prev); - } - if (m == NULL) { - control->tail_mbuf = prev; - } - continue; - } - prev = m; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); - } - sctp_sballoc(stcb, sb, m); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - atomic_add_int(&control->length, SCTP_BUF_LEN(m)); - m = SCTP_BUF_NEXT(m); - } - if (prev != NULL) { - control->tail_mbuf = prev; - } else { - /* Everything got collapsed out?? */ - if (!control->on_strm_q) { - sctp_free_remote_addr(control->whoFrom); - sctp_free_a_readq(stcb, control); - } - if (inp_read_lock_held == 0) - SCTP_INP_READ_UNLOCK(inp); - return; - } - if (end) { - control->end_added = 1; - } - TAILQ_INSERT_TAIL(&inp->read_queue, control, next); - control->on_read_q = 1; -#if defined(__Userspace__) - sctp_invoke_recv_callback(inp, stcb, control, SCTP_READ_LOCK_HELD); -#endif - if ((inp != NULL) && (inp->sctp_socket != NULL)) { - sctp_wakeup_the_read_socket(inp, stcb, so_locked); - } - if (inp_read_lock_held == SCTP_READ_LOCK_NOT_HELD) { - SCTP_INP_READ_UNLOCK(inp); - } -} - -/*************HOLD THIS COMMENT FOR PATCH FILE OF - *************ALTERNATE ROUTING CODE - */ - -/*************HOLD THIS COMMENT FOR END OF PATCH FILE OF - *************ALTERNATE ROUTING CODE - */ - -struct mbuf * -sctp_generate_cause(uint16_t code, char *info) -{ - struct mbuf *m; - struct sctp_gen_error_cause *cause; - size_t info_len; - uint16_t len; - - if ((code == 0) || (info == NULL)) { - return (NULL); - } - info_len = strlen(info); - if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) { - return (NULL); - } - len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len); - m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); - if (m != NULL) { - SCTP_BUF_LEN(m) = len; - cause = mtod(m, struct sctp_gen_error_cause *); - cause->code = htons(code); - cause->length = htons(len); - memcpy(cause->info, info, info_len); - } - return (m); -} - -struct mbuf * -sctp_generate_no_user_data_cause(uint32_t tsn) -{ - struct mbuf *m; - struct sctp_error_no_user_data *no_user_data_cause; - uint16_t len; - - len = (uint16_t)sizeof(struct sctp_error_no_user_data); - m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); - if (m != NULL) { - SCTP_BUF_LEN(m) = len; - no_user_data_cause = mtod(m, struct sctp_error_no_user_data *); - no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA); - no_user_data_cause->cause.length = htons(len); - no_user_data_cause->tsn = htonl(tsn); - } - return (m); -} - -void -sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_tmit_chunk *tp1, int chk_cnt) -{ - if (tp1->data == NULL) { - return; - } - atomic_subtract_int(&asoc->chunks_on_out_queue, chk_cnt); -#ifdef SCTP_MBCNT_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { - sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, - asoc->total_output_queue_size, - tp1->book_size, - 0, - tp1->mbcnt); - } -#endif - if (asoc->total_output_queue_size >= tp1->book_size) { - atomic_subtract_int(&asoc->total_output_queue_size, tp1->book_size); - } else { - asoc->total_output_queue_size = 0; - } - if ((stcb->sctp_socket != NULL) && - (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { - SCTP_SB_DECR(&stcb->sctp_socket->so_snd, tp1->book_size); - } -} - -int -sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, - uint8_t sent, int so_locked) -{ - struct sctp_stream_out *strq; - struct sctp_tmit_chunk *chk = NULL, *tp2; - struct sctp_stream_queue_pending *sp; - uint32_t mid; - uint16_t sid; - uint8_t foundeom = 0; - int ret_sz = 0; - int notdone; - int do_wakeup_routine = 0; - -#if defined(__APPLE__) && !defined(__Userspace__) - if (so_locked) { - sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } else { - sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); - } -#endif - SCTP_TCB_LOCK_ASSERT(stcb); - - sid = tp1->rec.data.sid; - mid = tp1->rec.data.mid; - if (sent || ((tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0)) { - stcb->asoc.abandoned_sent[0]++; - stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; - stcb->asoc.strmout[sid].abandoned_sent[0]++; -#if defined(SCTP_DETAILED_STR_STATS) - stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; -#endif - } else { - stcb->asoc.abandoned_unsent[0]++; - stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; - stcb->asoc.strmout[sid].abandoned_unsent[0]++; -#if defined(SCTP_DETAILED_STR_STATS) - stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; -#endif - } - do { - ret_sz += tp1->book_size; - if (tp1->data != NULL) { - if (tp1->sent < SCTP_DATAGRAM_RESEND) { - sctp_flight_size_decrease(tp1); - sctp_total_flight_decrease(stcb, tp1); - } - sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); - stcb->asoc.peers_rwnd += tp1->send_size; - stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); - if (sent) { - sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); - } else { - sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); - } - if (tp1->data) { - sctp_m_freem(tp1->data); - tp1->data = NULL; - } - do_wakeup_routine = 1; - if (PR_SCTP_BUF_ENABLED(tp1->flags)) { - stcb->asoc.sent_queue_cnt_removeable--; - } - } - tp1->sent = SCTP_FORWARD_TSN_SKIP; - if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == - SCTP_DATA_NOT_FRAG) { - /* not frag'ed we ae done */ - notdone = 0; - foundeom = 1; - } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - /* end of frag, we are done */ - notdone = 0; - foundeom = 1; - } else { - /* - * Its a begin or middle piece, we must mark all of - * it - */ - notdone = 1; - tp1 = TAILQ_NEXT(tp1, sctp_next); - } - } while (tp1 && notdone); - if (foundeom == 0) { - /* - * The multi-part message was scattered across the send and - * sent queue. - */ - TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) { - if ((tp1->rec.data.sid != sid) || - (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) { - break; - } - /* save to chk in case we have some on stream out - * queue. If so and we have an un-transmitted one - * we don't have to fudge the TSN. - */ - chk = tp1; - ret_sz += tp1->book_size; - sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); - if (sent) { - sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); - } else { - sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); - } - if (tp1->data) { - sctp_m_freem(tp1->data); - tp1->data = NULL; - } - /* No flight involved here book the size to 0 */ - tp1->book_size = 0; - if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - foundeom = 1; - } - do_wakeup_routine = 1; - tp1->sent = SCTP_FORWARD_TSN_SKIP; - TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next); - /* on to the sent queue so we can wait for it to be passed by. */ - TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1, - sctp_next); - stcb->asoc.send_queue_cnt--; - stcb->asoc.sent_queue_cnt++; - } - } - if (foundeom == 0) { - /* - * Still no eom found. That means there - * is stuff left on the stream out queue.. yuck. - */ - strq = &stcb->asoc.strmout[sid]; - sp = TAILQ_FIRST(&strq->outqueue); - if (sp != NULL) { - sp->discard_rest = 1; - /* - * We may need to put a chunk on the - * queue that holds the TSN that - * would have been sent with the LAST - * bit. - */ - if (chk == NULL) { - /* Yep, we have to */ - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* we are hosed. All we can - * do is nothing.. which will - * cause an abort if the peer is - * paying attention. - */ - goto oh_well; - } - memset(chk, 0, sizeof(*chk)); - chk->rec.data.rcv_flags = 0; - chk->sent = SCTP_FORWARD_TSN_SKIP; - chk->asoc = &stcb->asoc; - if (stcb->asoc.idata_supported == 0) { - if (sp->sinfo_flags & SCTP_UNORDERED) { - chk->rec.data.mid = 0; - } else { - chk->rec.data.mid = strq->next_mid_ordered; - } - } else { - if (sp->sinfo_flags & SCTP_UNORDERED) { - chk->rec.data.mid = strq->next_mid_unordered; - } else { - chk->rec.data.mid = strq->next_mid_ordered; - } - } - chk->rec.data.sid = sp->sid; - chk->rec.data.ppid = sp->ppid; - chk->rec.data.context = sp->context; - chk->flags = sp->act_flags; - chk->whoTo = NULL; -#if defined(__FreeBSD__) && !defined(__Userspace__) - chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); -#else - chk->rec.data.tsn = stcb->asoc.sending_seq++; -#endif - strq->chunks_on_queues++; - TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); - stcb->asoc.sent_queue_cnt++; - stcb->asoc.pr_sctp_cnt++; - } - chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; - if (sp->sinfo_flags & SCTP_UNORDERED) { - chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED; - } - if (stcb->asoc.idata_supported == 0) { - if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) { - strq->next_mid_ordered++; - } - } else { - if (sp->sinfo_flags & SCTP_UNORDERED) { - strq->next_mid_unordered++; - } else { - strq->next_mid_ordered++; - } - } - oh_well: - if (sp->data) { - /* Pull any data to free up the SB and - * allow sender to "add more" while we - * will throw away :-) - */ - sctp_free_spbufspace(stcb, &stcb->asoc, sp); - ret_sz += sp->length; - do_wakeup_routine = 1; - sp->some_taken = 1; - sctp_m_freem(sp->data); - sp->data = NULL; - sp->tail_mbuf = NULL; - sp->length = 0; - } - } - } - if (do_wakeup_routine) { -#if defined(__APPLE__) && !defined(__Userspace__) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - if (!so_locked) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return (ret_sz); - } - } -#endif - sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) && !defined(__Userspace__) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif - } - return (ret_sz); -} - -/* - * checks to see if the given address, sa, is one that is currently known by - * the kernel note: can't distinguish the same address on multiple interfaces - * and doesn't handle multiple addresses with different zone/scope id's note: - * ifa_ifwithaddr() compares the entire sockaddr struct - */ -struct sctp_ifa * -sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, - int holds_lock) -{ - struct sctp_laddr *laddr; - - if (holds_lock == 0) { - SCTP_INP_RLOCK(inp); - } - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa == NULL) - continue; - if (addr->sa_family != laddr->ifa->address.sa.sa_family) - continue; -#ifdef INET - if (addr->sa_family == AF_INET) { - if (((struct sockaddr_in *)addr)->sin_addr.s_addr == - laddr->ifa->address.sin.sin_addr.s_addr) { - /* found him. */ - break; - } - } -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, - &laddr->ifa->address.sin6)) { - /* found him. */ - break; - } - } -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - if (((struct sockaddr_conn *)addr)->sconn_addr == laddr->ifa->address.sconn.sconn_addr) { - /* found him. */ - break; - } - } -#endif - } - if (holds_lock == 0) { - SCTP_INP_RUNLOCK(inp); - } - if (laddr != NULL) { - return (laddr->ifa); - } else { - return (NULL); - } -} - -uint32_t -sctp_get_ifa_hash_val(struct sockaddr *addr) -{ - switch (addr->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - uint32_t hash_of_addr; - - sin6 = (struct sockaddr_in6 *)addr; -#if !defined(_WIN32) && !(defined(__FreeBSD__) && defined(__Userspace__)) && !defined(__APPLE__) - hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + - sin6->sin6_addr.s6_addr32[1] + - sin6->sin6_addr.s6_addr32[2] + - sin6->sin6_addr.s6_addr32[3]); -#else - hash_of_addr = (((uint32_t *)&sin6->sin6_addr)[0] + - ((uint32_t *)&sin6->sin6_addr)[1] + - ((uint32_t *)&sin6->sin6_addr)[2] + - ((uint32_t *)&sin6->sin6_addr)[3]); -#endif - hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); - return (hash_of_addr); - } -#endif -#if defined(__Userspace__) - case AF_CONN: - { - struct sockaddr_conn *sconn; - uintptr_t temp; - - sconn = (struct sockaddr_conn *)addr; - temp = (uintptr_t)sconn->sconn_addr; - return ((uint32_t)(temp ^ (temp >> 16))); - } -#endif - default: - break; - } - return (0); -} - -struct sctp_ifa * -sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) -{ - struct sctp_ifa *sctp_ifap; - struct sctp_vrf *vrf; - struct sctp_ifalist *hash_head; - uint32_t hash_of_addr; - - if (holds_lock == 0) { - SCTP_IPI_ADDR_RLOCK(); - } else { - SCTP_IPI_ADDR_LOCK_ASSERT(); - } - - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - if (holds_lock == 0) - SCTP_IPI_ADDR_RUNLOCK(); - return (NULL); - } - - hash_of_addr = sctp_get_ifa_hash_val(addr); - - hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; - if (hash_head == NULL) { - SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ", - hash_of_addr, (uint32_t)vrf->vrf_addr_hashmark, - (uint32_t)(hash_of_addr & vrf->vrf_addr_hashmark)); - sctp_print_address(addr); - SCTP_PRINTF("No such bucket for address\n"); - if (holds_lock == 0) - SCTP_IPI_ADDR_RUNLOCK(); - - return (NULL); - } - LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { - if (addr->sa_family != sctp_ifap->address.sa.sa_family) - continue; -#ifdef INET - if (addr->sa_family == AF_INET) { - if (((struct sockaddr_in *)addr)->sin_addr.s_addr == - sctp_ifap->address.sin.sin_addr.s_addr) { - /* found him. */ - break; - } - } -#endif -#ifdef INET6 - if (addr->sa_family == AF_INET6) { - if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, - &sctp_ifap->address.sin6)) { - /* found him. */ - break; - } - } -#endif -#if defined(__Userspace__) - if (addr->sa_family == AF_CONN) { - if (((struct sockaddr_conn *)addr)->sconn_addr == sctp_ifap->address.sconn.sconn_addr) { - /* found him. */ - break; - } - } -#endif - } - if (holds_lock == 0) - SCTP_IPI_ADDR_RUNLOCK(); - return (sctp_ifap); -} - -static void -sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock, - uint32_t rwnd_req) -{ - /* User pulled some data, do we need a rwnd update? */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - int r_unlocked = 0; - uint32_t dif, rwnd; - struct socket *so = NULL; - - if (stcb == NULL) - return; - - atomic_add_int(&stcb->asoc.refcnt, 1); - - if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || - (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | SCTP_STATE_SHUTDOWN_RECEIVED))) { - /* Pre-check If we are freeing no update */ - goto no_lock; - } - SCTP_INP_INCR_REF(stcb->sctp_ep); - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - goto out; - } - so = stcb->sctp_socket; - if (so == NULL) { - goto out; - } - atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); - /* Have you have freed enough to look */ - *freed_so_far = 0; - /* Yep, its worth a look and the lock overhead */ - - /* Figure out what the rwnd would be */ - rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); - if (rwnd >= stcb->asoc.my_last_reported_rwnd) { - dif = rwnd - stcb->asoc.my_last_reported_rwnd; - } else { - dif = 0; - } - if (dif >= rwnd_req) { - if (hold_rlock) { - SCTP_INP_READ_UNLOCK(stcb->sctp_ep); - r_unlocked = 1; - } - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - /* - * One last check before we allow the guy possibly - * to get in. There is a race, where the guy has not - * reached the gate. In that case - */ - goto out; - } - SCTP_TCB_LOCK(stcb); - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - /* No reports here */ - SCTP_TCB_UNLOCK(stcb); - goto out; - } - SCTP_STAT_INCR(sctps_wu_sacks_sent); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_send_sack(stcb, SCTP_SO_LOCKED); - - sctp_chunk_output(stcb->sctp_ep, stcb, - SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); - /* make sure no timer is running */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTPUTIL + SCTP_LOC_6); - SCTP_TCB_UNLOCK(stcb); - } else { - /* Update how much we have pending */ - stcb->freed_by_sorcv_sincelast = dif; - } - out: - if (so && r_unlocked && hold_rlock) { - SCTP_INP_READ_LOCK(stcb->sctp_ep); - } - - SCTP_INP_DECR_REF(stcb->sctp_ep); - no_lock: - atomic_subtract_int(&stcb->asoc.refcnt, 1); - return; -} - -int -sctp_sorecvmsg(struct socket *so, - struct uio *uio, - struct mbuf **mp, - struct sockaddr *from, - int fromlen, - int *msg_flags, - struct sctp_sndrcvinfo *sinfo, - int filling_sinfo) -{ - /* - * MSG flags we will look at MSG_DONTWAIT - non-blocking IO. - * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy - * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ?? - * On the way out we may send out any combination of: - * MSG_NOTIFICATION MSG_EOR - * - */ - struct sctp_inpcb *inp = NULL; - ssize_t my_len = 0; - ssize_t cp_len = 0; - int error = 0; - struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; - struct mbuf *m = NULL; - struct sctp_tcb *stcb = NULL; - int wakeup_read_socket = 0; - int freecnt_applied = 0; - int out_flags = 0, in_flags = 0; - int block_allowed = 1; - uint32_t freed_so_far = 0; - ssize_t copied_so_far = 0; - int in_eeor_mode = 0; - int no_rcv_needed = 0; - uint32_t rwnd_req = 0; - int hold_sblock = 0; - int hold_rlock = 0; - ssize_t slen = 0; - uint32_t held_length = 0; -#if defined(__FreeBSD__) && !defined(__Userspace__) - int sockbuf_lock = 0; -#endif - - if (uio == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - return (EINVAL); - } - - if (msg_flags) { - in_flags = *msg_flags; - if (in_flags & MSG_PEEK) - SCTP_STAT_INCR(sctps_read_peeks); - } else { - in_flags = 0; - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - slen = uio->uio_resid; -#else - slen = uio_resid(uio); -#endif -#else - slen = uio->uio_resid; -#endif - - /* Pull in and set up our int flags */ - if (in_flags & MSG_OOB) { - /* Out of band's NOT supported */ - return (EOPNOTSUPP); - } - if ((in_flags & MSG_PEEK) && (mp != NULL)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - return (EINVAL); - } - if ((in_flags & (MSG_DONTWAIT -#if defined(__FreeBSD__) && !defined(__Userspace__) - | MSG_NBIO -#endif - )) || - SCTP_SO_IS_NBIO(so)) { - block_allowed = 0; - } - /* setup the endpoint */ - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); - return (EFAULT); - } - rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); - /* Must be at least a MTU's worth */ - if (rwnd_req < SCTP_MIN_RWND) - rwnd_req = SCTP_MIN_RWND; - in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, SCTP_SBAVAIL(&so->so_rcv), uio->uio_resid); -#else - sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, SCTP_SBAVAIL(&so->so_rcv), uio_resid(uio)); -#endif -#else - sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, SCTP_SBAVAIL(&so->so_rcv), (uint32_t)uio->uio_resid); -#endif - } -#if defined(__Userspace__) - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; -#endif - if (SCTP_BASE_SYSCTL(sctp_logging_level) &SCTP_RECV_RWND_LOGGING_ENABLE) { -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, SCTP_SBAVAIL(&so->so_rcv), uio->uio_resid); -#else - sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, SCTP_SBAVAIL(&so->so_rcv), uio_resid(uio)); -#endif -#else - sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, SCTP_SBAVAIL(&so->so_rcv), (uint32_t)uio->uio_resid); -#endif - } - -#if defined(__APPLE__) && !defined(__Userspace__) - error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags)); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = SOCK_IO_RECV_LOCK(so, SBLOCKWAIT(in_flags)); -#endif - if (error) { - goto release_unlocked; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - sockbuf_lock = 1; -#endif - restart: -#if defined(__Userspace__) - if (hold_sblock == 0) { - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; - } -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - sbunlock(&so->so_rcv, 1); -#endif - - restart_nosblocks: - if (hold_sblock == 0) { - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - goto out; - } -#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__) - if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && SCTP_SBAVAIL(&so->so_rcv) == 0) { -#else - if ((so->so_state & SS_CANTRCVMORE) && SCTP_SBAVAIL(&so->so_rcv) == 0) { -#endif - if (so->so_error) { - error = so->so_error; - if ((in_flags & MSG_PEEK) == 0) - so->so_error = 0; - goto out; - } else { - if (SCTP_SBAVAIL(&so->so_rcv) == 0) { - /* indicate EOF */ - error = 0; - goto out; - } - } - } - if (SCTP_SBAVAIL(&so->so_rcv) <= held_length) { - if (so->so_error) { - error = so->so_error; - if ((in_flags & MSG_PEEK) == 0) { - so->so_error = 0; - } - goto out; - } - if ((SCTP_SBAVAIL(&so->so_rcv) == 0) && - ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { - /* For active open side clear flags for re-use - * passive open is blocked by connect. - */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { - /* You were aborted, passive side always hits here */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); - error = ECONNRESET; - } - so->so_state &= ~(SS_ISCONNECTING | - SS_ISDISCONNECTING | - SS_ISCONFIRMING | - SS_ISCONNECTED); - if (error == 0) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); - error = ENOTCONN; - } - } - goto out; - } - } - if (block_allowed) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = sbwait(so, SO_RCV); -#else - error = sbwait(&so->so_rcv); -#endif - if (error) { - goto out; - } - held_length = 0; - goto restart_nosblocks; - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); - error = EWOULDBLOCK; - goto out; - } - } - if (hold_sblock == 1) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } -#if defined(__APPLE__) && !defined(__Userspace__) - error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags)); -#endif - /* we possibly have data we can read */ - /*sa_ignore FREED_MEMORY*/ - control = TAILQ_FIRST(&inp->read_queue); - if (control == NULL) { - /* This could be happening since - * the appender did the increment but as not - * yet did the tailq insert onto the read_queue - */ - if (hold_rlock == 0) { - SCTP_INP_READ_LOCK(inp); - } - control = TAILQ_FIRST(&inp->read_queue); - if ((control == NULL) && (SCTP_SBAVAIL(&so->so_rcv) > 0)) { -#ifdef INVARIANTS - panic("Huh, its non zero and nothing on control?"); -#endif - SCTP_SB_CLEAR(so->so_rcv); - } - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - goto restart; - } - - if ((control->length == 0) && - (control->do_not_ref_stcb)) { - /* Clean up code for freeing assoc that left behind a pdapi.. - * maybe a peer in EEOR that just closed after sending and - * never indicated a EOR. - */ - if (hold_rlock == 0) { - hold_rlock = 1; - SCTP_INP_READ_LOCK(inp); - } - control->held_length = 0; - if (control->data) { - /* Hmm there is data here .. fix */ - struct mbuf *m_tmp; - int cnt = 0; - m_tmp = control->data; - while (m_tmp) { - cnt += SCTP_BUF_LEN(m_tmp); - if (SCTP_BUF_NEXT(m_tmp) == NULL) { - control->tail_mbuf = m_tmp; - control->end_added = 1; - } - m_tmp = SCTP_BUF_NEXT(m_tmp); - } - control->length = cnt; - } else { - /* remove it */ - TAILQ_REMOVE(&inp->read_queue, control, next); - /* Add back any hidden data */ - sctp_free_remote_addr(control->whoFrom); - sctp_free_a_readq(stcb, control); - } - if (hold_rlock) { - hold_rlock = 0; - SCTP_INP_READ_UNLOCK(inp); - } - goto restart; - } - if ((control->length == 0) && - (control->end_added == 1)) { - /* Do we also need to check for (control->pdapi_aborted == 1)? */ - if (hold_rlock == 0) { - hold_rlock = 1; - SCTP_INP_READ_LOCK(inp); - } - TAILQ_REMOVE(&inp->read_queue, control, next); - if (control->data) { -#ifdef INVARIANTS - panic("control->data not null but control->length == 0"); -#else - SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n"); - sctp_m_freem(control->data); - control->data = NULL; -#endif - } - if (control->aux_data) { - sctp_m_free (control->aux_data); - control->aux_data = NULL; - } -#ifdef INVARIANTS - if (control->on_strm_q) { - panic("About to free ctl:%p so:%p and its in %d", - control, so, control->on_strm_q); - } -#endif - sctp_free_remote_addr(control->whoFrom); - sctp_free_a_readq(stcb, control); - if (hold_rlock) { - hold_rlock = 0; - SCTP_INP_READ_UNLOCK(inp); - } - goto restart; - } - if (control->length == 0) { - if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && - (filling_sinfo)) { - /* find a more suitable one then this */ - ctl = TAILQ_NEXT(control, next); - while (ctl) { - if ((ctl->stcb != control->stcb) && (ctl->length) && - (ctl->some_taken || - (ctl->spec_flags & M_NOTIFICATION) || - ((ctl->do_not_ref_stcb == 0) && - (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) - ) { - /*- - * If we have a different TCB next, and there is data - * present. If we have already taken some (pdapi), OR we can - * ref the tcb and no delivery as started on this stream, we - * take it. Note we allow a notification on a different - * assoc to be delivered.. - */ - control = ctl; - goto found_one; - } else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) && - (ctl->length) && - ((ctl->some_taken) || - ((ctl->do_not_ref_stcb == 0) && - ((ctl->spec_flags & M_NOTIFICATION) == 0) && - (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) { - /*- - * If we have the same tcb, and there is data present, and we - * have the strm interleave feature present. Then if we have - * taken some (pdapi) or we can refer to tht tcb AND we have - * not started a delivery for this stream, we can take it. - * Note we do NOT allow a notification on the same assoc to - * be delivered. - */ - control = ctl; - goto found_one; - } - ctl = TAILQ_NEXT(ctl, next); - } - } - /* - * if we reach here, not suitable replacement is available - * fragment interleave is NOT on. So stuff the sb_cc - * into the our held count, and its time to sleep again. - */ - held_length = SCTP_SBAVAIL(&so->so_rcv); - control->held_length = SCTP_SBAVAIL(&so->so_rcv); - goto restart; - } - /* Clear the held length since there is something to read */ - control->held_length = 0; - found_one: - /* - * If we reach here, control has a some data for us to read off. - * Note that stcb COULD be NULL. - */ - if (hold_rlock == 0) { - hold_rlock = 1; - SCTP_INP_READ_LOCK(inp); - } - control->some_taken++; - stcb = control->stcb; - if (stcb) { - if ((control->do_not_ref_stcb == 0) && - (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { - if (freecnt_applied == 0) - stcb = NULL; - } else if (control->do_not_ref_stcb == 0) { - /* you can't free it on me please */ - /* - * The lock on the socket buffer protects us so the - * free code will stop. But since we used the socketbuf - * lock and the sender uses the tcb_lock to increment, - * we need to use the atomic add to the refcnt - */ - if (freecnt_applied) { -#ifdef INVARIANTS - panic("refcnt already incremented"); -#else - SCTP_PRINTF("refcnt already incremented?\n"); -#endif - } else { - atomic_add_int(&stcb->asoc.refcnt, 1); - freecnt_applied = 1; - } - /* - * Setup to remember how much we have not yet told - * the peer our rwnd has opened up. Note we grab - * the value from the tcb from last time. - * Note too that sack sending clears this when a sack - * is sent, which is fine. Once we hit the rwnd_req, - * we then will go to the sctp_user_rcvd() that will - * not lock until it KNOWs it MUST send a WUP-SACK. - */ - freed_so_far = (uint32_t)stcb->freed_by_sorcv_sincelast; - stcb->freed_by_sorcv_sincelast = 0; - } - } - if (stcb && - ((control->spec_flags & M_NOTIFICATION) == 0) && - control->do_not_ref_stcb == 0) { - stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; - } - - /* First lets get off the sinfo and sockaddr info */ - if ((sinfo != NULL) && (filling_sinfo != 0)) { - sinfo->sinfo_stream = control->sinfo_stream; - sinfo->sinfo_ssn = (uint16_t)control->mid; - sinfo->sinfo_flags = control->sinfo_flags; - sinfo->sinfo_ppid = control->sinfo_ppid; - sinfo->sinfo_context =control->sinfo_context; - sinfo->sinfo_timetolive = control->sinfo_timetolive; - sinfo->sinfo_tsn = control->sinfo_tsn; - sinfo->sinfo_cumtsn = control->sinfo_cumtsn; - sinfo->sinfo_assoc_id = control->sinfo_assoc_id; - nxt = TAILQ_NEXT(control, next); - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { - struct sctp_extrcvinfo *s_extra; - s_extra = (struct sctp_extrcvinfo *)sinfo; - if ((nxt) && - (nxt->length)) { - s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL; - if (nxt->sinfo_flags & SCTP_UNORDERED) { - s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED; - } - if (nxt->spec_flags & M_NOTIFICATION) { - s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION; - } - s_extra->serinfo_next_aid = nxt->sinfo_assoc_id; - s_extra->serinfo_next_length = nxt->length; - s_extra->serinfo_next_ppid = nxt->sinfo_ppid; - s_extra->serinfo_next_stream = nxt->sinfo_stream; - if (nxt->tail_mbuf != NULL) { - if (nxt->end_added) { - s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE; - } - } - } else { - /* we explicitly 0 this, since the memcpy got - * some other things beyond the older sinfo_ - * that is on the control's structure :-D - */ - nxt = NULL; - s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; - s_extra->serinfo_next_aid = 0; - s_extra->serinfo_next_length = 0; - s_extra->serinfo_next_ppid = 0; - s_extra->serinfo_next_stream = 0; - } - } - /* - * update off the real current cum-ack, if we have an stcb. - */ - if ((control->do_not_ref_stcb == 0) && stcb) - sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; - /* - * mask off the high bits, we keep the actual chunk bits in - * there. - */ - sinfo->sinfo_flags &= 0x00ff; - if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { - sinfo->sinfo_flags |= SCTP_UNORDERED; - } - } -#ifdef SCTP_ASOCLOG_OF_TSNS - { - int index, newindex; - struct sctp_pcbtsn_rlog *entry; - do { - index = inp->readlog_index; - newindex = index + 1; - if (newindex >= SCTP_READ_LOG_SIZE) { - newindex = 0; - } - } while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0); - entry = &inp->readlog[index]; - entry->vtag = control->sinfo_assoc_id; - entry->strm = control->sinfo_stream; - entry->seq = (uint16_t)control->mid; - entry->sz = control->length; - entry->flgs = control->sinfo_flags; - } -#endif - if ((fromlen > 0) && (from != NULL)) { - union sctp_sockstore store; - size_t len; - - switch (control->whoFrom->ro._l_addr.sa.sa_family) { -#ifdef INET6 - case AF_INET6: - len = sizeof(struct sockaddr_in6); - store.sin6 = control->whoFrom->ro._l_addr.sin6; - store.sin6.sin6_port = control->port_from; - break; -#endif -#ifdef INET - case AF_INET: -#ifdef INET6 - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { - len = sizeof(struct sockaddr_in6); - in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin, - &store.sin6); - store.sin6.sin6_port = control->port_from; - } else { - len = sizeof(struct sockaddr_in); - store.sin = control->whoFrom->ro._l_addr.sin; - store.sin.sin_port = control->port_from; - } -#else - len = sizeof(struct sockaddr_in); - store.sin = control->whoFrom->ro._l_addr.sin; - store.sin.sin_port = control->port_from; -#endif - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - len = sizeof(struct sockaddr_conn); - store.sconn = control->whoFrom->ro._l_addr.sconn; - store.sconn.sconn_port = control->port_from; - break; -#endif - default: - len = 0; - break; - } - memcpy(from, &store, min((size_t)fromlen, len)); -#if defined(SCTP_EMBEDDED_V6_SCOPE) -#ifdef INET6 - { - struct sockaddr_in6 lsa6, *from6; - - from6 = (struct sockaddr_in6 *)from; - sctp_recover_scope_mac(from6, (&lsa6)); - } -#endif -#endif - } - if (hold_rlock) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } - /* now copy out what data we can */ - if (mp == NULL) { - /* copy out each mbuf in the chain up to length */ - get_more_data: - m = control->data; - while (m) { - /* Move out all we can */ -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - cp_len = uio->uio_resid; -#else - cp_len = uio_resid(uio); -#endif -#else - cp_len = uio->uio_resid; -#endif - my_len = SCTP_BUF_LEN(m); - if (cp_len > my_len) { - /* not enough in this buf */ - cp_len = my_len; - } - if (hold_rlock) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 0); -#endif - if (cp_len > 0) - error = uiomove(mtod(m, char *), (int)cp_len, uio); -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 0); -#endif - /* re-read */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - goto release; - } - - if ((control->do_not_ref_stcb == 0) && stcb && - stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - no_rcv_needed = 1; - } - if (error) { - /* error we are out of here */ - goto release; - } - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - if (cp_len == SCTP_BUF_LEN(m)) { - if ((SCTP_BUF_NEXT(m)== NULL) && - (control->end_added)) { - out_flags |= MSG_EOR; - if ((control->do_not_ref_stcb == 0) && - (control->stcb != NULL) && - ((control->spec_flags & M_NOTIFICATION) == 0)) - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; - } - if (control->spec_flags & M_NOTIFICATION) { - out_flags |= MSG_NOTIFICATION; - } - /* we ate up the mbuf */ - if (in_flags & MSG_PEEK) { - /* just looking */ - m = SCTP_BUF_NEXT(m); - copied_so_far += cp_len; - } else { - /* dispose of the mbuf */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); - } - sctp_sbfree(control, stcb, &so->so_rcv, m); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - copied_so_far += cp_len; - freed_so_far += (uint32_t)cp_len; - freed_so_far += MSIZE; - atomic_subtract_int(&control->length, (int)cp_len); - control->data = sctp_m_free(m); - m = control->data; - /* been through it all, must hold sb lock ok to null tail */ - if (control->data == NULL) { -#ifdef INVARIANTS -#if defined(__FreeBSD__) && !defined(__Userspace__) - if ((control->end_added == 0) || - (TAILQ_NEXT(control, next) == NULL)) { - /* If the end is not added, OR the - * next is NOT null we MUST have the lock. - */ - if (mtx_owned(&inp->inp_rdata_mtx) == 0) { - panic("Hmm we don't own the lock?"); - } - } -#endif -#endif - control->tail_mbuf = NULL; -#ifdef INVARIANTS - if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { - panic("end_added, nothing left and no MSG_EOR"); - } -#endif - } - } - } else { - /* Do we need to trim the mbuf? */ - if (control->spec_flags & M_NOTIFICATION) { - out_flags |= MSG_NOTIFICATION; - } - if ((in_flags & MSG_PEEK) == 0) { - SCTP_BUF_RESV_UF(m, cp_len); - SCTP_BUF_LEN(m) -= (int)cp_len; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&so->so_rcv, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE, (int)cp_len); - } - SCTP_SB_DECR(&so->so_rcv, cp_len); - if ((control->do_not_ref_stcb == 0) && - stcb) { - atomic_subtract_int(&stcb->asoc.sb_cc, (int)cp_len); - } - copied_so_far += cp_len; - freed_so_far += (uint32_t)cp_len; - freed_so_far += MSIZE; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&so->so_rcv, control->do_not_ref_stcb?NULL:stcb, - SCTP_LOG_SBRESULT, 0); - } - atomic_subtract_int(&control->length, (int)cp_len); - } else { - copied_so_far += cp_len; - } - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { -#else - if ((out_flags & MSG_EOR) || (uio_resid(uio) == 0)) { -#endif -#else - if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { -#endif - break; - } - if (((stcb) && (in_flags & MSG_PEEK) == 0) && - (control->do_not_ref_stcb == 0) && - (freed_so_far >= rwnd_req)) { - sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); - } - } /* end while(m) */ - /* - * At this point we have looked at it all and we either have - * a MSG_EOR/or read all the user wants... - * control->length == 0. - */ - if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) { - /* we are done with this control */ - if (control->length == 0) { - if (control->data) { -#ifdef INVARIANTS - panic("control->data not null at read eor?"); -#else - SCTP_PRINTF("Strange, data left in the control buffer .. invariants would panic?\n"); - sctp_m_freem(control->data); - control->data = NULL; -#endif - } - done_with_control: - if (hold_rlock == 0) { - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - } - TAILQ_REMOVE(&inp->read_queue, control, next); - /* Add back any hidden data */ - if (control->held_length) { - held_length = 0; - control->held_length = 0; - wakeup_read_socket = 1; - } - if (control->aux_data) { - sctp_m_free (control->aux_data); - control->aux_data = NULL; - } - no_rcv_needed = control->do_not_ref_stcb; - sctp_free_remote_addr(control->whoFrom); - control->data = NULL; -#ifdef INVARIANTS - if (control->on_strm_q) { - panic("About to free ctl:%p so:%p and its in %d", - control, so, control->on_strm_q); - } -#endif - sctp_free_a_readq(stcb, control); - control = NULL; - if ((freed_so_far >= rwnd_req) && - (no_rcv_needed == 0)) - sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); - - } else { - /* - * The user did not read all of this - * message, turn off the returned MSG_EOR - * since we are leaving more behind on the - * control to read. - */ -#ifdef INVARIANTS - if (control->end_added && - (control->data == NULL) && - (control->tail_mbuf == NULL)) { - panic("Gak, control->length is corrupt?"); - } -#endif - no_rcv_needed = control->do_not_ref_stcb; - out_flags &= ~MSG_EOR; - } - } - if (out_flags & MSG_EOR) { - goto release; - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - if ((uio->uio_resid == 0) || -#else - if ((uio_resid(uio) == 0) || -#endif -#else - if ((uio->uio_resid == 0) || -#endif - ((in_eeor_mode) && - (copied_so_far >= max(so->so_rcv.sb_lowat, 1)))) { - goto release; - } - /* - * If I hit here the receiver wants more and this message is - * NOT done (pd-api). So two questions. Can we block? if not - * we are done. Did the user NOT set MSG_WAITALL? - */ - if (block_allowed == 0) { - goto release; - } - /* - * We need to wait for more data a few things: - * - We don't release the I/O lock so we don't get someone else - * reading. - * - We must be sure to account for the case where what is added - * is NOT to our control when we wakeup. - */ - - /* Do we need to tell the transport a rwnd update might be - * needed before we go to sleep? - */ - if (((stcb) && (in_flags & MSG_PEEK) == 0) && - ((freed_so_far >= rwnd_req) && - (control->do_not_ref_stcb == 0) && - (no_rcv_needed == 0))) { - sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); - } - wait_some_more: -#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__) - if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { - goto release; - } -#else - if (so->so_state & SS_CANTRCVMORE) { - goto release; - } -#endif - - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) - goto release; - - if (hold_rlock == 1) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } - if (hold_sblock == 0) { - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; - } - if ((copied_so_far) && (control->length == 0) && - (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) { - goto release; - } -#if defined(__APPLE__) && !defined(__Userspace__) - sbunlock(&so->so_rcv, 1); -#endif - if (SCTP_SBAVAIL(&so->so_rcv) <= control->held_length) { -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = sbwait(so, SO_RCV); -#else - error = sbwait(&so->so_rcv); -#endif - if (error) { -#if defined(__APPLE__) && !defined(__Userspace__) - goto release_unlocked; -#else - goto release; -#endif - } - control->held_length = 0; - } -#if defined(__APPLE__) && !defined(__Userspace__) - error = sblock(&so->so_rcv, SBLOCKWAIT(in_flags)); -#endif - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } - if (control->length == 0) { - /* still nothing here */ - if (control->end_added == 1) { - /* he aborted, or is done i.e.did a shutdown */ - out_flags |= MSG_EOR; - if (control->pdapi_aborted) { - if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; - - out_flags |= MSG_TRUNC; - } else { - if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; - } - goto done_with_control; - } - if (SCTP_SBAVAIL(&so->so_rcv) > held_length) { - control->held_length = SCTP_SBAVAIL(&so->so_rcv); - held_length = 0; - } - goto wait_some_more; - } else if (control->data == NULL) { - /* we must re-sync since data - * is probably being added - */ - SCTP_INP_READ_LOCK(inp); - if ((control->length > 0) && (control->data == NULL)) { - /* big trouble.. we have the lock and its corrupt? */ -#ifdef INVARIANTS - panic ("Impossible data==NULL length !=0"); -#endif - out_flags |= MSG_EOR; - out_flags |= MSG_TRUNC; - control->length = 0; - SCTP_INP_READ_UNLOCK(inp); - goto done_with_control; - } - SCTP_INP_READ_UNLOCK(inp); - /* We will fall around to get more data */ - } - goto get_more_data; - } else { - /*- - * Give caller back the mbuf chain, - * store in uio_resid the length - */ - wakeup_read_socket = 0; - if ((control->end_added == 0) || - (TAILQ_NEXT(control, next) == NULL)) { - /* Need to get rlock */ - if (hold_rlock == 0) { - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - } - } - if (control->end_added) { - out_flags |= MSG_EOR; - if ((control->do_not_ref_stcb == 0) && - (control->stcb != NULL) && - ((control->spec_flags & M_NOTIFICATION) == 0)) - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; - } - if (control->spec_flags & M_NOTIFICATION) { - out_flags |= MSG_NOTIFICATION; - } -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - uio->uio_resid = control->length; -#else - uio_setresid(uio, control->length); -#endif -#else - uio->uio_resid = control->length; -#endif - *mp = control->data; - m = control->data; - while (m) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); - } - sctp_sbfree(control, stcb, &so->so_rcv, m); - freed_so_far += (uint32_t)SCTP_BUF_LEN(m); - freed_so_far += MSIZE; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - m = SCTP_BUF_NEXT(m); - } - control->data = control->tail_mbuf = NULL; - control->length = 0; - if (out_flags & MSG_EOR) { - /* Done with this control */ - goto done_with_control; - } - } - release: - if (hold_rlock == 1) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } -#if defined(__Userspace__) - if (hold_sblock == 0) { - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; - } -#else - if (hold_sblock == 1) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } -#endif -#if defined(__APPLE__) && !defined(__Userspace__) - sbunlock(&so->so_rcv, 1); -#endif - -#if defined(__FreeBSD__) && !defined(__Userspace__) - SOCK_IO_RECV_UNLOCK(so); - sockbuf_lock = 0; -#endif - - release_unlocked: - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } - if ((stcb) && (in_flags & MSG_PEEK) == 0) { - if ((freed_so_far >= rwnd_req) && - (control && (control->do_not_ref_stcb == 0)) && - (no_rcv_needed == 0)) - sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); - } - out: - if (msg_flags) { - *msg_flags = out_flags; - } - if (((out_flags & MSG_EOR) == 0) && - ((in_flags & MSG_PEEK) == 0) && - (sinfo) && - (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) { - struct sctp_extrcvinfo *s_extra; - s_extra = (struct sctp_extrcvinfo *)sinfo; - s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; - } - if (hold_rlock == 1) { - SCTP_INP_READ_UNLOCK(inp); - } - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (sockbuf_lock) { - SOCK_IO_RECV_UNLOCK(so); - } -#endif - - if (freecnt_applied) { - /* - * The lock on the socket buffer protects us so the free - * code will stop. But since we used the socketbuf lock and - * the sender uses the tcb_lock to increment, we need to use - * the atomic add to the refcnt. - */ - if (stcb == NULL) { -#ifdef INVARIANTS - panic("stcb for refcnt has gone NULL?"); - goto stage_left; -#else - goto stage_left; -#endif - } - /* Save the value back for next time */ - stcb->freed_by_sorcv_sincelast = freed_so_far; - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) &SCTP_RECV_RWND_LOGGING_ENABLE) { - if (stcb) { - sctp_misc_ints(SCTP_SORECV_DONE, - freed_so_far, -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - ((uio) ? (slen - uio->uio_resid) : slen), -#else - ((uio) ? (slen - uio_resid(uio)) : slen), -#endif -#else - (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), -#endif - stcb->asoc.my_rwnd, - SCTP_SBAVAIL(&so->so_rcv)); - } else { - sctp_misc_ints(SCTP_SORECV_DONE, - freed_so_far, -#if defined(__APPLE__) && !defined(__Userspace__) -#if defined(APPLE_LEOPARD) - ((uio) ? (slen - uio->uio_resid) : slen), -#else - ((uio) ? (slen - uio_resid(uio)) : slen), -#endif -#else - (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), -#endif - 0, - SCTP_SBAVAIL(&so->so_rcv)); - } - } - stage_left: - if (wakeup_read_socket) { - sctp_sorwakeup(inp, so); - } - return (error); -} - -#ifdef SCTP_MBUF_LOGGING -struct mbuf * -sctp_m_free(struct mbuf *m) -{ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mb(m, SCTP_MBUF_IFREE); - } - return (m_free(m)); -} - -void -sctp_m_freem(struct mbuf *mb) -{ - while (mb != NULL) - mb = sctp_m_free(mb); -} - -#endif - -int -sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) -{ - /* Given a local address. For all associations - * that holds the address, request a peer-set-primary. - */ - struct sctp_ifa *ifa; - struct sctp_laddr *wi; - - ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); - if (ifa == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); - return (EADDRNOTAVAIL); - } - /* Now that we have the ifa we must awaken the - * iterator with this message. - */ - wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (wi == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); - return (ENOMEM); - } - /* Now incr the count and int wi structure */ - SCTP_INCR_LADDR_COUNT(); - memset(wi, 0, sizeof(*wi)); - (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); - wi->ifa = ifa; - wi->action = SCTP_SET_PRIM_ADDR; - atomic_add_int(&ifa->refcount, 1); - - /* Now add it to the work queue */ - SCTP_WQ_ADDR_LOCK(); - /* - * Should this really be a tailq? As it is we will process the - * newest first :-0 - */ - LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, - (struct sctp_inpcb *)NULL, - (struct sctp_tcb *)NULL, - (struct sctp_nets *)NULL); - SCTP_WQ_ADDR_UNLOCK(); - return (0); -} - -#if defined(__Userspace__) -/* no sctp_soreceive for __Userspace__ now */ -#endif -#if !defined(__Userspace__) -int -sctp_soreceive( struct socket *so, - struct sockaddr **psa, - struct uio *uio, - struct mbuf **mp0, - struct mbuf **controlp, - int *flagsp) -{ - int error, fromlen; - uint8_t sockbuf[256]; - struct sockaddr *from; - struct sctp_extrcvinfo sinfo; - int filling_sinfo = 1; - int flags; - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - /* pickup the assoc we are reading from */ - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - return (EINVAL); - } - if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && - sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && - sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) || - (controlp == NULL)) { - /* user does not want the sndrcv ctl */ - filling_sinfo = 0; - } - if (psa) { - from = (struct sockaddr *)sockbuf; - fromlen = sizeof(sockbuf); -#ifdef HAVE_SA_LEN - from->sa_len = 0; -#endif - } else { - from = NULL; - fromlen = 0; - } - -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_LOCK(so, 1); -#endif - if (filling_sinfo) { - memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo)); - } - if (flagsp != NULL) { - flags = *flagsp; - } else { - flags = 0; - } - error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags, - (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo); - if (flagsp != NULL) { - *flagsp = flags; - } - if (controlp != NULL) { - /* copy back the sinfo in a CMSG format */ - if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) { - *controlp = sctp_build_ctl_nchunk(inp, - (struct sctp_sndrcvinfo *)&sinfo); - } else { - *controlp = NULL; - } - } - if (psa) { - /* copy back the address info */ -#ifdef HAVE_SA_LEN - if (from && from->sa_len) { -#else - if (from) { -#endif -#if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__) - *psa = sodupsockaddr(from, M_NOWAIT); -#else - *psa = dup_sockaddr(from, mp0 == 0); -#endif - } else { - *psa = NULL; - } - } -#if defined(__APPLE__) && !defined(__Userspace__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - return (error); -} - -#if defined(_WIN32) && !defined(__Userspace__) -/* - * General routine to allocate a hash table with control of memory flags. - * is in 7.0 and beyond for sure :-) - */ -void * -sctp_hashinit_flags(int elements, struct malloc_type *type, - u_long *hashmask, int flags) -{ - long hashsize; - LIST_HEAD(generic, generic) *hashtbl; - int i; - - - if (elements <= 0) { -#ifdef INVARIANTS - panic("hashinit: bad elements"); -#else - SCTP_PRINTF("hashinit: bad elements?"); - elements = 1; -#endif - } - for (hashsize = 1; hashsize <= elements; hashsize <<= 1) - continue; - hashsize >>= 1; - if (flags & HASH_WAITOK) - hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); - else if (flags & HASH_NOWAIT) - hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_NOWAIT); - else { -#ifdef INVARIANTS - panic("flag incorrect in hashinit_flags"); -#else - return (NULL); -#endif - } - - /* no memory? */ - if (hashtbl == NULL) - return (NULL); - - for (i = 0; i < hashsize; i++) - LIST_INIT(&hashtbl[i]); - *hashmask = hashsize - 1; - return (hashtbl); -} -#endif -#else /* __Userspace__ ifdef above sctp_soreceive */ -/* - * __Userspace__ Defining sctp_hashinit_flags() and sctp_hashdestroy() for userland. - * NOTE: We don't want multiple definitions here. So sctp_hashinit_flags() above for - *__FreeBSD__ must be excluded. - * - */ - -void * -sctp_hashinit_flags(int elements, struct malloc_type *type, - u_long *hashmask, int flags) -{ - long hashsize; - LIST_HEAD(generic, generic) *hashtbl; - int i; - - if (elements <= 0) { - SCTP_PRINTF("hashinit: bad elements?"); -#ifdef INVARIANTS - return (NULL); -#else - elements = 1; -#endif - } - for (hashsize = 1; hashsize <= elements; hashsize <<= 1) - continue; - hashsize >>= 1; - /*cannot use MALLOC here because it has to be declared or defined - using MALLOC_DECLARE or MALLOC_DEFINE first. */ - if (flags & HASH_WAITOK) - hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl)); - else if (flags & HASH_NOWAIT) - hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl)); - else { -#ifdef INVARIANTS - SCTP_PRINTF("flag incorrect in hashinit_flags.\n"); -#endif - return (NULL); - } - - /* no memory? */ - if (hashtbl == NULL) - return (NULL); - - for (i = 0; i < hashsize; i++) - LIST_INIT(&hashtbl[i]); - *hashmask = hashsize - 1; - return (hashtbl); -} - -void -sctp_hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask) -{ - LIST_HEAD(generic, generic) *hashtbl, *hp; - - hashtbl = vhashtbl; - for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++) - if (!LIST_EMPTY(hp)) { - SCTP_PRINTF("hashdestroy: hash not empty.\n"); - return; - } - FREE(hashtbl, type); -} - -void -sctp_hashfreedestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask) -{ - LIST_HEAD(generic, generic) *hashtbl/*, *hp*/; - /* - LIST_ENTRY(type) *start, *temp; - */ - hashtbl = vhashtbl; - /* Apparently temp is not dynamically allocated, so attempts to - free it results in error. - for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++) - if (!LIST_EMPTY(hp)) { - start = LIST_FIRST(hp); - while (start != NULL) { - temp = start; - start = start->le_next; - SCTP_PRINTF("%s: %p \n", __func__, (void *)temp); - FREE(temp, type); - } - } - */ - FREE(hashtbl, type); -} - -#endif -int -sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, - int totaddr, int *error) -{ - int added = 0; - int i; - struct sctp_inpcb *inp; - struct sockaddr *sa; - size_t incr = 0; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - - sa = addr; - inp = stcb->sctp_ep; - *error = 0; - for (i = 0; i < totaddr; i++) { - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - incr = sizeof(struct sockaddr_in); - sin = (struct sockaddr_in *)sa; - if ((sin->sin_addr.s_addr == INADDR_ANY) || - (sin->sin_addr.s_addr == INADDR_BROADCAST) || - IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_7); - *error = EINVAL; - goto out_now; - } - if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, - SCTP_ADDR_IS_CONFIRMED)) { - /* assoc gone no un-lock */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_8); - *error = ENOBUFS; - goto out_now; - } - added++; - break; -#endif -#ifdef INET6 - case AF_INET6: - incr = sizeof(struct sockaddr_in6); - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || - IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_9); - *error = EINVAL; - goto out_now; - } - if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, - SCTP_ADDR_IS_CONFIRMED)) { - /* assoc gone no un-lock */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_10); - *error = ENOBUFS; - goto out_now; - } - added++; - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - incr = sizeof(struct sockaddr_conn); - if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, - SCTP_DONOT_SETSCOPE, - SCTP_ADDR_IS_CONFIRMED)) { - /* assoc gone no un-lock */ - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTPUTIL + SCTP_LOC_11); - *error = ENOBUFS; - goto out_now; - } - added++; - break; -#endif - default: - break; - } - sa = (struct sockaddr *)((caddr_t)sa + incr); - } - out_now: - return (added); -} - -int -sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, - unsigned int totaddr, - unsigned int *num_v4, unsigned int *num_v6, - unsigned int limit) -{ - struct sockaddr *sa; - struct sctp_tcb *stcb; - unsigned int incr, at, i; - - at = 0; - sa = addr; - *num_v6 = *num_v4 = 0; - /* account and validate addresses */ - if (totaddr == 0) { - return (EINVAL); - } - for (i = 0; i < totaddr; i++) { - if (at + sizeof(struct sockaddr) > limit) { - return (EINVAL); - } - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - incr = (unsigned int)sizeof(struct sockaddr_in); -#ifdef HAVE_SA_LEN - if (sa->sa_len != incr) { - return (EINVAL); - } -#endif - (*num_v4) += 1; - break; -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6; - - incr = (unsigned int)sizeof(struct sockaddr_in6); -#ifdef HAVE_SA_LEN - if (sa->sa_len != incr) { - return (EINVAL); - } -#endif - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - /* Must be non-mapped for connectx */ - return (EINVAL); - } - (*num_v6) += 1; - break; - } -#endif - default: - return (EINVAL); - } - if ((at + incr) > limit) { - return (EINVAL); - } - SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - return (EALREADY); - } else { - SCTP_INP_DECR_REF(inp); - } - at += incr; - sa = (struct sockaddr *)((caddr_t)sa + incr); - } - return (0); -} - -/* - * sctp_bindx(ADD) for one address. - * assumes all arguments are valid/checked by caller. - */ -void -sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, - struct sockaddr *sa, uint32_t vrf_id, int *error, - void *p) -{ -#if defined(INET) && defined(INET6) - struct sockaddr_in sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif -#ifdef INET - struct sockaddr_in *sinp; -#endif - struct sockaddr *addr_to_use; - struct sctp_inpcb *lep; -#ifdef SCTP_MVRF - int i; -#endif - uint16_t port; - - /* see if we're bound all already! */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#ifdef SCTP_MVRF - /* Is the VRF one we have */ - for (i = 0; i < inp->num_vrfs; i++) { - if (vrf_id == inp->m_vrf_ids[i]) { - break; - } - } - if (i == inp->num_vrfs) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - switch (sa->sa_family) { -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (sa->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { - /* can only bind v6 on PF_INET6 sockets */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - sin6 = (struct sockaddr_in6 *)sa; - port = sin6->sin6_port; -#ifdef INET - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - /* can't bind v4-mapped on PF_INET sockets */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - in6_sin6_2_sin(&sin, sin6); - addr_to_use = (struct sockaddr *)&sin; - } else { - addr_to_use = sa; - } -#else - addr_to_use = sa; -#endif - break; -#endif -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (sa->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - /* can't bind v4 on PF_INET sockets */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - sinp = (struct sockaddr_in *)sa; - port = sinp->sin_port; - addr_to_use = sa; - break; -#endif - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { -#if !(defined(_WIN32) || defined(__Userspace__)) - if (p == NULL) { - /* Can't get proc for Net/Open BSD */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - *error = sctp_inpcb_bind(so, addr_to_use, NULL, p); - return; - } - /* Validate the incoming port. */ - if ((port != 0) && (port != inp->sctp_lport)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - lep = sctp_pcb_findep(addr_to_use, 1, 0, vrf_id); - if (lep == NULL) { - /* add the address */ - *error = sctp_addr_mgmt_ep_sa(inp, addr_to_use, - SCTP_ADD_IP_ADDRESS, vrf_id); - } else { - if (lep != inp) { - *error = EADDRINUSE; - } - SCTP_INP_DECR_REF(lep); - } -} - -/* - * sctp_bindx(DELETE) for one address. - * assumes all arguments are valid/checked by caller. - */ -void -sctp_bindx_delete_address(struct sctp_inpcb *inp, - struct sockaddr *sa, uint32_t vrf_id, int *error) -{ - struct sockaddr *addr_to_use; -#if defined(INET) && defined(INET6) - struct sockaddr_in6 *sin6; - struct sockaddr_in sin; -#endif -#ifdef SCTP_MVRF - int i; -#endif - - /* see if we're bound all already! */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#ifdef SCTP_MVRF - /* Is the VRF one we have */ - for (i = 0; i < inp->num_vrfs; i++) { - if (vrf_id == inp->m_vrf_ids[i]) { - break; - } - } - if (i == inp->num_vrfs) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - switch (sa->sa_family) { -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (sa->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { - /* can only bind v6 on PF_INET6 sockets */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#ifdef INET - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - /* can't bind mapped-v4 on PF_INET sockets */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - in6_sin6_2_sin(&sin, sin6); - addr_to_use = (struct sockaddr *)&sin; - } else { - addr_to_use = sa; - } -#else - addr_to_use = sa; -#endif - break; -#endif -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (sa->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } -#endif - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp)) { - /* can't bind v4 on PF_INET sockets */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - addr_to_use = sa; - break; -#endif - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - *error = EINVAL; - return; - } - /* No lock required mgmt_ep_sa does its own locking. */ - *error = sctp_addr_mgmt_ep_sa(inp, addr_to_use, SCTP_DEL_IP_ADDRESS, - vrf_id); -} - -/* - * returns the valid local address count for an assoc, taking into account - * all scoping rules - */ -int -sctp_local_addr_count(struct sctp_tcb *stcb) -{ - int loopback_scope; -#if defined(INET) - int ipv4_local_scope, ipv4_addr_legal; -#endif -#if defined(INET6) - int local_scope, site_scope, ipv6_addr_legal; -#endif -#if defined(__Userspace__) - int conn_addr_legal; -#endif - struct sctp_vrf *vrf; - struct sctp_ifn *sctp_ifn; - struct sctp_ifa *sctp_ifa; - int count = 0; - - /* Turn on all the appropriate scopes */ - loopback_scope = stcb->asoc.scope.loopback_scope; -#if defined(INET) - ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; - ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; -#endif -#if defined(INET6) - local_scope = stcb->asoc.scope.local_scope; - site_scope = stcb->asoc.scope.site_scope; - ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; -#endif -#if defined(__Userspace__) - conn_addr_legal = stcb->asoc.scope.conn_addr_legal; -#endif - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(stcb->asoc.vrf_id); - if (vrf == NULL) { - /* no vrf, no addresses */ - SCTP_IPI_ADDR_RUNLOCK(); - return (0); - } - - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* - * bound all case: go through all ifns on the vrf - */ - LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if ((loopback_scope == 0) && - SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { - continue; - } - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (sctp_is_addr_restricted(stcb, sctp_ifa)) - continue; - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (ipv4_addr_legal) { - struct sockaddr_in *sin; - - sin = &sctp_ifa->address.sin; - if (sin->sin_addr.s_addr == 0) { - /* skip unspecified addrs */ - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin->sin_addr) != 0) { - continue; - } -#endif - if ((ipv4_local_scope == 0) && - (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { - continue; - } - /* count this one */ - count++; - } else { - continue; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (ipv6_addr_legal) { - struct sockaddr_in6 *sin6; - -#if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME) - struct sockaddr_in6 lsa6; -#endif - sin6 = &sctp_ifa->address.sin6; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - continue; - } -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, - &sin6->sin6_addr) != 0) { - continue; - } -#endif - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (local_scope == 0) - continue; -#if defined(SCTP_EMBEDDED_V6_SCOPE) - if (sin6->sin6_scope_id == 0) { -#ifdef SCTP_KAME - if (sa6_recoverscope(sin6) != 0) - /* - * bad link - * local - * address - */ - continue; -#else - lsa6 = *sin6; - if (in6_recoverscope(&lsa6, - &lsa6.sin6_addr, - NULL)) - /* - * bad link - * local - * address - */ - continue; - sin6 = &lsa6; -#endif /* SCTP_KAME */ - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ - } - if ((site_scope == 0) && - (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - continue; - } - /* count this one */ - count++; - } - break; -#endif -#if defined(__Userspace__) - case AF_CONN: - if (conn_addr_legal) { - count++; - } - break; -#endif - default: - /* TSNH */ - break; - } - } - } - } else { - /* - * subset bound case - */ - struct sctp_laddr *laddr; - LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, - sctp_nxt_addr) { - if (sctp_is_addr_restricted(stcb, laddr->ifa)) { - continue; - } - /* count this one */ - count++; - } - } - SCTP_IPI_ADDR_RUNLOCK(); - return (count); -} - -#if defined(SCTP_LOCAL_TRACE_BUF) - -void -sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) -{ - uint32_t saveindex, newindex; - -#if defined(_WIN32) && !defined(__Userspace__) - if (SCTP_BASE_SYSCTL(sctp_log) == NULL) { - return; - } - do { - saveindex = SCTP_BASE_SYSCTL(sctp_log)->index; - if (saveindex >= SCTP_MAX_LOGGING_SIZE) { - newindex = 1; - } else { - newindex = saveindex + 1; - } - } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log)->index, saveindex, newindex) == 0); - if (saveindex >= SCTP_MAX_LOGGING_SIZE) { - saveindex = 0; - } - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].subsys = subsys; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].params[0] = a; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].params[1] = b; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].params[2] = c; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].params[3] = d; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].params[4] = e; - SCTP_BASE_SYSCTL(sctp_log)->entry[saveindex].params[5] = f; -#else - do { - saveindex = SCTP_BASE_SYSCTL(sctp_log).index; - if (saveindex >= SCTP_MAX_LOGGING_SIZE) { - newindex = 1; - } else { - newindex = saveindex + 1; - } - } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0); - if (saveindex >= SCTP_MAX_LOGGING_SIZE) { - saveindex = 0; - } - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e; - SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f; -#endif -} - -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) -static bool -sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, - const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) -{ - struct ip *iph; -#ifdef INET6 - struct ip6_hdr *ip6; -#endif - struct mbuf *sp, *last; - struct udphdr *uhdr; - uint16_t port; - - if ((m->m_flags & M_PKTHDR) == 0) { - /* Can't handle one that is not a pkt hdr */ - goto out; - } - /* Pull the src port */ - iph = mtod(m, struct ip *); - uhdr = (struct udphdr *)((caddr_t)iph + off); - port = uhdr->uh_sport; - /* Split out the mbuf chain. Leave the - * IP header in m, place the - * rest in the sp. - */ - sp = m_split(m, off, M_NOWAIT); - if (sp == NULL) { - /* Gak, drop packet, we can't do a split */ - goto out; - } - if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) { - /* Gak, packet can't have an SCTP header in it - too small */ - m_freem(sp); - goto out; - } - /* Now pull up the UDP header and SCTP header together */ - sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr)); - if (sp == NULL) { - /* Gak pullup failed */ - goto out; - } - /* Trim out the UDP header */ - m_adj(sp, sizeof(struct udphdr)); - - /* Now reconstruct the mbuf chain */ - for (last = m; last->m_next; last = last->m_next); - last->m_next = sp; - m->m_pkthdr.len += sp->m_pkthdr.len; - /* - * The CSUM_DATA_VALID flags indicates that the HW checked the - * UDP checksum and it was valid. - * Since CSUM_DATA_VALID == CSUM_SCTP_VALID this would imply that - * the HW also verified the SCTP checksum. Therefore, clear the bit. - */ - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n", - m->m_pkthdr.len, - if_name(m->m_pkthdr.rcvif), - (int)m->m_pkthdr.csum_flags, CSUM_BITS); - m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID; - iph = mtod(m, struct ip *); - switch (iph->ip_v) { -#ifdef INET - case IPVERSION: - iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); - sctp_input_with_port(m, off, port); - break; -#endif -#ifdef INET6 - case IPV6_VERSION >> 4: - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr)); - sctp6_input_with_port(&m, &off, port); - break; -#endif - default: - goto out; - break; - } - return (true); - out: - m_freem(m); - - return (true); -} - -#ifdef INET -static void -sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) -{ - struct icmp *icmp = param.icmp; - struct ip *outer_ip, *inner_ip; - struct sctphdr *sh; - struct udphdr *udp; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sctp_init_chunk *ch; - struct sockaddr_in src, dst; - uint8_t type, code; - - inner_ip = &icmp->icmp_ip; - outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); - if (ntohs(outer_ip->ip_len) < - sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { - return; - } - udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); - sh = (struct sctphdr *)(udp + 1); - memset(&src, 0, sizeof(struct sockaddr_in)); - src.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - src.sin_len = sizeof(struct sockaddr_in); -#endif - src.sin_port = sh->src_port; - src.sin_addr = inner_ip->ip_src; - memset(&dst, 0, sizeof(struct sockaddr_in)); - dst.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - dst.sin_port = sh->dest_port; - dst.sin_addr = inner_ip->ip_dst; - /* - * 'dst' holds the dest of the packet that failed to be sent. - * 'src' holds our local endpoint address. Thus we reverse - * the dst and the src in the lookup. - */ - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, - SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the UDP port numbers */ - if ((udp->uh_dport != net->port) || - (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { - SCTP_TCB_UNLOCK(stcb); - return; - } - /* Check the verification tag */ - if (ntohl(sh->v_tag) != 0) { - /* - * This must be the verification tag used - * for sending out packets. We don't - * consider packets reflecting the - * verification tag. - */ - if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - if (ntohs(outer_ip->ip_len) >= - sizeof(struct ip) + - 8 + (inner_ip->ip_hl << 2) + 8 + 20) { - /* - * In this case we can check if we - * got an INIT chunk and if the - * initiate tag matches. - */ - ch = (struct sctp_init_chunk *)(sh + 1); - if ((ch->ch.chunk_type != SCTP_INITIATION) || - (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - } - type = icmp->icmp_type; - code = icmp->icmp_code; - if ((type == ICMP_UNREACH) && - (code == ICMP_UNREACH_PORT)) { - code = ICMP_UNREACH_PROTOCOL; - } - sctp_notify(inp, stcb, net, type, code, - ntohs(inner_ip->ip_len), - (uint32_t)ntohs(icmp->icmp_nextmtu)); -#if defined(__Userspace__) - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - struct socket *upcall_socket; - - upcall_socket = stcb->sctp_socket; - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - if ((upcall_socket->so_upcall != NULL) && - (upcall_socket->so_error != 0)) { - (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); - } - ACCEPT_LOCK(); - SOCK_LOCK(upcall_socket); - sorele(upcall_socket); - } -#endif - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } - return; -} -#endif - -#ifdef INET6 -static void -sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) -{ - struct ip6ctlparam *ip6cp = param.ip6cp; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sctphdr sh; - struct udphdr udp; - struct sockaddr_in6 src, dst; - uint8_t type, code; - - /* - * XXX: We assume that when IPV6 is non NULL, M and OFF are - * valid. - */ - if (ip6cp->ip6c_m == NULL) { - return; - } - /* Check if we can safely examine the ports and the - * verification tag of the SCTP common header. - */ - if (ip6cp->ip6c_m->m_pkthdr.len < - ip6cp->ip6c_off + sizeof(struct udphdr)+ offsetof(struct sctphdr, checksum)) { - return; - } - /* Copy out the UDP header. */ - memset(&udp, 0, sizeof(struct udphdr)); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off, - sizeof(struct udphdr), - (caddr_t)&udp); - /* Copy out the port numbers and the verification tag. */ - memset(&sh, 0, sizeof(struct sctphdr)); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + sizeof(struct udphdr), - sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), - (caddr_t)&sh); - memset(&src, 0, sizeof(struct sockaddr_in6)); - src.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - src.sin6_len = sizeof(struct sockaddr_in6); -#endif - src.sin6_port = sh.src_port; - src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { - return; - } -#endif - memset(&dst, 0, sizeof(struct sockaddr_in6)); - dst.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - dst.sin6_len = sizeof(struct sockaddr_in6); -#endif - dst.sin6_port = sh.dest_port; - dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { - return; - } -#endif - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the UDP port numbers */ - if ((udp.uh_dport != net->port) || - (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { - SCTP_TCB_UNLOCK(stcb); - return; - } - /* Check the verification tag */ - if (ntohl(sh.v_tag) != 0) { - /* - * This must be the verification tag used for - * sending out packets. We don't consider - * packets reflecting the verification tag. - */ - if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { -#if defined(__FreeBSD__) && !defined(__Userspace__) - if (ip6cp->ip6c_m->m_pkthdr.len >= - ip6cp->ip6c_off + sizeof(struct udphdr) + - sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr) + - offsetof(struct sctp_init, a_rwnd)) { - /* - * In this case we can check if we - * got an INIT chunk and if the - * initiate tag matches. - */ - uint32_t initiate_tag; - uint8_t chunk_type; - - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + - sizeof(struct udphdr) + - sizeof(struct sctphdr), - sizeof(uint8_t), - (caddr_t)&chunk_type); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + - sizeof(struct udphdr) + - sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr), - sizeof(uint32_t), - (caddr_t)&initiate_tag); - if ((chunk_type != SCTP_INITIATION) || - (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } -#else - SCTP_TCB_UNLOCK(stcb); - return; -#endif - } - type = ip6cp->ip6c_icmp6->icmp6_type; - code = ip6cp->ip6c_icmp6->icmp6_code; - if ((type == ICMP6_DST_UNREACH) && - (code == ICMP6_DST_UNREACH_NOPORT)) { - type = ICMP6_PARAM_PROB; - code = ICMP6_PARAMPROB_NEXTHEADER; - } - sctp6_notify(inp, stcb, net, type, code, - ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); -#if defined(__Userspace__) - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - struct socket *upcall_socket; - - upcall_socket = stcb->sctp_socket; - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - if ((upcall_socket->so_upcall != NULL) && - (upcall_socket->so_error != 0)) { - (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); - } - ACCEPT_LOCK(); - SOCK_LOCK(upcall_socket); - sorele(upcall_socket); - } -#endif - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce inp's ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } -} -#endif - -void -sctp_over_udp_stop(void) -{ - /* - * This function assumes sysctl caller holds sctp_sysctl_info_lock() for writing! - */ -#ifdef INET - if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { - soclose(SCTP_BASE_INFO(udp4_tun_socket)); - SCTP_BASE_INFO(udp4_tun_socket) = NULL; - } -#endif -#ifdef INET6 - if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { - soclose(SCTP_BASE_INFO(udp6_tun_socket)); - SCTP_BASE_INFO(udp6_tun_socket) = NULL; - } -#endif -} - -int -sctp_over_udp_start(void) -{ - uint16_t port; - int ret; -#ifdef INET - struct sockaddr_in sin; -#endif -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - /* - * This function assumes sysctl caller holds sctp_sysctl_info_lock() for writing! - */ - port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); - if (ntohs(port) == 0) { - /* Must have a port set */ - return (EINVAL); - } -#ifdef INET - if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { - /* Already running -- must stop first */ - return (EALREADY); - } -#endif -#ifdef INET6 - if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { - /* Already running -- must stop first */ - return (EALREADY); - } -#endif -#ifdef INET - if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket), - SOCK_DGRAM, IPPROTO_UDP, - curthread->td_ucred, curthread))) { - sctp_over_udp_stop(); - return (ret); - } - /* Call the special UDP hook. */ - if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket), - sctp_recv_udp_tunneled_packet, - sctp_recv_icmp_tunneled_packet, - NULL))) { - sctp_over_udp_stop(); - return (ret); - } - /* Ok, we have a socket, bind it to the port. */ - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket), - (struct sockaddr *)&sin, curthread))) { - sctp_over_udp_stop(); - return (ret); - } -#endif -#ifdef INET6 - if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket), - SOCK_DGRAM, IPPROTO_UDP, - curthread->td_ucred, curthread))) { - sctp_over_udp_stop(); - return (ret); - } - /* Call the special UDP hook. */ - if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket), - sctp_recv_udp_tunneled_packet, - sctp_recv_icmp6_tunneled_packet, - NULL))) { - sctp_over_udp_stop(); - return (ret); - } - /* Ok, we have a socket, bind it to the port. */ - memset(&sin6, 0, sizeof(struct sockaddr_in6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(port); - if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket), - (struct sockaddr *)&sin6, curthread))) { - sctp_over_udp_stop(); - return (ret); - } -#endif - return (0); -} -#endif - -/* - * sctp_min_mtu ()returns the minimum of all non-zero arguments. - * If all arguments are zero, zero is returned. - */ -uint32_t -sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3) -{ - if (mtu1 > 0) { - if (mtu2 > 0) { - if (mtu3 > 0) { - return (min(mtu1, min(mtu2, mtu3))); - } else { - return (min(mtu1, mtu2)); - } - } else { - if (mtu3 > 0) { - return (min(mtu1, mtu3)); - } else { - return (mtu1); - } - } - } else { - if (mtu2 > 0) { - if (mtu3 > 0) { - return (min(mtu2, mtu3)); - } else { - return (mtu2); - } - } else { - return (mtu3); - } - } -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -void -sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu) -{ - struct in_conninfo inc; - - memset(&inc, 0, sizeof(struct in_conninfo)); - inc.inc_fibnum = fibnum; - switch (addr->sa.sa_family) { -#ifdef INET - case AF_INET: - inc.inc_faddr = addr->sin.sin_addr; - break; -#endif -#ifdef INET6 - case AF_INET6: - inc.inc_flags |= INC_ISIPV6; - inc.inc6_faddr = addr->sin6.sin6_addr; - break; -#endif - default: - return; - } - tcp_hc_updatemtu(&inc, (u_long)mtu); -} - -uint32_t -sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum) -{ - struct in_conninfo inc; - - memset(&inc, 0, sizeof(struct in_conninfo)); - inc.inc_fibnum = fibnum; - switch (addr->sa.sa_family) { -#ifdef INET - case AF_INET: - inc.inc_faddr = addr->sin.sin_addr; - break; -#endif -#ifdef INET6 - case AF_INET6: - inc.inc_flags |= INC_ISIPV6; - inc.inc6_faddr = addr->sin6.sin6_addr; - break; -#endif - default: - return (0); - } - return ((uint32_t)tcp_hc_getmtu(&inc)); -} -#endif - -void -sctp_set_state(struct sctp_tcb *stcb, int new_state) -{ -#if defined(KDTRACE_HOOKS) - int old_state = stcb->asoc.state; -#endif - - KASSERT((new_state & ~SCTP_STATE_MASK) == 0, - ("sctp_set_state: Can't set substate (new_state = %x)", - new_state)); - stcb->asoc.state = (stcb->asoc.state & ~SCTP_STATE_MASK) | new_state; - if ((new_state == SCTP_STATE_SHUTDOWN_RECEIVED) || - (new_state == SCTP_STATE_SHUTDOWN_SENT) || - (new_state == SCTP_STATE_SHUTDOWN_ACK_SENT)) { - SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); - } -#if defined(KDTRACE_HOOKS) - if (((old_state & SCTP_STATE_MASK) != new_state) && - !(((old_state & SCTP_STATE_MASK) == SCTP_STATE_EMPTY) && - (new_state == SCTP_STATE_INUSE))) { - SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state); - } -#endif -} - -void -sctp_add_substate(struct sctp_tcb *stcb, int substate) -{ -#if defined(KDTRACE_HOOKS) - int old_state = stcb->asoc.state; -#endif - - KASSERT((substate & SCTP_STATE_MASK) == 0, - ("sctp_add_substate: Can't set state (substate = %x)", - substate)); - stcb->asoc.state |= substate; -#if defined(KDTRACE_HOOKS) - if (((substate & SCTP_STATE_ABOUT_TO_BE_FREED) && - ((old_state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) || - ((substate & SCTP_STATE_SHUTDOWN_PENDING) && - ((old_state & SCTP_STATE_SHUTDOWN_PENDING) == 0))) { - SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state); - } -#endif -} - diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.h deleted file mode 100644 index fc2992d1..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet/sctputil.h +++ /dev/null @@ -1,386 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET_SCTP_UTIL_H_ -#define _NETINET_SCTP_UTIL_H_ - -#if defined(_KERNEL) || defined(__Userspace__) - -#define SCTP_READ_LOCK_HELD 1 -#define SCTP_READ_LOCK_NOT_HELD 0 - -#ifdef SCTP_ASOCLOG_OF_TSNS -void sctp_print_out_track_log(struct sctp_tcb *stcb); -#endif - -#ifdef SCTP_MBUF_LOGGING -struct mbuf *sctp_m_free(struct mbuf *m); -void sctp_m_freem(struct mbuf *m); -#else -#define sctp_m_free m_free -#define sctp_m_freem m_freem -#endif - -#if defined(SCTP_LOCAL_TRACE_BUF) -void -sctp_log_trace(uint32_t fr, const char *str SCTP_UNUSED, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f); -#endif - -#define sctp_get_associd(stcb) ((sctp_assoc_t)stcb->asoc.assoc_id) - -/* - * Function prototypes - */ -int32_t -sctp_map_assoc_state(int); - -uint32_t -sctp_get_ifa_hash_val(struct sockaddr *addr); - -struct sctp_ifa * -sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int hold_lock); - -struct sctp_ifa * -sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock); - -uint32_t sctp_select_initial_TSN(struct sctp_pcb *); - -uint32_t sctp_select_a_tag(struct sctp_inpcb *, uint16_t lport, uint16_t rport, int); - -int sctp_init_asoc(struct sctp_inpcb *, struct sctp_tcb *, uint32_t, uint32_t, uint32_t, uint16_t); - -void sctp_fill_random_store(struct sctp_pcb *); - -void -sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, - uint16_t numberout, int flag); -void -sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag); - -/* - * NOTE: sctp_timer_start() will increment the reference count of any relevant - * structure the timer is referencing, in order to prevent a race condition - * between the timer executing and the structure being freed. - * - * When the timer fires or sctp_timer_stop() is called, these references are - * removed. - */ -void -sctp_timer_start(int, struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); - -void -sctp_timer_stop(int, struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *, uint32_t); - -int -sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id); - -void -sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - int so_locked -#if !(defined(__APPLE__) && !defined(__Userspace__)) - SCTP_UNUSED -#endif -); - -#if defined(__Userspace__) -void sctp_invoke_recv_callback(struct sctp_inpcb *, - struct sctp_tcb *, - struct sctp_queued_to_read *, - int); - -#endif -void -sctp_add_to_readq(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_queued_to_read *control, - struct sockbuf *sb, - int end, - int inpread_locked, - int so_locked); - -void sctp_iterator_worker(void); - -uint32_t sctp_get_prev_mtu(uint32_t); -uint32_t sctp_get_next_mtu(uint32_t); - -void -sctp_timeout_handler(void *); - -int -sctp_calculate_rto(struct sctp_tcb *, struct sctp_association *, - struct sctp_nets *, struct timeval *, int); - -uint32_t sctp_calculate_len(struct mbuf *); - -caddr_t sctp_m_getptr(struct mbuf *, int, int, uint8_t *); - -struct sctp_paramhdr * -sctp_get_next_param(struct mbuf *, int, - struct sctp_paramhdr *, int); - -struct mbuf * -sctp_add_pad_tombuf(struct mbuf *, int); - -struct mbuf * -sctp_pad_lastmbuf(struct mbuf *, int, struct mbuf *); - -void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *, int); - -void -sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, - struct sctp_inpcb *new_inp, - struct sctp_tcb *stcb, int waitflags); - -void sctp_stop_timers_for_shutdown(struct sctp_tcb *); - -/* Stop all timers for association and remote addresses. */ -void sctp_stop_association_timers(struct sctp_tcb *, bool); - -void sctp_report_all_outbound(struct sctp_tcb *, uint16_t, int); - -int sctp_expand_mapping_array(struct sctp_association *, uint32_t); - -void sctp_abort_notification(struct sctp_tcb *, bool, bool, uint16_t, - struct sctp_abort_chunk *, int); - -/* We abort responding to an IP packet for some reason */ -void -sctp_abort_association(struct sctp_inpcb *, struct sctp_tcb *, struct mbuf *, - int, struct sockaddr *, struct sockaddr *, - struct sctphdr *, struct mbuf *, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, -#endif - uint32_t, uint16_t); - -/* We choose to abort via user input */ -void -sctp_abort_an_association(struct sctp_inpcb *, struct sctp_tcb *, - struct mbuf *, bool, int); - -void sctp_handle_ootb(struct mbuf *, int, int, - struct sockaddr *, struct sockaddr *, - struct sctphdr *, struct sctp_inpcb *, - struct mbuf *, -#if defined(__FreeBSD__) && !defined(__Userspace__) - uint8_t, uint32_t, uint16_t, -#endif - uint32_t, uint16_t); - -int sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, - int totaddr, int *error); - -int -sctp_connectx_helper_find(struct sctp_inpcb *, struct sockaddr *, - unsigned int, unsigned int *, unsigned int *, unsigned int); - -int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *); -#ifdef INET6 -uint32_t sctp_is_same_scope(struct sockaddr_in6 *, struct sockaddr_in6 *); - -#if defined(SCTP_EMBEDDED_V6_SCOPE) -struct sockaddr_in6 * -sctp_recover_scope(struct sockaddr_in6 *, struct sockaddr_in6 *); - -#ifdef SCTP_KAME -#define sctp_recover_scope_mac(addr, store) do { \ - if ((addr->sin6_family == AF_INET6) && \ - (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr))) { \ - *store = *addr; \ - if (addr->sin6_scope_id == 0) { \ - if (!sa6_recoverscope(store)) { \ - addr = store; \ - } \ - } else { \ - in6_clearscope(&addr->sin6_addr); \ - addr = store; \ - } \ - } \ -} while (0) -#else -#define sctp_recover_scope_mac(addr, store) do { \ - if ((addr->sin6_family == AF_INET6) && \ - (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr))) { \ - *store = *addr; \ - if (addr->sin6_scope_id == 0) { \ - if (!in6_recoverscope(store, &store->sin6_addr, \ - NULL)) { \ - addr = store; \ - } \ - } else { \ - in6_clearscope(&addr->sin6_addr); \ - addr = store; \ - } \ - } \ -} while (0) -#endif -#endif -#endif - -int sctp_cmpaddr(struct sockaddr *, struct sockaddr *); - -void sctp_print_address(struct sockaddr *); - -int -sctp_release_pr_sctp_chunk(struct sctp_tcb *, struct sctp_tmit_chunk *, - uint8_t, int); - -struct mbuf *sctp_generate_cause(uint16_t, char *); -struct mbuf *sctp_generate_no_user_data_cause(uint32_t); - -void sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, - struct sockaddr *sa, uint32_t vrf_id, int *error, - void *p); -void sctp_bindx_delete_address(struct sctp_inpcb *inp, struct sockaddr *sa, - uint32_t vrf_id, int *error); - -int sctp_local_addr_count(struct sctp_tcb *stcb); - -void -sctp_free_bufspace(struct sctp_tcb *, struct sctp_association *, - struct sctp_tmit_chunk *, int); - -#define sctp_free_spbufspace(stcb, asoc, sp) \ -do { \ - if (sp->data != NULL) { \ - if ((asoc)->total_output_queue_size >= sp->length) { \ - atomic_subtract_int(&(asoc)->total_output_queue_size, sp->length); \ - } else { \ - (asoc)->total_output_queue_size = 0; \ - } \ - if (stcb->sctp_socket && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \ - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \ - SCTP_SB_DECR(&stcb->sctp_socket->so_snd, sp->length); \ - } \ - } \ -} while (0) - -#define sctp_snd_sb_alloc(stcb, sz) \ -do { \ - atomic_add_int(&stcb->asoc.total_output_queue_size,sz); \ - if ((stcb->sctp_socket != NULL) && \ - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \ - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \ - SCTP_SB_INCR(&stcb->sctp_socket->so_snd, sz); \ - } \ -} while (0) - -/* functions to start/stop udp tunneling */ -#if (defined(__APPLE__) || defined(__FreeBSD__)) && !defined(__Userspace__) -void sctp_over_udp_stop(void); -int sctp_over_udp_start(void); -#endif -#if defined(_WIN32) && !defined(__Userspace__) -void sctp_over_udp_restart(void); -#endif - -int -sctp_soreceive(struct socket *so, struct sockaddr **psa, - struct uio *uio, - struct mbuf **mp0, - struct mbuf **controlp, - int *flagsp); - -void -sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d); - -void -sctp_wakeup_log(struct sctp_tcb *stcb, - uint32_t wake_cnt, int from); - -void sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t, uint16_t, uint16_t, int); - -void sctp_log_nagle_event(struct sctp_tcb *stcb, int action); - -#ifdef SCTP_MBUF_LOGGING -void -sctp_log_mb(struct mbuf *m, int from); - -void -sctp_log_mbc(struct mbuf *m, int from); -#endif - -void -sctp_sblog(struct sockbuf *sb, - struct sctp_tcb *stcb, int from, int incr); - -void -sctp_log_strm_del(struct sctp_queued_to_read *control, - struct sctp_queued_to_read *poschk, - int from); -void sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *, int, uint8_t); -void rto_logging(struct sctp_nets *net, int from); - -void sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc); - -void sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from); -void sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *, int, int, uint8_t); -void sctp_log_block(uint8_t, struct sctp_association *, ssize_t); -void sctp_log_rwnd(uint8_t, uint32_t, uint32_t, uint32_t); -void sctp_log_rwnd_set(uint8_t, uint32_t, uint32_t, uint32_t, uint32_t); -int sctp_fill_stat_log(void *, size_t *); -void sctp_log_fr(uint32_t, uint32_t, uint32_t, int); -void sctp_log_sack(uint32_t, uint32_t, uint32_t, uint16_t, uint16_t, int); -void sctp_log_map(uint32_t, uint32_t, uint32_t, int); -void sctp_print_mapping_array(struct sctp_association *asoc); -void sctp_clr_stat_log(void); - -#ifdef SCTP_AUDITING_ENABLED -void -sctp_auditing(int, struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *); -void sctp_audit_log(uint8_t, uint8_t); - -#endif -uint32_t sctp_min_mtu(uint32_t, uint32_t, uint32_t); -#if defined(__FreeBSD__) && !defined(__Userspace__) -void sctp_hc_set_mtu(union sctp_sockstore *, uint16_t, uint32_t); -uint32_t sctp_hc_get_mtu(union sctp_sockstore *, uint16_t); -#endif -void sctp_set_state(struct sctp_tcb *, int); -void sctp_add_substate(struct sctp_tcb *, int); -uint32_t sctp_ticks_to_msecs(uint32_t); -uint32_t sctp_msecs_to_ticks(uint32_t); -uint32_t sctp_ticks_to_secs(uint32_t); -uint32_t sctp_secs_to_ticks(uint32_t); - -#endif /* _KERNEL */ -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_usrreq.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_usrreq.c deleted file mode 100644 index 199a9bdc..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_usrreq.c +++ /dev/null @@ -1,1750 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#ifdef INET6 -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#include -#endif -#if defined(__Userspace__) -int ip6_v6only=0; -#endif -#if defined(__Userspace__) -#ifdef INET -void -in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) -{ -#if defined(_WIN32) - uint32_t temp; -#endif - memset(sin, 0, sizeof(*sin)); -#ifdef HAVE_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_family = AF_INET; - sin->sin_port = sin6->sin6_port; -#if defined(_WIN32) - temp = sin6->sin6_addr.s6_addr16[7]; - temp = temp << 16; - temp = temp | sin6->sin6_addr.s6_addr16[6]; - sin->sin_addr.s_addr = temp; -#else - sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; -#endif -} - -void -in6_sin6_2_sin_in_sock(struct sockaddr *nam) -{ - struct sockaddr_in *sin_p; - struct sockaddr_in6 sin6; - - /* save original sockaddr_in6 addr and convert it to sockaddr_in */ - sin6 = *(struct sockaddr_in6 *)nam; - sin_p = (struct sockaddr_in *)nam; - in6_sin6_2_sin(sin_p, &sin6); -} - -void -in6_sin_2_v4mapsin6(const struct sockaddr_in *sin, struct sockaddr_in6 *sin6) -{ - memset(sin6, 0, sizeof(struct sockaddr_in6)); - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6->sin6_port = sin->sin_port; -#if defined(_WIN32) - ((uint32_t *)&sin6->sin6_addr)[0] = 0; - ((uint32_t *)&sin6->sin6_addr)[1] = 0; - ((uint32_t *)&sin6->sin6_addr)[2] = htonl(0xffff); - ((uint32_t *)&sin6->sin6_addr)[3] = sin->sin_addr.s_addr; -#else - sin6->sin6_addr.s6_addr32[0] = 0; - sin6->sin6_addr.s6_addr32[1] = 0; - sin6->sin6_addr.s6_addr32[2] = htonl(0xffff); - sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; -#endif -} -#endif -#endif - -#if !defined(__Userspace__) -int -#if defined(__APPLE__) || defined(__FreeBSD__) -sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port) -#else -sctp6_input(struct mbuf **i_pak, int *offp, int proto) -#endif -{ - struct mbuf *m; - int iphlen; - uint32_t vrf_id; - uint8_t ecn_bits; - struct sockaddr_in6 src, dst; - struct ip6_hdr *ip6; - struct sctphdr *sh; - struct sctp_chunkhdr *ch; - int length, offset; - uint8_t compute_crc; -#if defined(__FreeBSD__) - uint32_t mflowid; - uint8_t mflowtype; - uint16_t fibnum; -#endif -#if !(defined(__APPLE__) || defined(__FreeBSD__)) - uint16_t port = 0; -#endif - - iphlen = *offp; - if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) { - SCTP_RELEASE_PKT(*i_pak); - return (IPPROTO_DONE); - } - m = SCTP_HEADER_TO_CHAIN(*i_pak); -#ifdef SCTP_MBUF_LOGGING - /* Log in any input mbufs */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { - sctp_log_mbc(m, SCTP_MBUF_INPUT); - } -#endif -#ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { - sctp_packet_log(m); - } -#endif -#if defined(__FreeBSD__) - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n", - m->m_pkthdr.len, - if_name(m->m_pkthdr.rcvif), - (int)m->m_pkthdr.csum_flags, CSUM_BITS); -#endif -#if defined(__APPLE__) - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp6_input(): Packet of length %d received on %s%d with csum_flags 0x%x.\n", - m->m_pkthdr.len, - m->m_pkthdr.rcvif->if_name, - m->m_pkthdr.rcvif->if_unit, - m->m_pkthdr.csum_flags); -#endif -#if defined(_WIN32) && !defined(__Userspace__) - SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, - "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", - m->m_pkthdr.len, - m->m_pkthdr.rcvif->if_xname, - m->m_pkthdr.csum_flags); -#endif -#if defined(__FreeBSD__) - mflowid = m->m_pkthdr.flowid; - mflowtype = M_HASHTYPE_GET(m); - fibnum = M_GETFIB(m); -#endif - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - /* Get IP, SCTP, and first chunk header together in the first mbuf. */ - offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (m->m_len < offset) { - m = m_pullup(m, offset); - if (m == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - return (IPPROTO_DONE); - } - } - ip6 = mtod(m, struct ip6_hdr *); - sh = (struct sctphdr *)(mtod(m, caddr_t) + iphlen); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - memset(&src, 0, sizeof(struct sockaddr_in6)); - src.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - src.sin6_len = sizeof(struct sockaddr_in6); -#endif - src.sin6_port = sh->src_port; - src.sin6_addr = ip6->ip6_src; -#if defined(__FreeBSD__) -#if defined(__APPLE__) - /* XXX: This code should also be used on Apple */ -#endif - if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) { - goto out; - } -#endif - memset(&dst, 0, sizeof(struct sockaddr_in6)); - dst.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - dst.sin6_len = sizeof(struct sockaddr_in6); -#endif - dst.sin6_port = sh->dest_port; - dst.sin6_addr = ip6->ip6_dst; -#if defined(__FreeBSD__) -#if defined(__APPLE__) - /* XXX: This code should also be used on Apple */ -#endif - if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) { - goto out; - } -#endif -#if defined(__APPLE__) -#if defined(NFAITH) && 0 < NFAITH - if (faithprefix(&dst.sin6_addr)) { - goto out; - } -#endif -#endif - length = ntohs(ip6->ip6_plen) + iphlen; - /* Validate mbuf chain length with IP payload length. */ - if (SCTP_HEADER_LEN(m) != length) { - SCTPDBG(SCTP_DEBUG_INPUT1, - "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m)); - SCTP_STAT_INCR(sctps_hdrops); - goto out; - } - if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - goto out; - } -#if defined(__FreeBSD__) - ecn_bits = IPV6_TRAFFIC_CLASS(ip6); - if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { - SCTP_STAT_INCR(sctps_recvhwcrc); - compute_crc = 0; - } else { -#else - ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (IN6_ARE_ADDR_EQUAL(&src.sin6_addr, &dst.sin6_addr))) { - SCTP_STAT_INCR(sctps_recvhwcrc); - compute_crc = 0; - } else { -#endif - SCTP_STAT_INCR(sctps_recvswcrc); - compute_crc = 1; - } - sctp_common_input_processing(&m, iphlen, offset, length, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - compute_crc, - ecn_bits, -#if defined(__FreeBSD__) - mflowtype, mflowid, fibnum, -#endif - vrf_id, port); - out: - if (m) { - sctp_m_freem(m); - } - return (IPPROTO_DONE); -} - -#if defined(__APPLE__) -int -sctp6_input(struct mbuf **i_pak, int *offp) -{ - return (sctp6_input_with_port(i_pak, offp, 0)); -} -#endif -#if defined(__FreeBSD__) -int -sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED) -{ - return (sctp6_input_with_port(i_pak, offp, 0)); -} -#endif - -void -sctp6_notify(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net, - uint8_t icmp6_type, - uint8_t icmp6_code, - uint32_t next_mtu) -{ -#if defined(__APPLE__) - struct socket *so; -#endif - int timer_stopped; - - switch (icmp6_type) { - case ICMP6_DST_UNREACH: - if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) || - (icmp6_code == ICMP6_DST_UNREACH_ADMIN) || - (icmp6_code == ICMP6_DST_UNREACH_BEYONDSCOPE) || - (icmp6_code == ICMP6_DST_UNREACH_ADDR)) { - /* Mark the net unreachable. */ - if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* Ok that destination is not reachable */ - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state &= ~SCTP_ADDR_PF; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED); - } - } - SCTP_TCB_UNLOCK(stcb); - break; - case ICMP6_PARAM_PROB: - /* Treat it like an ABORT. */ - if (icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) { - sctp_abort_notification(stcb, true, false, 0, NULL, SCTP_SO_NOT_LOCKED); -#if defined(__APPLE__) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); -#endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); -#if defined(__APPLE__) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } else { - SCTP_TCB_UNLOCK(stcb); - } - break; - case ICMP6_PACKET_TOO_BIG: - if (net->dest_state & SCTP_ADDR_NO_PMTUD) { - SCTP_TCB_UNLOCK(stcb); - break; - } - if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - timer_stopped = 1; - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); - } else { - timer_stopped = 0; - } - /* Update the path MTU. */ - if (net->port) { - next_mtu -= sizeof(struct udphdr); - } - if (net->mtu > next_mtu) { - net->mtu = next_mtu; -#if defined(__FreeBSD__) - if (net->port) { - sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr)); - } else { - sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu); - } -#endif - } - /* Update the association MTU */ - if (stcb->asoc.smallest_mtu > next_mtu) { - sctp_pathmtu_adjustment(stcb, next_mtu, true); - } - /* Finally, start the PMTU timer if it was running before. */ - if (timer_stopped) { - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); - } - SCTP_TCB_UNLOCK(stcb); - break; - default: - SCTP_TCB_UNLOCK(stcb); - break; - } -} - -#if defined(__FreeBSD__) && !defined(__Userspace__) -void -sctp6_ctlinput(struct ip6ctlparam *ip6cp) -{ - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sctphdr sh; - struct sockaddr_in6 src, dst; - - if (icmp6_errmap(ip6cp->ip6c_icmp6) == 0) { - return; - } - - /* - * Check if we can safely examine the ports and the - * verification tag of the SCTP common header. - */ - if (ip6cp->ip6c_m->m_pkthdr.len < - (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { - return; - } - - /* Copy out the port numbers and the verification tag. */ - memset(&sh, 0, sizeof(sh)); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off, - sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), - (caddr_t)&sh); - memset(&src, 0, sizeof(struct sockaddr_in6)); - src.sin6_family = AF_INET6; - src.sin6_len = sizeof(struct sockaddr_in6); - src.sin6_port = sh.src_port; - src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; - if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { - return; - } - memset(&dst, 0, sizeof(struct sockaddr_in6)); - dst.sin6_family = AF_INET6; - dst.sin6_len = sizeof(struct sockaddr_in6); - dst.sin6_port = sh.dest_port; - dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; - if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { - return; - } - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the verification tag */ - if (ntohl(sh.v_tag) != 0) { - /* - * This must be the verification tag used for - * sending out packets. We don't consider - * packets reflecting the verification tag. - */ - if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - if (ip6cp->ip6c_m->m_pkthdr.len >= - ip6cp->ip6c_off + sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr) + - offsetof(struct sctp_init, a_rwnd)) { - /* - * In this case we can check if we - * got an INIT chunk and if the - * initiate tag matches. - */ - uint32_t initiate_tag; - uint8_t chunk_type; - - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + - sizeof(struct sctphdr), - sizeof(uint8_t), - (caddr_t)&chunk_type); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + - sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr), - sizeof(uint32_t), - (caddr_t)&initiate_tag); - if ((chunk_type != SCTP_INITIATION) || - (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - } - sctp6_notify(inp, stcb, net, - ip6cp->ip6c_icmp6->icmp6_type, - ip6cp->ip6c_icmp6->icmp6_code, - ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce inp's ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } -} -#else -void -#if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN) -sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d, struct ifnet *ifp SCTP_UNUSED) -#else -sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) -#endif -{ - struct ip6ctlparam *ip6cp; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; - struct sctphdr sh; - struct sockaddr_in6 src, dst; - -#ifdef HAVE_SA_LEN - if (pktdst->sa_family != AF_INET6 || - pktdst->sa_len != sizeof(struct sockaddr_in6)) { -#else - if (pktdst->sa_family != AF_INET6) { -#endif - return; - } - - if ((unsigned)cmd >= PRC_NCMDS) { - return; - } - if (PRC_IS_REDIRECT(cmd)) { - d = NULL; - } else if (inet6ctlerrmap[cmd] == 0) { - return; - } - /* If the parameter is from icmp6, decode it. */ - if (d != NULL) { - ip6cp = (struct ip6ctlparam *)d; - } else { - ip6cp = (struct ip6ctlparam *)NULL; - } - - if (ip6cp != NULL) { - /* - * XXX: We assume that when IPV6 is non NULL, M and OFF are - * valid. - */ - if (ip6cp->ip6c_m == NULL) { - return; - } - - /* Check if we can safely examine the ports and the - * verification tag of the SCTP common header. - */ - if (ip6cp->ip6c_m->m_pkthdr.len < - (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { - return; - } - - /* Copy out the port numbers and the verification tag. */ - memset(&sh, 0, sizeof(sh)); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off, - sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), - (caddr_t)&sh); - memset(&src, 0, sizeof(struct sockaddr_in6)); - src.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - src.sin6_len = sizeof(struct sockaddr_in6); -#endif - src.sin6_port = sh.src_port; - src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; - memset(&dst, 0, sizeof(struct sockaddr_in6)); - dst.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - dst.sin6_len = sizeof(struct sockaddr_in6); -#endif - dst.sin6_port = sh.dest_port; - dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the verification tag */ - if (ntohl(sh.v_tag) != 0) { - /* - * This must be the verification tag used for - * sending out packets. We don't consider - * packets reflecting the verification tag. - */ - if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - sctp6_notify(inp, stcb, net, - ip6cp->ip6c_icmp6->icmp6_type, - ip6cp->ip6c_icmp6->icmp6_code, - ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); -#if defined(__Userspace__) - if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (stcb->sctp_socket != NULL)) { - struct socket *upcall_socket; - - upcall_socket = stcb->sctp_socket; - SOCK_LOCK(upcall_socket); - soref(upcall_socket); - SOCK_UNLOCK(upcall_socket); - if ((upcall_socket->so_upcall != NULL) && - (upcall_socket->so_error != 0)) { - (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); - } - ACCEPT_LOCK(); - SOCK_LOCK(upcall_socket); - sorele(upcall_socket); - } -#endif - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce inp's ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } - } -} -#endif -#endif - -/* - * this routine can probably be collasped into the one in sctp_userreq.c - * since they do the same thing and now we lookup with a sockaddr - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) -static int -sctp6_getcred(SYSCTL_HANDLER_ARGS) -{ - struct xucred xuc; - struct sockaddr_in6 addrs[2]; - struct sctp_inpcb *inp; - struct sctp_nets *net; - struct sctp_tcb *stcb; - int error; - uint32_t vrf_id; - - vrf_id = SCTP_DEFAULT_VRFID; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - error = priv_check(req->td, PRIV_NETINET_GETCRED); -#else - error = suser(req->p); -#endif - if (error) - return (error); - - if (req->newlen != sizeof(addrs)) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - if (req->oldlen != sizeof(struct ucred)) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - error = SYSCTL_IN(req, addrs, sizeof(addrs)); - if (error) - return (error); - - stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]), - sin6tosa(&addrs[0]), - &inp, &net, 1, vrf_id); - if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { - if ((inp != NULL) && (stcb == NULL)) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - goto cred_can_cont; - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); - error = ENOENT; - goto out; - } - SCTP_TCB_UNLOCK(stcb); - /* We use the write lock here, only - * since in the error leg we need it. - * If we used RLOCK, then we would have - * to wlock/decr/unlock/rlock. Which - * in theory could create a hole. Better - * to use higher wlock. - */ - SCTP_INP_WLOCK(inp); - cred_can_cont: - error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); - if (error) { - SCTP_INP_WUNLOCK(inp); - goto out; - } - cru2x(inp->sctp_socket->so_cred, &xuc); - SCTP_INP_WUNLOCK(inp); - error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); -out: - return (error); -} - -SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, - CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - 0, 0, sctp6_getcred, "S,ucred", - "Get the ucred of a SCTP6 connection"); -#endif - -#if defined(__Userspace__) -int -sctp6_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) -#elif defined(__FreeBSD__) -static int -sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) -#elif defined(_WIN32) -static int -sctp6_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED) -#else -static int -sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED) -#endif -{ - int error; - struct sctp_inpcb *inp; -#if !defined(__Userspace__) - uint32_t vrf_id = SCTP_DEFAULT_VRFID; -#endif - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp != NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); - if (error) - return (error); - } - error = sctp_inpcb_alloc(so, vrf_id); - if (error) - return (error); - inp = (struct sctp_inpcb *)so->so_pcb; - SCTP_INP_WLOCK(inp); - inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ - - inp->ip_inp.inp.inp_vflag |= INP_IPV6; - inp->ip_inp.inp.in6p_hops = -1; /* use kernel default */ - inp->ip_inp.inp.in6p_cksum = -1; /* just to be sure */ -#ifdef INET - /* - * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 - * socket as well, because the socket may be bound to an IPv6 - * wildcard address, which may match an IPv4-mapped IPv6 address. - */ - inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl); -#endif - SCTP_INP_WUNLOCK(inp); - return (0); -} - -#if defined(__Userspace__) -int -sctp6_bind(struct socket *so, struct sockaddr *addr, void * p) -{ -#elif defined(__FreeBSD__) -static int -sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) -{ -#elif defined(__APPLE__) -static int -sctp6_bind(struct socket *so, struct sockaddr *addr, struct proc *p) -{ -#elif defined(_WIN32) -static int -sctp6_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) -{ -#else -static int -sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p) -{ - struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL; - -#endif - struct sctp_inpcb *inp; - int error; - u_char vflagsav; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - -#if !(defined(_WIN32) && !defined(__Userspace__)) - if (addr) { - switch (addr->sa_family) { -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - } -#endif - vflagsav = inp->ip_inp.inp.inp_vflag; - inp->ip_inp.inp.inp_vflag &= ~INP_IPV4; - inp->ip_inp.inp.inp_vflag |= INP_IPV6; - if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp) == 0)) { - switch (addr->sa_family) { -#ifdef INET - case AF_INET: - /* binding v4 addr to v6 socket, so reset flags */ - inp->ip_inp.inp.inp_vflag |= INP_IPV4; - inp->ip_inp.inp.inp_vflag &= ~INP_IPV6; - break; -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6_p; - - sin6_p = (struct sockaddr_in6 *)addr; - - if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { - inp->ip_inp.inp.inp_vflag |= INP_IPV4; - } -#ifdef INET - if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { - struct sockaddr_in sin; - - in6_sin6_2_sin(&sin, sin6_p); - inp->ip_inp.inp.inp_vflag |= INP_IPV4; - inp->ip_inp.inp.inp_vflag &= ~INP_IPV6; - error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p); - goto out; - } -#endif - break; - } -#endif - default: - break; - } - } else if (addr != NULL) { - struct sockaddr_in6 *sin6_p; - - /* IPV6_V6ONLY socket */ -#ifdef INET - if (addr->sa_family == AF_INET) { - /* can't bind v4 addr to v6 only socket! */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - error = EINVAL; - goto out; - } -#endif - sin6_p = (struct sockaddr_in6 *)addr; - - if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { - /* can't bind v4-mapped addrs either! */ - /* NOTE: we don't support SIIT */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - error = EINVAL; - goto out; - } - } - error = sctp_inpcb_bind(so, addr, NULL, p); -out: - if (error != 0) - inp->ip_inp.inp.inp_vflag = vflagsav; - return (error); -} - -#if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__) -#if !defined(__Userspace__) -static void -#else -void -#endif -sctp6_close(struct socket *so) -{ - sctp_close(so); -} - -/* This could be made common with sctp_detach() since they are identical */ -#else - -static -int -sctp6_detach(struct socket *so) -{ -#if defined(__Userspace__) - sctp_close(so); - return (0); -#else - return (sctp_detach(so)); -#endif -} - -#endif - -int -#if defined(__FreeBSD__) && !defined(__Userspace__) -sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *p); -#else -sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct proc *p); -#endif - -#if !defined(_WIN32) && !defined(__Userspace__) -#if defined(__FreeBSD__) -static int -sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *p) -{ -#elif defined(__APPLE__) -static int -sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct proc *p) -{ -#else -static int -sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam, - struct mbuf *control, struct proc *p) -{ - struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL; -#endif - struct sctp_inpcb *inp; - -#ifdef INET - struct sockaddr_in6 *sin6; -#endif /* INET */ - /* No SPL needed since sctp_output does this */ - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_RELEASE_PKT(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - /* - * For the TCP model we may get a NULL addr, if we are a connected - * socket thats ok. - */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && - (addr == NULL)) { - goto connected_type; - } - if (addr == NULL) { - SCTP_RELEASE_PKT(m); - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); - return (EDESTADDRREQ); - } - switch (addr->sa_family) { -#ifdef INET - case AF_INET: -#if defined(HAVE_SA_LEN) - if (addr->sa_len != sizeof(struct sockaddr_in)) { - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_RELEASE_PKT(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: -#if defined(HAVE_SA_LEN) - if (addr->sa_len != sizeof(struct sockaddr_in6)) { - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_RELEASE_PKT(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif - default: - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_RELEASE_PKT(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#ifdef INET - sin6 = (struct sockaddr_in6 *)addr; - if (SCTP_IPV6_V6ONLY(inp)) { - /* - * if IPV6_V6ONLY flag, we discard datagrams destined to a - * v4 addr or v4-mapped addr - */ - if (addr->sa_family == AF_INET) { - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_RELEASE_PKT(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - if (control) { - SCTP_RELEASE_PKT(control); - control = NULL; - } - SCTP_RELEASE_PKT(m); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - } - if ((addr->sa_family == AF_INET6) && - IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - struct sockaddr_in sin; - - /* convert v4-mapped into v4 addr and send */ - in6_sin6_2_sin(&sin, sin6); - return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p)); - } -#endif /* INET */ -connected_type: - /* now what about control */ - if (control) { - if (inp->control) { - SCTP_PRINTF("huh? control set?\n"); - SCTP_RELEASE_PKT(inp->control); - inp->control = NULL; - } - inp->control = control; - } - /* Place the data */ - if (inp->pkt) { - SCTP_BUF_NEXT(inp->pkt_last) = m; - inp->pkt_last = m; - } else { - inp->pkt_last = inp->pkt = m; - } - if ( -#if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) - /* FreeBSD and MacOSX uses a flag passed */ - ((flags & PRUS_MORETOCOME) == 0) -#else - 1 /* Open BSD does not have any "more to come" - * indication */ -#endif - ) { - /* - * note with the current version this code will only be used - * by OpenBSD, NetBSD and FreeBSD have methods for - * re-defining sosend() to use sctp_sosend(). One can - * optionaly switch back to this code (by changing back the - * defininitions but this is not advisable. - */ -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - int ret; - -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - inp->pkt = NULL; - inp->control = NULL; - return (ret); - } else { - return (0); - } -} -#endif - -#if defined(__Userspace__) -int -sctp6_connect(struct socket *so, struct sockaddr *addr) -{ - void *p = NULL; -#elif defined(__FreeBSD__) -static int -sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) -{ -#elif defined(__APPLE__) -static int -sctp6_connect(struct socket *so, struct sockaddr *addr, struct proc *p) -{ -#elif defined(_WIN32) -static int -sctp6_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p) -{ -#else -static int -sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p) -{ - struct sockaddr *addr = mtod(nam, struct sockaddr *); -#endif -#if defined(__FreeBSD__) && !defined(__Userspace__) - struct epoch_tracker et; -#endif - uint32_t vrf_id; - int error = 0; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; -#ifdef INET - struct sockaddr_in6 *sin6; - union sctp_sockstore store; -#endif - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); - return (ECONNRESET); /* I made the same as TCP since we are - * not setup? */ - } - if (addr == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#if !(defined(_WIN32) && !defined(__Userspace__)) - switch (addr->sa_family) { -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (addr->sa_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - break; -#endif - default: - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } -#endif - - vrf_id = inp->def_vrf_id; - SCTP_ASOC_CREATE_LOCK(inp); - SCTP_INP_RLOCK(inp); - if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == - SCTP_PCB_FLAGS_UNBOUND) { - /* Bind a ephemeral port */ - SCTP_INP_RUNLOCK(inp); - error = sctp6_bind(so, NULL, p); - if (error) { - SCTP_ASOC_CREATE_UNLOCK(inp); - - return (error); - } - SCTP_INP_RLOCK(inp); - } - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { - /* We are already connected AND the TCP model */ - SCTP_INP_RUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE); - return (EADDRINUSE); - } -#ifdef INET - sin6 = (struct sockaddr_in6 *)addr; - if (SCTP_IPV6_V6ONLY(inp)) { - /* - * if IPV6_V6ONLY flag, ignore connections destined to a v4 - * addr or v4-mapped addr - */ - if (addr->sa_family == AF_INET) { - SCTP_INP_RUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - SCTP_INP_RUNLOCK(inp); - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - } - if ((addr->sa_family == AF_INET6) && - IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - /* convert v4-mapped into v4 addr */ - in6_sin6_2_sin(&store.sin, sin6); - addr = &store.sa; - } -#endif /* INET */ - /* Now do we connect? */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb) { - SCTP_TCB_LOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - } else { - SCTP_INP_RUNLOCK(inp); - SCTP_INP_WLOCK(inp); - SCTP_INP_INCR_REF(inp); - SCTP_INP_WUNLOCK(inp); - stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); - if (stcb == NULL) { - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - } - - if (stcb != NULL) { - /* Already have or am bring up an association */ - SCTP_ASOC_CREATE_UNLOCK(inp); - SCTP_TCB_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY); - return (EALREADY); - } - /* We are GOOD to go */ - stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, - inp->sctp_ep.pre_open_stream_count, - inp->sctp_ep.port, p, - SCTP_INITIALIZE_AUTH_PARAMS); - SCTP_ASOC_CREATE_UNLOCK(inp); - if (stcb == NULL) { - /* Gak! no memory */ - return (error); - } - SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); - (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_ENTER(et); -#endif - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - SCTP_TCB_UNLOCK(stcb); -#if defined(__FreeBSD__) && !defined(__Userspace__) - NET_EPOCH_EXIT(et); -#endif - return (error); -} - -static int -#if !defined(__Userspace__) -sctp6_getaddr(struct socket *so, struct sockaddr **addr) -{ - struct sockaddr_in6 *sin6; -#else -sctp6_getaddr(struct socket *so, struct mbuf *nam) -{ - struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *); -#endif - struct sctp_inpcb *inp; - uint32_t vrf_id; - struct sctp_ifa *sctp_ifa; - -#if defined(SCTP_KAME) && defined(SCTP_EMBEDDED_V6_SCOPE) - int error; -#endif - - /* - * Do the malloc first in case it blocks. - */ -#if !defined(__Userspace__) - SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6)); - if (sin6 == NULL) - return (ENOMEM); -#else - SCTP_BUF_LEN(nam) = sizeof(*sin6); - memset(sin6, 0, sizeof(*sin6)); -#endif - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(*sin6); -#endif - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); - return (ECONNRESET); - } - SCTP_INP_RLOCK(inp); - sin6->sin6_port = inp->sctp_lport; - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - /* For the bound all case you get back 0 */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { - struct sctp_tcb *stcb; - struct sockaddr_in6 *sin_a6; - struct sctp_nets *net; - int fnd; - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); - return (ENOENT); - } - fnd = 0; - sin_a6 = NULL; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; - if (sin_a6 == NULL) - /* this will make coverity happy */ - continue; - - if (sin_a6->sin6_family == AF_INET6) { - fnd = 1; - break; - } - } - if ((!fnd) || (sin_a6 == NULL)) { - /* punt */ - SCTP_INP_RUNLOCK(inp); -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); - return (ENOENT); - } - vrf_id = inp->def_vrf_id; - sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id); - if (sctp_ifa) { - sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr; - } - } else { - /* For the bound all case you get back 0 */ - memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); - } - } else { - /* Take the first IPv6 address in the list */ - struct sctp_laddr *laddr; - int fnd = 0; - - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { - if (laddr->ifa->address.sa.sa_family == AF_INET6) { - struct sockaddr_in6 *sin_a; - - sin_a = &laddr->ifa->address.sin6; - sin6->sin6_addr = sin_a->sin6_addr; - fnd = 1; - break; - } - } - if (!fnd) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); - return (ENOENT); - } - } - SCTP_INP_RUNLOCK(inp); - /* Scoping things for v6 */ -#ifdef SCTP_EMBEDDED_V6_SCOPE -#ifdef SCTP_KAME - if ((error = sa6_recoverscope(sin6)) != 0) { - SCTP_FREE_SONAME(sin6); - return (error); - } -#else - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) - /* skip ifp check below */ - in6_recoverscope(sin6, &sin6->sin6_addr, NULL); - else - sin6->sin6_scope_id = 0; /* XXX */ -#endif /* SCTP_KAME */ -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#if !defined(__Userspace__) - (*addr) = (struct sockaddr *)sin6; -#endif - return (0); -} - -static int -#if !defined(__Userspace__) -sctp6_peeraddr(struct socket *so, struct sockaddr **addr) -{ - struct sockaddr_in6 *sin6; -#else -sctp6_peeraddr(struct socket *so, struct mbuf *nam) -{ - struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *); -#endif - int fnd; - struct sockaddr_in6 *sin_a6; - struct sctp_inpcb *inp; - struct sctp_tcb *stcb; - struct sctp_nets *net; -#ifdef SCTP_KAME - int error; -#endif - - /* Do the malloc first in case it blocks. */ -#if !defined(__Userspace__) - SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); - if (sin6 == NULL) - return (ENOMEM); -#else - SCTP_BUF_LEN(nam) = sizeof(*sin6); - memset(sin6, 0, sizeof(*sin6)); -#endif - sin6->sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - sin6->sin6_len = sizeof(*sin6); -#endif - - inp = (struct sctp_inpcb *)so->so_pcb; - if ((inp == NULL) || - ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { - /* UDP type and listeners will drop out here */ -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); - return (ENOTCONN); - } - SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb) { - SCTP_TCB_LOCK(stcb); - } - SCTP_INP_RUNLOCK(inp); - if (stcb == NULL) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); - return (ECONNRESET); - } - fnd = 0; - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; - if (sin_a6->sin6_family == AF_INET6) { - fnd = 1; - sin6->sin6_port = stcb->rport; - sin6->sin6_addr = sin_a6->sin6_addr; - break; - } - } - SCTP_TCB_UNLOCK(stcb); - if (!fnd) { - /* No IPv4 address */ -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); - return (ENOENT); - } -#ifdef SCTP_EMBEDDED_V6_SCOPE -#ifdef SCTP_KAME - if ((error = sa6_recoverscope(sin6)) != 0) { -#if !defined(__Userspace__) - SCTP_FREE_SONAME(sin6); -#endif - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error); - return (error); - } -#else - in6_recoverscope(sin6, &sin6->sin6_addr, NULL); -#endif /* SCTP_KAME */ -#endif /* SCTP_EMBEDDED_V6_SCOPE */ -#if !defined(__Userspace__) - *addr = (struct sockaddr *)sin6; -#endif - return (0); -} - -#if !defined(__Userspace__) -static int -sctp6_in6getaddr(struct socket *so, struct sockaddr **nam) -{ -#elif defined(__Userspace__) -int -sctp6_in6getaddr(struct socket *so, struct mbuf *nam) -{ -#ifdef INET - struct sockaddr *addr = mtod(nam, struct sockaddr *); -#endif -#else -static int -sctp6_in6getaddr(struct socket *so, struct mbuf *nam) -{ -#ifdef INET - struct sockaddr *addr = mtod(nam, struct sockaddr *); -#endif -#endif - struct inpcb *inp = sotoinpcb(so); - int error; - - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - - /* allow v6 addresses precedence */ - error = sctp6_getaddr(so, nam); -#ifdef INET - if (error) { -#if !defined(__Userspace__) - struct sockaddr_in6 *sin6; -#else - struct sockaddr_in6 sin6; -#endif - - /* try v4 next if v6 failed */ - error = sctp_ingetaddr(so, nam); - if (error) { - return (error); - } -#if !defined(__Userspace__) - SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); - if (sin6 == NULL) { - SCTP_FREE_SONAME(*nam); - return (ENOMEM); - } - in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6); - SCTP_FREE_SONAME(*nam); - *nam = (struct sockaddr *)sin6; -#else - in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); - SCTP_BUF_LEN(nam) = sizeof(struct sockaddr_in6); - memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); -#endif - } -#endif - return (error); -} - -#if !defined(__Userspace__) -static int -sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) -{ -#elif defined(__Userspace__) -int -sctp6_getpeeraddr(struct socket *so, struct mbuf *nam) -{ -#ifdef INET - struct sockaddr *addr = mtod(nam, struct sockaddr *); -#endif -#else -static -int -sctp6_getpeeraddr(struct socket *so, struct mbuf *nam) -{ -#ifdef INET - struct sockaddr *addr = mtod(nam, struct sockaddr *); -#endif - -#endif - struct inpcb *inp = sotoinpcb(so); - int error; - - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - - /* allow v6 addresses precedence */ - error = sctp6_peeraddr(so, nam); -#ifdef INET - if (error) { -#if !defined(__Userspace__) - struct sockaddr_in6 *sin6; -#else - struct sockaddr_in6 sin6; -#endif - - /* try v4 next if v6 failed */ - error = sctp_peeraddr(so, nam); - if (error) { - return (error); - } -#if !defined(__Userspace__) - SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); - if (sin6 == NULL) { - SCTP_FREE_SONAME(*nam); - return (ENOMEM); - } - in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6); - SCTP_FREE_SONAME(*nam); - *nam = (struct sockaddr *)sin6; -#else - in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); - SCTP_BUF_LEN(nam) = sizeof(struct sockaddr_in6); - memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); -#endif - } -#endif - return (error); -} - -#if !defined(__Userspace__) -#if defined(__FreeBSD__) -#define SCTP6_PROTOSW \ - .pr_protocol = IPPROTO_SCTP, \ - .pr_ctloutput = sctp_ctloutput, \ - .pr_abort = sctp_abort, \ - .pr_accept = sctp_accept, \ - .pr_attach = sctp6_attach, \ - .pr_bind = sctp6_bind, \ - .pr_connect = sctp6_connect, \ - .pr_control = in6_control, \ - .pr_close = sctp6_close, \ - .pr_detach = sctp6_close, \ - .pr_sopoll = sopoll_generic, \ - .pr_flush = sctp_flush, \ - .pr_disconnect = sctp_disconnect, \ - .pr_listen = sctp_listen, \ - .pr_peeraddr = sctp6_getpeeraddr, \ - .pr_send = sctp6_send, \ - .pr_shutdown = sctp_shutdown, \ - .pr_sockaddr = sctp6_in6getaddr, \ - .pr_sosend = sctp_sosend, \ - .pr_soreceive = sctp_soreceive - -struct protosw sctp6_seqpacket_protosw = { - .pr_type = SOCK_SEQPACKET, - .pr_flags = PR_WANTRCVD, - SCTP6_PROTOSW -}; - -struct protosw sctp6_stream_protosw = { - .pr_type = SOCK_STREAM, - .pr_flags = PR_CONNREQUIRED | PR_WANTRCVD, - SCTP6_PROTOSW -}; -#else -struct pr_usrreqs sctp6_usrreqs = { -#if defined(__APPLE__) && !defined(__Userspace__) - .pru_abort = sctp_abort, - .pru_accept = sctp_accept, - .pru_attach = sctp6_attach, - .pru_bind = sctp6_bind, - .pru_connect = sctp6_connect, - .pru_connect2 = pru_connect2_notsupp, - .pru_control = in6_control, - .pru_detach = sctp6_detach, - .pru_disconnect = sctp_disconnect, - .pru_listen = sctp_listen, - .pru_peeraddr = sctp6_getpeeraddr, - .pru_rcvd = NULL, - .pru_rcvoob = pru_rcvoob_notsupp, - .pru_send = sctp6_send, - .pru_sense = pru_sense_null, - .pru_shutdown = sctp_shutdown, - .pru_sockaddr = sctp6_in6getaddr, - .pru_sosend = sctp_sosend, - .pru_soreceive = sctp_soreceive, - .pru_sopoll = sopoll -#elif defined(_WIN32) && !defined(__Userspace__) - sctp_abort, - sctp_accept, - sctp6_attach, - sctp6_bind, - sctp6_connect, - pru_connect2_notsupp, - NULL, - NULL, - sctp_disconnect, - sctp_listen, - sctp6_getpeeraddr, - NULL, - pru_rcvoob_notsupp, - NULL, - pru_sense_null, - sctp_shutdown, - sctp_flush, - sctp6_in6getaddr, - sctp_sosend, - sctp_soreceive, - sopoll_generic, - NULL, - sctp6_close -}; -#endif -#endif -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_var.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_var.h deleted file mode 100644 index e4d737b2..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/netinet6/sctp6_var.h +++ /dev/null @@ -1,87 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. - * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * b) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * c) Neither the name of Cisco Systems, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__FreeBSD__) && !defined(__Userspace__) -#include -__FBSDID("$FreeBSD$"); -#endif - -#ifndef _NETINET6_SCTP6_VAR_H_ -#define _NETINET6_SCTP6_VAR_H_ - -#if defined(__Userspace__) -#ifdef INET -extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *); -extern void in6_sin6_2_sin_in_sock(struct sockaddr *); -extern void in6_sin_2_v4mapsin6(const struct sockaddr_in *, struct sockaddr_in6 *); -#endif -#endif -#if defined(_KERNEL) - -#if !defined(__Userspace__) -SYSCTL_DECL(_net_inet6_sctp6); -#if defined(__FreeBSD__) -extern struct protosw sctp6_seqpacket_protosw, sctp6_stream_protosw; -#else -extern struct pr_usrreqs sctp6_usrreqs; -#endif -#else -int sctp6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *); -#endif - -#if defined(__APPLE__) && !defined(__Userspace__) -int sctp6_input(struct mbuf **, int *); -int sctp6_input_with_port(struct mbuf **, int *, uint16_t); -#else -int sctp6_input(struct mbuf **, int *, int); -int sctp6_input_with_port(struct mbuf **, int *, uint16_t); -#endif -int sctp6_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *, - struct mbuf *, struct proc *); -#if defined(__APPLE__) && !defined(__Userspace__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN) -void sctp6_ctlinput(int, struct sockaddr *, void *, struct ifnet * SCTP_UNUSED); -#elif defined(__FreeBSD__) && !defined(__Userspace__) -ip6proto_ctlinput_t sctp6_ctlinput; -#else -void sctp6_ctlinput(int, struct sockaddr_in6 *, ip6ctlparam *); -#endif -#if !((defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)) -extern void in6_sin_2_v4mapsin6(struct sockaddr_in *, struct sockaddr_in6 *); -extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *); -extern void in6_sin6_2_sin_in_sock(struct sockaddr *); -#endif -void sctp6_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, - uint8_t, uint8_t, uint32_t); -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_atomic.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_atomic.h deleted file mode 100644 index 6a59587e..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_atomic.h +++ /dev/null @@ -1,315 +0,0 @@ -/*- - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USER_ATOMIC_H_ -#define _USER_ATOMIC_H_ - -/* __Userspace__ version of sys/i386/include/atomic.h goes here */ - -/* TODO In the future, might want to not use i386 specific assembly. - * The options include: - * - implement them generically (but maybe not truly atomic?) in userspace - * - have ifdef's for __Userspace_arch_ perhaps (OS isn't enough...) - */ - -#include -#include - -#if defined(__APPLE__) || defined(_WIN32) -#if defined(_WIN32) -#define atomic_add_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val) -#define atomic_fetchadd_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val) -#define atomic_subtract_int(addr, val) InterlockedExchangeAdd((LPLONG)addr,-((LONG)val)) -#define atomic_cmpset_int(dst, exp, src) InterlockedCompareExchange((LPLONG)dst, src, exp) -#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (InterlockedExchangeAdd((LPLONG)addr, (-1L)) == 1) -#else -#include -#define atomic_add_int(addr, val) OSAtomicAdd32Barrier(val, (int32_t *)addr) -#define atomic_fetchadd_int(addr, val) OSAtomicAdd32Barrier(val, (int32_t *)addr) -#define atomic_subtract_int(addr, val) OSAtomicAdd32Barrier(-val, (int32_t *)addr) -#define atomic_cmpset_int(dst, exp, src) OSAtomicCompareAndSwapIntBarrier(exp, src, (int *)dst) -#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 0) -#endif - -#if defined(INVARIANTS) -#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ -{ \ - int32_t newval; \ - newval = atomic_fetchadd_int(addr, -val); \ - if (newval < 0) { \ - panic("Counter goes negative"); \ - } \ -} -#else -#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ -{ \ - int32_t newval; \ - newval = atomic_fetchadd_int(addr, -val); \ - if (newval < 0) { \ - *addr = 0; \ - } \ -} -#endif -#if defined(_WIN32) -static void atomic_init(void) {} /* empty when we are not using atomic_mtx */ -#else -static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */ -#endif - -#else -/* Using gcc built-in functions for atomic memory operations - Reference: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html - Requires gcc version 4.1.0 - compile with -march=i486 - */ - -/*Atomically add V to *P.*/ -#define atomic_add_int(P, V) (void) __sync_fetch_and_add(P, V) - -/*Atomically subtrace V from *P.*/ -#define atomic_subtract_int(P, V) (void) __sync_fetch_and_sub(P, V) - -/* - * Atomically add the value of v to the integer pointed to by p and return - * the previous value of *p. - */ -#define atomic_fetchadd_int(p, v) __sync_fetch_and_add(p, v) - -/* Following explanation from src/sys/i386/include/atomic.h, - * for atomic compare and set - * - * if (*dst == exp) *dst = src (all 32 bit words) - * - * Returns 0 on failure, non-zero on success - */ - -#define atomic_cmpset_int(dst, exp, src) __sync_bool_compare_and_swap(dst, exp, src) - -#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 1) -#if defined(INVARIANTS) -#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ -{ \ - int32_t oldval; \ - oldval = atomic_fetchadd_int(addr, -val); \ - if (oldval < val) { \ - panic("Counter goes negative"); \ - } \ -} -#else -#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ -{ \ - int32_t oldval; \ - oldval = atomic_fetchadd_int(addr, -val); \ - if (oldval < val) { \ - *addr = 0; \ - } \ -} -#endif -static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */ -#endif - -#if 0 /* using libatomic_ops */ -#include "user_include/atomic_ops.h" - -/*Atomically add incr to *P, and return the original value of *P.*/ -#define atomic_add_int(P, V) AO_fetch_and_add((AO_t*)P, V) - -#define atomic_subtract_int(P, V) AO_fetch_and_add((AO_t*)P, -(V)) - -/* - * Atomically add the value of v to the integer pointed to by p and return - * the previous value of *p. - */ -#define atomic_fetchadd_int(p, v) AO_fetch_and_add((AO_t*)p, v) - -/* Atomically compare *addr to old_val, and replace *addr by new_val - if the first comparison succeeds. Returns nonzero if the comparison - succeeded and *addr was updated. -*/ -/* Following Explanation from src/sys/i386/include/atomic.h, which - matches that of AO_compare_and_swap above. - * Atomic compare and set, used by the mutex functions - * - * if (*dst == exp) *dst = src (all 32 bit words) - * - * Returns 0 on failure, non-zero on success - */ - -#define atomic_cmpset_int(dst, exp, src) AO_compare_and_swap((AO_t*)dst, exp, src) - -static inline void atomic_init() {} /* empty when we are not using atomic_mtx */ -#endif /* closing #if for libatomic */ - -#if 0 /* using atomic_mtx */ - -#include - -extern userland_mutex_t atomic_mtx; - -#if defined(_WIN32) -static inline void atomic_init() { - InitializeCriticalSection(&atomic_mtx); -} -static inline void atomic_destroy() { - DeleteCriticalSection(&atomic_mtx); -} -static inline void atomic_lock() { - EnterCriticalSection(&atomic_mtx); -} -static inline void atomic_unlock() { - LeaveCriticalSection(&atomic_mtx); -} -#else -static inline void atomic_init() { - pthread_mutexattr_t mutex_attr; - - pthread_mutexattr_init(&mutex_attr); -#ifdef INVARIANTS - pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK); -#endif - pthread_mutex_init(&accept_mtx, &mutex_attr); - pthread_mutexattr_destroy(&mutex_attr); -} -static inline void atomic_destroy() { - (void)pthread_mutex_destroy(&atomic_mtx); -} -static inline void atomic_lock() { -#ifdef INVARIANTS - KASSERT(pthread_mutex_lock(&atomic_mtx) == 0, ("atomic_lock: atomic_mtx already locked")) -#else - (void)pthread_mutex_lock(&atomic_mtx); -#endif -} -static inline void atomic_unlock() { -#ifdef INVARIANTS - KASSERT(pthread_mutex_unlock(&atomic_mtx) == 0, ("atomic_unlock: atomic_mtx not locked")) -#else - (void)pthread_mutex_unlock(&atomic_mtx); -#endif -} -#endif -/* - * For userland, always use lock prefixes so that the binaries will run - * on both SMP and !SMP systems. - */ - -#define MPLOCKED "lock ; " - -/* - * Atomically add the value of v to the integer pointed to by p and return - * the previous value of *p. - */ -static __inline u_int -atomic_fetchadd_int(volatile void *n, u_int v) -{ - int *p = (int *) n; - atomic_lock(); - __asm __volatile( - " " MPLOCKED " " - " xaddl %0, %1 ; " - "# atomic_fetchadd_int" - : "+r" (v), /* 0 (result) */ - "=m" (*p) /* 1 */ - : "m" (*p)); /* 2 */ - atomic_unlock(); - - return (v); -} - - -#ifdef CPU_DISABLE_CMPXCHG - -static __inline int -atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src) -{ - u_char res; - - atomic_lock(); - __asm __volatile( - " pushfl ; " - " cli ; " - " cmpl %3,%4 ; " - " jne 1f ; " - " movl %2,%1 ; " - "1: " - " sete %0 ; " - " popfl ; " - "# atomic_cmpset_int" - : "=q" (res), /* 0 */ - "=m" (*dst) /* 1 */ - : "r" (src), /* 2 */ - "r" (exp), /* 3 */ - "m" (*dst) /* 4 */ - : "memory"); - atomic_unlock(); - - return (res); -} - -#else /* !CPU_DISABLE_CMPXCHG */ - -static __inline int -atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src) -{ - atomic_lock(); - u_char res; - - __asm __volatile( - " " MPLOCKED " " - " cmpxchgl %2,%1 ; " - " sete %0 ; " - "1: " - "# atomic_cmpset_int" - : "=a" (res), /* 0 */ - "=m" (*dst) /* 1 */ - : "r" (src), /* 2 */ - "a" (exp), /* 3 */ - "m" (*dst) /* 4 */ - : "memory"); - atomic_unlock(); - - return (res); -} - -#endif /* CPU_DISABLE_CMPXCHG */ - -#define atomic_add_int(P, V) do { \ - atomic_lock(); \ - (*(u_int *)(P) += (V)); \ - atomic_unlock(); \ -} while(0) -#define atomic_subtract_int(P, V) do { \ - atomic_lock(); \ - (*(u_int *)(P) -= (V)); \ - atomic_unlock(); \ -} while(0) - -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.c deleted file mode 100644 index 3deb3ef0..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.c +++ /dev/null @@ -1,384 +0,0 @@ -/*- - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* __Userspace__ */ - -#if defined(_WIN32) -#if !defined(_CRT_RAND_S) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) -#define _CRT_RAND_S -#endif -#else -#include -#include -#endif -#ifdef INVARIANTS -#include -#endif -#include -#include -/* #include defines MIN */ -#if !defined(MIN) -#define MIN(arg1,arg2) ((arg1) < (arg2) ? (arg1) : (arg2)) -#endif - -#define uHZ 1000 - -/* See user_include/user_environment.h for comments about these variables */ -int maxsockets = 25600; -int hz = uHZ; -int ip_defttl = 64; -int ipport_firstauto = 49152, ipport_lastauto = 65535; -int nmbclusters = 65536; - -/* Source ip_output.c. extern'd in ip_var.h */ -u_short ip_id = 0; /*__Userspace__ TODO Should it be initialized to zero? */ - -/* used in user_include/user_atomic.h in order to make the operations - * defined there truly atomic - */ -userland_mutex_t atomic_mtx; - -/* If the entropy device is not loaded, make a token effort to - * provide _some_ kind of randomness. This should only be used - * inside other RNG's, like arc4random(9). - */ -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) -#include - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - memset(buf, 'A', size); - return; -} - -void -finish_random(void) -{ - return; -} -/* This define can be used to optionally use OpenSSL's random number utility, - * which is capable of bypassing the chromium sandbox which normally would - * prevent opening files, including /dev/urandom. - */ -#elif defined(SCTP_USE_OPENSSL_RAND) -#include - -/* Requiring BoringSSL because it guarantees that RAND_bytes will succeed. */ -#ifndef OPENSSL_IS_BORINGSSL -#error Only BoringSSL is supported with SCTP_USE_OPENSSL_RAND. -#endif - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - RAND_bytes((uint8_t *)buf, size); - return; -} - -void -finish_random(void) -{ - return; -} -#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__Bitrig__) -#include - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - arc4random_buf(buf, size); - return; -} - -void -finish_random(void) -{ - return; -} -#elif defined(_WIN32) -#include - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - unsigned int randval; - size_t position, remaining; - - position = 0; - while (position < size) { - if (rand_s(&randval) == 0) { - remaining = MIN(size - position, sizeof(unsigned int)); - memcpy((char *)buf + position, &randval, remaining); - position += sizeof(unsigned int); - } - } - return; -} - -void -finish_random(void) -{ - return; -} -#elif (defined(__ANDROID__) && (__ANDROID_API__ < 28)) || defined(__QNX__) || defined(__EMSCRIPTEN__) -#include - -static int fd = -1; - -void -init_random(void) -{ - fd = open("/dev/urandom", O_RDONLY); - return; -} - -void -read_random(void *buf, size_t size) -{ - size_t position; - ssize_t n; - - position = 0; - while (position < size) { - n = read(fd, (char *)buf + position, size - position); - if (n > 0) { - position += n; - } - } - return; -} - -void -finish_random(void) -{ - close(fd); - return; -} -#elif defined(__ANDROID__) && (__ANDROID_API__ >= 28) -#include - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - size_t position; - ssize_t n; - - position = 0; - while (position < size) { - n = getrandom((char *)buf + position, size - position, 0); - if (n > 0) { - position += n; - } - } - return; -} - -void -finish_random(void) -{ - return; -} -#elif defined(__linux__) -#include -#include -#include - -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) -void __msan_unpoison(void *, size_t); -#endif -#endif - -#ifdef __NR_getrandom -#if !defined(GRND_NONBLOCK) -#define GRND_NONBLOCK 1 -#endif -static int getrandom_available = 0; -#endif -static int fd = -1; - -void -init_random(void) -{ -#ifdef __NR_getrandom - char dummy; - ssize_t n = syscall(__NR_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); - if (n > 0 || errno == EINTR || errno == EAGAIN) { - /* Either getrandom succeeded, was interrupted or is waiting for entropy; - * all of which mean the syscall is available. - */ - getrandom_available = 1; - } else { -#ifdef INVARIANTS - if (errno != ENOSYS) { - panic("getrandom syscall returned unexpected error: %d", errno); - } -#endif - /* If the syscall isn't available, fall back to /dev/urandom. */ -#endif - fd = open("/dev/urandom", O_RDONLY); -#ifdef __NR_getrandom - } -#endif - return; -} - -void -read_random(void *buf, size_t size) -{ - size_t position; - ssize_t n; - - position = 0; - while (position < size) { -#ifdef __NR_getrandom - if (getrandom_available) { - /* Using syscall directly because getrandom isn't present in glibc < 2.25. - */ - n = syscall(__NR_getrandom, (char *)buf + position, size - position, 0); - if (n > 0) { -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) - /* Need to do this because MSan doesn't realize that syscall has - * initialized the output buffer. - */ - __msan_unpoison(buf + position, n); -#endif -#endif - position += n; - } else if (errno != EINTR && errno != EAGAIN) { -#ifdef INVARIANTS - panic("getrandom syscall returned unexpected error: %d", errno); -#endif - } - } else -#endif /* __NR_getrandom */ - { - n = read(fd, (char *)buf + position, size - position); - if (n > 0) { - position += n; - } - } - } - return; -} - -void -finish_random(void) -{ - if (fd != -1) { - close(fd); - } - return; -} -#elif defined(__Fuchsia__) -#include - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - zx_cprng_draw(buf, size); - return; -} - -void -finish_random(void) -{ - return; -} -#elif defined(__native_client__) -#include - -void -init_random(void) -{ - return; -} - -void -read_random(void *buf, size_t size) -{ - size_t position; - size_t n; - - position = 0; - while (position < size) { - if (nacl_secure_random((char *)buf + position, size - position, &n) == 0) - position += n; - } - } - return; -} - -void -finish_random(void) -{ - return; -} -#else -#error "Unknown platform. Please provide platform specific RNG." -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h deleted file mode 100644 index 4aa35201..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h +++ /dev/null @@ -1,123 +0,0 @@ -/*- - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USER_ENVIRONMENT_H_ -#define _USER_ENVIRONMENT_H_ -/* __Userspace__ */ -#include - -#ifdef __FreeBSD__ -#ifndef _SYS_MUTEX_H_ -#include -#endif -#endif -#if defined(_WIN32) -#include "netinet/sctp_os_userspace.h" -#endif - -/* maxsockets is used in SCTP_ZONE_INIT call. It refers to - * kern.ipc.maxsockets kernel environment variable. - */ -extern int maxsockets; - -/* int hz; is declared in sys/kern/subr_param.c and refers to kernel timer frequency. - * See http://ivoras.sharanet.org/freebsd/vmware.html for additional info about kern.hz - * hz is initialized in void init_param1(void) in that file. - */ -extern int hz; - - -/* The following two ints define a range of available ephemeral ports. */ -extern int ipport_firstauto, ipport_lastauto; - -/* nmbclusters is used in sctp_usrreq.c (e.g., sctp_init). In the FreeBSD kernel, - * this is 1024 + maxusers * 64. - */ -extern int nmbclusters; - -#if !defined(_MSC_VER) -#define min(a,b) (((a)>(b))?(b):(a)) -#define max(a,b) (((a)>(b))?(a):(b)) -#endif - -void init_random(void); -void read_random(void *, size_t); -void finish_random(void); - -/* errno's may differ per OS. errno.h now included in sctp_os_userspace.h */ -/* Source: /usr/src/sys/sys/errno.h */ -/* #define ENOSPC 28 */ /* No space left on device */ -/* #define ENOBUFS 55 */ /* No buffer space available */ -/* #define ENOMEM 12 */ /* Cannot allocate memory */ -/* #define EACCES 13 */ /* Permission denied */ -/* #define EFAULT 14 */ /* Bad address */ -/* #define EHOSTDOWN 64 */ /* Host is down */ -/* #define EHOSTUNREACH 65 */ /* No route to host */ - -/* Source ip_output.c. extern'd in ip_var.h */ -extern u_short ip_id; - -#if defined(__linux__) -#define IPV6_VERSION 0x60 -#endif - -#if defined(INVARIANTS) -#include - -#if defined(_WIN32) -static inline void __declspec(noreturn) -#else -static inline void __attribute__((__noreturn__)) -#endif -terminate_non_graceful(void) { - abort(); -} - -#define panic(...) \ - do { \ - SCTP_PRINTF("%s(): ", __func__); \ - SCTP_PRINTF(__VA_ARGS__); \ - SCTP_PRINTF("\n"); \ - terminate_non_graceful(); \ -} while (0) - -#define KASSERT(cond, args) \ - do { \ - if (!(cond)) { \ - panic args ; \ - } \ - } while (0) -#else -#define KASSERT(cond, args) -#endif - -/* necessary for sctp_pcb.c */ -extern int ip_defttl; -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_inpcb.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_inpcb.h deleted file mode 100644 index 2e6e9334..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_inpcb.h +++ /dev/null @@ -1,373 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)in_pcb.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: src/sys/netinet/in_pcb.h,v 1.100.2.1 2007/12/07 05:46:08 kmacy Exp $ - */ - -#ifndef _USER_INPCB_H_ -#define _USER_INPCB_H_ - -#include /* was */ - -struct inpcbpolicy; - -/* - * Struct inpcb is the ommon structure pcb for the Internet Protocol - * implementation. - * - * Pointers to local and foreign host table entries, local and foreign socket - * numbers, and pointers up (to a socket structure) and down (to a - * protocol-specific control block) are stored here. - */ -LIST_HEAD(inpcbhead, inpcb); -LIST_HEAD(inpcbporthead, inpcbport); - -/* - * PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet. - * So, AF_INET6 null laddr is also used as AF_INET null laddr, by utilizing - * the following structure. - */ -struct in_addr_4in6 { - uint32_t ia46_pad32[3]; - struct in_addr ia46_addr4; -}; - -/* - * NOTE: ipv6 addrs should be 64-bit aligned, per RFC 2553. in_conninfo has - * some extra padding to accomplish this. - */ -struct in_endpoints { - uint16_t ie_fport; /* foreign port */ - uint16_t ie_lport; /* local port */ - /* protocol dependent part, local and foreign addr */ - union { - /* foreign host table entry */ - struct in_addr_4in6 ie46_foreign; - struct in6_addr ie6_foreign; - } ie_dependfaddr; - union { - /* local host table entry */ - struct in_addr_4in6 ie46_local; - struct in6_addr ie6_local; - } ie_dependladdr; -#define ie_faddr ie_dependfaddr.ie46_foreign.ia46_addr4 -#define ie_laddr ie_dependladdr.ie46_local.ia46_addr4 -#define ie6_faddr ie_dependfaddr.ie6_foreign -#define ie6_laddr ie_dependladdr.ie6_local -}; - -/* - * XXX The defines for inc_* are hacks and should be changed to direct - * references. - */ -struct in_conninfo { - uint8_t inc_flags; - uint8_t inc_len; - uint16_t inc_pad; /* XXX alignment for in_endpoints */ - /* protocol dependent part */ - struct in_endpoints inc_ie; -}; -#define inc_isipv6 inc_flags /* temp compatibility */ -#define inc_fport inc_ie.ie_fport -#define inc_lport inc_ie.ie_lport -#define inc_faddr inc_ie.ie_faddr -#define inc_laddr inc_ie.ie_laddr -#define inc6_faddr inc_ie.ie6_faddr -#define inc6_laddr inc_ie.ie6_laddr - -struct icmp6_filter; - -struct inpcb { - LIST_ENTRY(inpcb) inp_hash; /* hash list */ - LIST_ENTRY(inpcb) inp_list; /* list for all PCBs of this proto */ - void *inp_ppcb; /* pointer to per-protocol pcb */ - struct inpcbinfo *inp_pcbinfo; /* PCB list info */ - struct socket *inp_socket; /* back pointer to socket */ - - uint32_t inp_flow; - int inp_flags; /* generic IP/datagram flags */ - - u_char inp_vflag; /* IP version flag (v4/v6) */ -#define INP_IPV4 0x1 -#define INP_IPV6 0x2 -#define INP_IPV6PROTO 0x4 /* opened under IPv6 protocol */ -#define INP_TIMEWAIT 0x8 /* .. probably doesn't go here */ -#define INP_ONESBCAST 0x10 /* send all-ones broadcast */ -#define INP_DROPPED 0x20 /* protocol drop flag */ -#define INP_SOCKREF 0x40 /* strong socket reference */ -#define INP_CONN 0x80 - u_char inp_ip_ttl; /* time to live proto */ - u_char inp_ip_p; /* protocol proto */ - u_char inp_ip_minttl; /* minimum TTL or drop */ - uint32_t inp_ispare1; /* connection id / queue id */ - void *inp_pspare[2]; /* rtentry / general use */ - - /* Local and foreign ports, local and foreign addr. */ - struct in_conninfo inp_inc; - - /* list for this PCB's local port */ - struct label *inp_label; /* MAC label */ - struct inpcbpolicy *inp_sp; /* for IPSEC */ - - /* Protocol-dependent part; options. */ - struct { - u_char inp4_ip_tos; /* type of service proto */ - struct mbuf *inp4_options; /* IP options */ - struct ip_moptions *inp4_moptions; /* IP multicast options */ - } inp_depend4; -#define inp_fport inp_inc.inc_fport -#define inp_lport inp_inc.inc_lport -#define inp_faddr inp_inc.inc_faddr -#define inp_laddr inp_inc.inc_laddr -#define inp_ip_tos inp_depend4.inp4_ip_tos -#define inp_options inp_depend4.inp4_options -#define inp_moptions inp_depend4.inp4_moptions - struct { - /* IP options */ - struct mbuf *inp6_options; - /* IP6 options for outgoing packets */ - struct ip6_pktopts *inp6_outputopts; - /* IP multicast options */ -#if 0 - struct ip6_moptions *inp6_moptions; -#endif - /* ICMPv6 code type filter */ - struct icmp6_filter *inp6_icmp6filt; - /* IPV6_CHECKSUM setsockopt */ - int inp6_cksum; - short inp6_hops; - } inp_depend6; - LIST_ENTRY(inpcb) inp_portlist; - struct inpcbport *inp_phd; /* head of this list */ -#define inp_zero_size offsetof(struct inpcb, inp_gencnt) - struct mtx inp_mtx; - -#define in6p_faddr inp_inc.inc6_faddr -#define in6p_laddr inp_inc.inc6_laddr -#define in6p_hops inp_depend6.inp6_hops /* default hop limit */ -#define in6p_ip6_nxt inp_ip_p -#define in6p_flowinfo inp_flow -#define in6p_vflag inp_vflag -#define in6p_options inp_depend6.inp6_options -#define in6p_outputopts inp_depend6.inp6_outputopts -#if 0 -#define in6p_moptions inp_depend6.inp6_moptions -#endif -#define in6p_icmp6filt inp_depend6.inp6_icmp6filt -#define in6p_cksum inp_depend6.inp6_cksum -#define in6p_flags inp_flags /* for KAME src sync over BSD*'s */ -#define in6p_socket inp_socket /* for KAME src sync over BSD*'s */ -#define in6p_lport inp_lport /* for KAME src sync over BSD*'s */ -#define in6p_fport inp_fport /* for KAME src sync over BSD*'s */ -#define in6p_ppcb inp_ppcb /* for KAME src sync over BSD*'s */ -}; -/* - * The range of the generation count, as used in this implementation, is 9e19. - * We would have to create 300 billion connections per second for this number - * to roll over in a year. This seems sufficiently unlikely that we simply - * don't concern ourselves with that possibility. - */ - -struct inpcbport { - LIST_ENTRY(inpcbport) phd_hash; - struct inpcbhead phd_pcblist; - u_short phd_port; -}; - -/* - * Global data structure for each high-level protocol (UDP, TCP, ...) in both - * IPv4 and IPv6. Holds inpcb lists and information for managing them. - */ -struct inpcbinfo { - /* - * Global list of inpcbs on the protocol. - */ - struct inpcbhead *ipi_listhead; - u_int ipi_count; - - /* - * Global hash of inpcbs, hashed by local and foreign addresses and - * port numbers. - */ - struct inpcbhead *ipi_hashbase; - u_long ipi_hashmask; - - /* - * Global hash of inpcbs, hashed by only local port number. - */ - struct inpcbporthead *ipi_porthashbase; - u_long ipi_porthashmask; - - /* - * Fields associated with port lookup and allocation. - */ - u_short ipi_lastport; - u_short ipi_lastlow; - u_short ipi_lasthi; - - /* - * UMA zone from which inpcbs are allocated for this protocol. - */ - struct uma_zone *ipi_zone; - - /* - * Generation count--incremented each time a connection is allocated - * or freed. - */ - struct mtx ipi_mtx; - - /* - * vimage 1 - * general use 1 - */ - void *ipi_pspare[2]; -}; - -#define INP_LOCK_INIT(inp, d, t) \ - mtx_init(&(inp)->inp_mtx, (d), (t), MTX_DEF | MTX_RECURSE | MTX_DUPOK) -#define INP_LOCK_DESTROY(inp) mtx_destroy(&(inp)->inp_mtx) -#define INP_LOCK(inp) mtx_lock(&(inp)->inp_mtx) -#define INP_UNLOCK(inp) mtx_unlock(&(inp)->inp_mtx) -#define INP_LOCK_ASSERT(inp) mtx_assert(&(inp)->inp_mtx, MA_OWNED) -#define INP_UNLOCK_ASSERT(inp) mtx_assert(&(inp)->inp_mtx, MA_NOTOWNED) - -#define INP_INFO_LOCK_INIT(ipi, d) \ - mtx_init(&(ipi)->ipi_mtx, (d), NULL, MTX_DEF | MTX_RECURSE) -#define INP_INFO_LOCK_DESTROY(ipi) mtx_destroy(&(ipi)->ipi_mtx) -#define INP_INFO_RLOCK(ipi) mtx_lock(&(ipi)->ipi_mtx) -#define INP_INFO_WLOCK(ipi) mtx_lock(&(ipi)->ipi_mtx) -#define INP_INFO_RUNLOCK(ipi) mtx_unlock(&(ipi)->ipi_mtx) -#define INP_INFO_WUNLOCK(ipi) mtx_unlock(&(ipi)->ipi_mtx) -#define INP_INFO_RLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_mtx, MA_OWNED) -#define INP_INFO_WLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_mtx, MA_OWNED) -#define INP_INFO_UNLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_mtx, MA_NOTOWNED) - -#define INP_PCBHASH(faddr, lport, fport, mask) \ - (((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask)) -#define INP_PCBPORTHASH(lport, mask) \ - (ntohs((lport)) & (mask)) - -/* flags in inp_flags: */ -#define INP_RECVOPTS 0x01 /* receive incoming IP options */ -#define INP_RECVRETOPTS 0x02 /* receive IP options for reply */ -#define INP_RECVDSTADDR 0x04 /* receive IP dst address */ -#define INP_HDRINCL 0x08 /* user supplies entire IP header */ -#define INP_HIGHPORT 0x10 /* user wants "high" port binding */ -#define INP_LOWPORT 0x20 /* user wants "low" port binding */ -#define INP_ANONPORT 0x40 /* port chosen for user */ -#define INP_RECVIF 0x80 /* receive incoming interface */ -#define INP_MTUDISC 0x100 /* user can do MTU discovery */ -#define INP_FAITH 0x200 /* accept FAITH'ed connections */ -#define INP_RECVTTL 0x400 /* receive incoming IP TTL */ -#define INP_DONTFRAG 0x800 /* don't fragment packet */ - -#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */ - -#define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */ -#define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */ -#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */ -#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */ -#define IN6P_RTHDR 0x100000 /* receive routing header */ -#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */ -#define IN6P_TCLASS 0x400000 /* receive traffic class value */ -#define IN6P_AUTOFLOWLABEL 0x800000 /* attach flowlabel automatically */ -#define IN6P_RFC2292 0x40000000 /* used RFC2292 API on the socket */ -#define IN6P_MTU 0x80000000 /* receive path MTU */ - -#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ - INP_RECVIF|INP_RECVTTL|\ - IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\ - IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\ - IN6P_TCLASS|IN6P_AUTOFLOWLABEL|IN6P_RFC2292|\ - IN6P_MTU) -#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\ - IN6P_TCLASS|IN6P_AUTOFLOWLABEL) - - /* for KAME src sync over BSD*'s */ -#define IN6P_HIGHPORT INP_HIGHPORT -#define IN6P_LOWPORT INP_LOWPORT -#define IN6P_ANONPORT INP_ANONPORT -#define IN6P_RECVIF INP_RECVIF -#define IN6P_MTUDISC INP_MTUDISC -#define IN6P_FAITH INP_FAITH -#define IN6P_CONTROLOPTS INP_CONTROLOPTS - /* - * socket AF version is {newer than,or include} - * actual datagram AF version - */ - -#define INPLOOKUP_WILDCARD 1 -#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) - -#define INP_SOCKAF(so) so->so_proto->pr_domain->dom_family - -#define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af) - -extern int ipport_reservedhigh; -extern int ipport_reservedlow; -extern int ipport_lowfirstauto; -extern int ipport_lowlastauto; -extern int ipport_firstauto; -extern int ipport_lastauto; -extern int ipport_hifirstauto; -extern int ipport_hilastauto; -extern struct callout ipport_tick_callout; - -void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *); -int in_pcballoc(struct socket *, struct inpcbinfo *); -int in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *); -int in_pcbconnect(struct inpcb *, struct sockaddr *, struct ucred *); -void in_pcbdetach(struct inpcb *); -void in_pcbdisconnect(struct inpcb *); -void in_pcbdrop(struct inpcb *); -void in_pcbfree(struct inpcb *); -int in_pcbinshash(struct inpcb *); -struct inpcb * - in_pcblookup_local(struct inpcbinfo *, - struct in_addr, u_int, int); -struct inpcb * - in_pcblookup_hash(struct inpcbinfo *, struct in_addr, u_int, - struct in_addr, u_int, int, struct ifnet *); -void in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr, - int, struct inpcb *(*)(struct inpcb *, int)); -void in_pcbrehash(struct inpcb *); -void in_pcbsetsolabel(struct socket *so); -int in_getpeeraddr(struct socket *so, struct sockaddr **nam); -int in_getsockaddr(struct socket *so, struct sockaddr **nam); -void in_pcbsosetlabel(struct socket *so); -void in_pcbremlists(struct inpcb *inp); -void ipport_tick(void *xtp); - -/* - * Debugging routines compiled in when DDB is present. - */ -void db_print_inpcb(struct inpcb *inp, const char *name, int indent); - - -#endif /* !_NETINET_IN_PCB_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip6_var.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip6_var.h deleted file mode 100644 index b970fb8f..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip6_var.h +++ /dev/null @@ -1,124 +0,0 @@ -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ -/*- - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _USER_IP6_VAR_H_ -#define _USER_IP6_VAR_H_ - -#if defined(_WIN32) -struct ip6_hdr { - union { - struct ip6_hdrctl { - uint32_t ip6_un1_flow; /* 20 bits of flow-ID */ - uint16_t ip6_un1_plen; /* payload length */ - uint8_t ip6_un1_nxt; /* next header */ - uint8_t ip6_un1_hlim; /* hop limit */ - } ip6_un1; - uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ - } ip6_ctlun; - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ -}; -#define ip6_vfc ip6_ctlun.ip6_un2_vfc -#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow -#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen -#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt -#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim -#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim - -#define IPV6_VERSION 0x60 -#endif - -#if defined(_WIN32) -#define s6_addr16 u.Word -#endif -#if !defined(_WIN32) && !defined(__linux__) && !defined(__EMSCRIPTEN__) -#define s6_addr8 __u6_addr.__u6_addr8 -#define s6_addr16 __u6_addr.__u6_addr16 -#define s6_addr32 __u6_addr.__u6_addr32 -#endif - -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) -struct route_in6 { - struct rtentry *ro_rt; - struct llentry *ro_lle; - struct in6_addr *ro_ia6; - int ro_flags; - struct sockaddr_in6 ro_dst; -}; -#endif -#define IP6_EXTHDR_GET(val, typ, m, off, len) \ -do { \ - struct mbuf *t; \ - int tmp; \ - if ((m)->m_len >= (off) + (len)) \ - (val) = (typ)(mtod((m), caddr_t) + (off)); \ - else { \ - t = m_pulldown((m), (off), (len), &tmp); \ - if (t) { \ - KASSERT(t->m_len >= tmp + (len), \ - ("m_pulldown malfunction")); \ - (val) = (typ)(mtod(t, caddr_t) + tmp); \ - } else { \ - (val) = (typ)NULL; \ - (m) = NULL; \ - } \ - } \ -} while (0) - -#endif /* !_USER_IP6_VAR_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip_icmp.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip_icmp.h deleted file mode 100644 index a993411a..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_ip_icmp.h +++ /dev/null @@ -1,225 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _USER_IP_ICMP_H_ -#define _USER_IP_ICMP_H_ - -/* - * Interface Control Message Protocol Definitions. - * Per RFC 792, September 1981. - */ - -/* - * Internal of an ICMP Router Advertisement - */ -struct icmp_ra_addr { - uint32_t ira_addr; - uint32_t ira_preference; -}; - -/* - * Structure of an icmp header. - */ -struct icmphdr { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ -}; - -#if defined(_WIN32) -#pragma pack (push, 1) -struct icmp6_hdr { - uint8_t icmp6_type; - uint8_t icmp6_code; - uint16_t icmp6_cksum; - union { - uint32_t icmp6_un_data32[1]; - uint16_t icmp6_un_data16[2]; - uint8_t icmp6_un_data8[4]; - } icmp6_dataun; -}; -#pragma pack(pop) - -#define icmp6_data32 icmp6_dataun.icmp6_un_data32 -#define icmp6_mtu icmp6_data32[0] -#endif - -/* - * Structure of an icmp packet. - * - * XXX: should start with a struct icmphdr. - */ -struct icmp { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ - union { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - uint16_t icd_id; /* network format */ - uint16_t icd_seq; /* network format */ - } ih_idseq; - int ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu { - uint16_t ipm_void; /* network format */ - uint16_t ipm_nextmtu; /* network format */ - } ih_pmtu; - - struct ih_rtradv { - u_char irt_num_addrs; - u_char irt_wpa; - uint16_t irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu -#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs -#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa -#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime - union { - struct id_ts { /* ICMP Timestamp */ - /* - * The next 3 fields are in network format, - * milliseconds since 00:00 GMT - */ - uint32_t its_otime; /* Originate */ - uint32_t its_rtime; /* Receive */ - uint32_t its_ttime; /* Transmit */ - } id_ts; - struct id_ip { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - struct icmp_ra_addr id_radv; - uint32_t id_mask; - char id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_radv icmp_dun.id_radv -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; - -/* - * Lower bounds on packet lengths for various types. - * For the error advice packets must first insure that the - * packet is large enough to contain the returned ip header. - * Only then can we do the check to see if 64 bits of packet - * data have been returned, since we need to check the returned - * ip header length. - */ -#define ICMP_MINLEN 8 /* abs minimum */ -#define ICMP_TSLEN (8 + 3 * sizeof (uint32_t)) /* timestamp */ -#define ICMP_MASKLEN 12 /* address mask */ -#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ -#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) - /* N.B.: must separately check that ip_hl >= 5 */ - -/* - * Definition of type and code field values. - */ -#define ICMP_ECHOREPLY 0 /* echo reply */ -#define ICMP_UNREACH 3 /* dest unreachable, codes: */ -#define ICMP_UNREACH_NET 0 /* bad net */ -#define ICMP_UNREACH_HOST 1 /* bad host */ -#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ -#define ICMP_UNREACH_PORT 3 /* bad port */ -#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ -#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ -#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ -#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ -#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ -#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ -#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ -#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ -#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ -#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */ -#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */ -#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */ -#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ -#define ICMP_REDIRECT 5 /* shorter route, codes: */ -#define ICMP_REDIRECT_NET 0 /* for network */ -#define ICMP_REDIRECT_HOST 1 /* for host */ -#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ -#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ -#define ICMP_ALTHOSTADDR 6 /* alternate host address */ -#define ICMP_ECHO 8 /* echo service */ -#define ICMP_ROUTERADVERT 9 /* router advertisement */ -#define ICMP_ROUTERADVERT_NORMAL 0 /* normal advertisement */ -#define ICMP_ROUTERADVERT_NOROUTE_COMMON 16 /* selective routing */ -#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ -#define ICMP_TIMXCEED 11 /* time exceeded, code: */ -#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ -#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ -#define ICMP_PARAMPROB 12 /* ip header bad */ -#define ICMP_PARAMPROB_ERRATPTR 0 /* error at param ptr */ -#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ -#define ICMP_PARAMPROB_LENGTH 2 /* bad length */ -#define ICMP_TSTAMP 13 /* timestamp request */ -#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ -#define ICMP_IREQ 15 /* information request */ -#define ICMP_IREQREPLY 16 /* information reply */ -#define ICMP_MASKREQ 17 /* address mask request */ -#define ICMP_MASKREPLY 18 /* address mask reply */ -#define ICMP_TRACEROUTE 30 /* traceroute */ -#define ICMP_DATACONVERR 31 /* data conversion error */ -#define ICMP_MOBILE_REDIRECT 32 /* mobile host redirect */ -#define ICMP_IPV6_WHEREAREYOU 33 /* IPv6 where-are-you */ -#define ICMP_IPV6_IAMHERE 34 /* IPv6 i-am-here */ -#define ICMP_MOBILE_REGREQUEST 35 /* mobile registration req */ -#define ICMP_MOBILE_REGREPLY 36 /* mobile registration reply */ -#define ICMP_SKIP 39 /* SKIP */ -#define ICMP_PHOTURIS 40 /* Photuris */ -#define ICMP_PHOTURIS_UNKNOWN_INDEX 1 /* unknown sec index */ -#define ICMP_PHOTURIS_AUTH_FAILED 2 /* auth failed */ -#define ICMP_PHOTURIS_DECRYPT_FAILED 3 /* decrypt failed */ - -#define ICMP_MAXTYPE 40 - -#define ICMP_INFOTYPE(type) \ - ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ - (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ - (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ - (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ - (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) - - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_malloc.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_malloc.h deleted file mode 100644 index c588e094..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_malloc.h +++ /dev/null @@ -1,203 +0,0 @@ -/*- - * Copyright (c) 1987, 1993 - * The Regents of the University of California. - * Copyright (c) 2005 Robert N. M. Watson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* This file has been renamed user_malloc.h for Userspace */ -#ifndef _USER_MALLOC_H_ -#define _USER_MALLOC_H_ - -/*__Userspace__*/ -#include -#include -#if !defined(_WIN32) -#include -#include -#else -#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ >= 1400) -#include -#elif defined(SCTP_STDINT_INCLUDE) -#include SCTP_STDINT_INCLUDE -#else -#define uint32_t unsigned __int32 -#define uint64_t unsigned __int64 -#endif -#include -#endif - -#define MINALLOCSIZE UMA_SMALLEST_UNIT - -/* - * flags to malloc. - */ -#define M_NOWAIT 0x0001 /* do not block */ -#define M_WAITOK 0x0002 /* ok to block */ -#define M_ZERO 0x0100 /* bzero the allocation */ -#define M_NOVM 0x0200 /* don't ask VM for pages */ -#define M_USE_RESERVE 0x0400 /* can alloc out of reserve memory */ - -#define M_MAGIC 877983977 /* time when first defined :-) */ - -/* - * Two malloc type structures are present: malloc_type, which is used by a - * type owner to declare the type, and malloc_type_internal, which holds - * malloc-owned statistics and other ABI-sensitive fields, such as the set of - * malloc statistics indexed by the compile-time MAXCPU constant. - * Applications should avoid introducing dependence on the allocator private - * data layout and size. - * - * The malloc_type ks_next field is protected by malloc_mtx. Other fields in - * malloc_type are static after initialization so unsynchronized. - * - * Statistics in malloc_type_stats are written only when holding a critical - * section and running on the CPU associated with the index into the stat - * array, but read lock-free resulting in possible (minor) races, which the - * monitoring app should take into account. - */ -struct malloc_type_stats { - uint64_t mts_memalloced; /* Bytes allocated on CPU. */ - uint64_t mts_memfreed; /* Bytes freed on CPU. */ - uint64_t mts_numallocs; /* Number of allocates on CPU. */ - uint64_t mts_numfrees; /* number of frees on CPU. */ - uint64_t mts_size; /* Bitmask of sizes allocated on CPU. */ - uint64_t _mts_reserved1; /* Reserved field. */ - uint64_t _mts_reserved2; /* Reserved field. */ - uint64_t _mts_reserved3; /* Reserved field. */ -}; - -#ifndef MAXCPU /* necessary on Linux */ -#define MAXCPU 4 /* arbitrary? */ -#endif - -struct malloc_type_internal { - struct malloc_type_stats mti_stats[MAXCPU]; -}; - -/* - * ABI-compatible version of the old 'struct malloc_type', only all stats are - * now malloc-managed in malloc-owned memory rather than in caller memory, so - * as to avoid ABI issues. The ks_next pointer is reused as a pointer to the - * internal data handle. - */ -struct malloc_type { - struct malloc_type *ks_next; /* Next in global chain. */ - u_long _ks_memuse; /* No longer used. */ - u_long _ks_size; /* No longer used. */ - u_long _ks_inuse; /* No longer used. */ - uint64_t _ks_calls; /* No longer used. */ - u_long _ks_maxused; /* No longer used. */ - u_long ks_magic; /* Detect programmer error. */ - const char *ks_shortdesc; /* Printable type name. */ - - /* - * struct malloc_type was terminated with a struct mtx, which is no - * longer required. For ABI reasons, continue to flesh out the full - * size of the old structure, but reuse the _lo_class field for our - * internal data handle. - */ - void *ks_handle; /* Priv. data, was lo_class. */ - const char *_lo_name; - const char *_lo_type; - u_int _lo_flags; - void *_lo_list_next; - struct witness *_lo_witness; - uintptr_t _mtx_lock; - u_int _mtx_recurse; -}; - -/* - * Statistics structure headers for user space. The kern.malloc sysctl - * exposes a structure stream consisting of a stream header, then a series of - * malloc type headers and statistics structures (quantity maxcpus). For - * convenience, the kernel will provide the current value of maxcpus at the - * head of the stream. - */ -#define MALLOC_TYPE_STREAM_VERSION 0x00000001 -struct malloc_type_stream_header { - uint32_t mtsh_version; /* Stream format version. */ - uint32_t mtsh_maxcpus; /* Value of MAXCPU for stream. */ - uint32_t mtsh_count; /* Number of records. */ - uint32_t _mtsh_pad; /* Pad/reserved field. */ -}; - -#define MALLOC_MAX_NAME 32 -struct malloc_type_header { - char mth_name[MALLOC_MAX_NAME]; -}; - -/* __Userspace__ -Notice that at places it uses ifdef _KERNEL. That line cannot be -removed because it causes conflicts with malloc definition in -/usr/include/malloc.h, which essentially says that malloc.h has -been overridden by stdlib.h. We will need to use names like -user_malloc.h for isolating kernel interface headers. using -original names like malloc.h in a user_include header can be -confusing, All userspace header files are being placed in ./user_include -Better still to remove from user_include.h all irrelevant code such -as that in the block starting with #ifdef _KERNEL. I am only leaving -it in for the time being to see what functionality is in this file -that kernel uses. - -Start copy: Copied code for __Userspace__ */ -#define MALLOC_DEFINE(type, shortdesc, longdesc) \ - struct malloc_type type[1] = { \ - { NULL, 0, 0, 0, 0, 0, M_MAGIC, shortdesc, NULL, NULL, \ - NULL, 0, NULL, NULL, 0, 0 } \ - } - -/* Removed "extern" in __Userspace__ code */ -/* If we need to use MALLOC_DECLARE before using MALLOC then - we have to remove extern. - In /usr/include/sys/malloc.h there is this definition: - #define MALLOC_DECLARE(type) \ - extern struct malloc_type type[1] - and loader is unable to find the extern malloc_type because - it may be defined in one of kernel object files. - It seems that MALLOC_DECLARE and MALLOC_DEFINE cannot be used at - the same time for same "type" variable. Also, in Randall's architecture - document, where it specifies O/S specific macros and functions, it says - that the name in SCTP_MALLOC does not have to be used. -*/ -#define MALLOC_DECLARE(type) \ - extern struct malloc_type type[1] - -#define FREE(addr, type) free((addr)) - -/* changed definitions of MALLOC and FREE */ -/* Using memset if flag M_ZERO is specified. Todo: M_WAITOK and M_NOWAIT */ -#define MALLOC(space, cast, size, type, flags) \ - ((space) = (cast)malloc((u_long)(size))); \ - do { \ - if (flags & M_ZERO) { \ - memset(space,0,size); \ - } \ - } while (0); - -#endif /* !_SYS_MALLOC_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.c deleted file mode 100644 index 85badc0f..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.c +++ /dev/null @@ -1,1589 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* - * __Userspace__ version of /usr/src/sys/kern/kern_mbuf.c - * We are initializing two zones for Mbufs and Clusters. - * - */ - -#include -#include -/* #include This defines MSIZE 256 */ -#if !defined(SCTP_SIMPLE_ALLOCATOR) -#include "umem.h" -#endif -#include "user_mbuf.h" -#include "user_environment.h" -#include "user_atomic.h" -#include "netinet/sctp_pcb.h" - -#define KIPC_MAX_LINKHDR 4 /* int: max length of link header (see sys/sysclt.h) */ -#define KIPC_MAX_PROTOHDR 5 /* int: max length of network header (see sys/sysclt.h)*/ -int max_linkhdr = KIPC_MAX_LINKHDR; -int max_protohdr = KIPC_MAX_PROTOHDR; /* Size of largest protocol layer header. */ - -/* - * Zones from which we allocate. - */ -sctp_zone_t zone_mbuf; -sctp_zone_t zone_clust; -sctp_zone_t zone_ext_refcnt; - -/* __Userspace__ clust_mb_args will be passed as callback data to mb_ctor_clust - * and mb_dtor_clust. - * Note: I had to use struct clust_args as an encapsulation for an mbuf pointer. - * struct mbuf * clust_mb_args; does not work. - */ -struct clust_args clust_mb_args; - - -/* __Userspace__ - * Local prototypes. - */ -static int mb_ctor_mbuf(void *, void *, int); -static int mb_ctor_clust(void *, void *, int); -static void mb_dtor_mbuf(void *, void *); -static void mb_dtor_clust(void *, void *); - - -/***************** Functions taken from user_mbuf.h *************/ - -static int mbuf_constructor_dup(struct mbuf *m, int pkthdr, short type) -{ - int flags = pkthdr; - - m->m_next = NULL; - m->m_nextpkt = NULL; - m->m_len = 0; - m->m_flags = flags; - m->m_type = type; - if (flags & M_PKTHDR) { - m->m_data = m->m_pktdat; - m->m_pkthdr.rcvif = NULL; - m->m_pkthdr.len = 0; - m->m_pkthdr.header = NULL; - m->m_pkthdr.csum_flags = 0; - m->m_pkthdr.csum_data = 0; - m->m_pkthdr.tso_segsz = 0; - m->m_pkthdr.ether_vtag = 0; - SLIST_INIT(&m->m_pkthdr.tags); - } else - m->m_data = m->m_dat; - - return (0); -} - -/* __Userspace__ */ -struct mbuf * -m_get(int how, short type) -{ - struct mbuf *mret; -#if defined(SCTP_SIMPLE_ALLOCATOR) - struct mb_args mbuf_mb_args; - - /* The following setter function is not yet being enclosed within - * #if USING_MBUF_CONSTRUCTOR - #endif, until I have thoroughly tested - * mb_dtor_mbuf. See comment there - */ - mbuf_mb_args.flags = 0; - mbuf_mb_args.type = type; -#endif - /* Mbuf master zone, zone_mbuf, has already been - * created in mbuf_initialize() */ - mret = SCTP_ZONE_GET(zone_mbuf, struct mbuf); -#if defined(SCTP_SIMPLE_ALLOCATOR) - mb_ctor_mbuf(mret, &mbuf_mb_args, 0); -#endif - /*mret = ((struct mbuf *)umem_cache_alloc(zone_mbuf, UMEM_DEFAULT));*/ - - /* There are cases when an object available in the current CPU's - * loaded magazine and in those cases the object's constructor is not applied. - * If that is the case, then we are duplicating constructor initialization here, - * so that the mbuf is properly constructed before returning it. - */ - if (mret) { -#if USING_MBUF_CONSTRUCTOR - if (! (mret->m_type == type) ) { - mbuf_constructor_dup(mret, 0, type); - } -#else - mbuf_constructor_dup(mret, 0, type); -#endif - - } - return mret; -} - - -/* __Userspace__ */ -struct mbuf * -m_gethdr(int how, short type) -{ - struct mbuf *mret; -#if defined(SCTP_SIMPLE_ALLOCATOR) - struct mb_args mbuf_mb_args; - - /* The following setter function is not yet being enclosed within - * #if USING_MBUF_CONSTRUCTOR - #endif, until I have thoroughly tested - * mb_dtor_mbuf. See comment there - */ - mbuf_mb_args.flags = M_PKTHDR; - mbuf_mb_args.type = type; -#endif - mret = SCTP_ZONE_GET(zone_mbuf, struct mbuf); -#if defined(SCTP_SIMPLE_ALLOCATOR) - mb_ctor_mbuf(mret, &mbuf_mb_args, 0); -#endif - /*mret = ((struct mbuf *)umem_cache_alloc(zone_mbuf, UMEM_DEFAULT));*/ - /* There are cases when an object available in the current CPU's - * loaded magazine and in those cases the object's constructor is not applied. - * If that is the case, then we are duplicating constructor initialization here, - * so that the mbuf is properly constructed before returning it. - */ - if (mret) { -#if USING_MBUF_CONSTRUCTOR - if (! ((mret->m_flags & M_PKTHDR) && (mret->m_type == type)) ) { - mbuf_constructor_dup(mret, M_PKTHDR, type); - } -#else - mbuf_constructor_dup(mret, M_PKTHDR, type); -#endif - } - return mret; -} - -/* __Userspace__ */ -struct mbuf * -m_free(struct mbuf *m) -{ - - struct mbuf *n = m->m_next; - - if (m->m_flags & M_EXT) - mb_free_ext(m); - else if ((m->m_flags & M_NOFREE) == 0) { -#if defined(SCTP_SIMPLE_ALLOCATOR) - mb_dtor_mbuf(m, NULL); -#endif - SCTP_ZONE_FREE(zone_mbuf, m); - } - /*umem_cache_free(zone_mbuf, m);*/ - return (n); -} - - -static void -clust_constructor_dup(caddr_t m_clust, struct mbuf* m) -{ - u_int *refcnt; - int type, size; - - if (m == NULL) { - return; - } - /* Assigning cluster of MCLBYTES. TODO: Add jumbo frame functionality */ - type = EXT_CLUSTER; - size = MCLBYTES; - - refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int); - /*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/ -#if !defined(SCTP_SIMPLE_ALLOCATOR) - if (refcnt == NULL) { - umem_reap(); - refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int); - /*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/ - } -#endif - *refcnt = 1; - m->m_ext.ext_buf = (caddr_t)m_clust; - m->m_data = m->m_ext.ext_buf; - m->m_flags |= M_EXT; - m->m_ext.ext_free = NULL; - m->m_ext.ext_args = NULL; - m->m_ext.ext_size = size; - m->m_ext.ext_type = type; - m->m_ext.ref_cnt = refcnt; - return; -} - - -/* __Userspace__ */ -void -m_clget(struct mbuf *m, int how) -{ - caddr_t mclust_ret; -#if defined(SCTP_SIMPLE_ALLOCATOR) - struct clust_args clust_mb_args_l; -#endif - if (m->m_flags & M_EXT) { - SCTPDBG(SCTP_DEBUG_USR, "%s: %p mbuf already has cluster\n", __func__, (void *)m); - } - m->m_ext.ext_buf = (char *)NULL; -#if defined(SCTP_SIMPLE_ALLOCATOR) - clust_mb_args_l.parent_mbuf = m; -#endif - mclust_ret = SCTP_ZONE_GET(zone_clust, char); -#if defined(SCTP_SIMPLE_ALLOCATOR) - mb_ctor_clust(mclust_ret, &clust_mb_args_l, 0); -#endif - /*mclust_ret = umem_cache_alloc(zone_clust, UMEM_DEFAULT);*/ - /* - On a cluster allocation failure, call umem_reap() and retry. - */ - - if (mclust_ret == NULL) { -#if !defined(SCTP_SIMPLE_ALLOCATOR) - /* mclust_ret = SCTP_ZONE_GET(zone_clust, char); - mb_ctor_clust(mclust_ret, &clust_mb_args, 0); -#else*/ - umem_reap(); - mclust_ret = SCTP_ZONE_GET(zone_clust, char); -#endif - /*mclust_ret = umem_cache_alloc(zone_clust, UMEM_DEFAULT);*/ - /* if (NULL == mclust_ret) { */ - SCTPDBG(SCTP_DEBUG_USR, "Memory allocation failure in %s\n", __func__); - /* } */ - } - -#if USING_MBUF_CONSTRUCTOR - if ((m->m_ext.ext_buf == NULL)) { - clust_constructor_dup(mclust_ret, m); - } -#else - clust_constructor_dup(mclust_ret, m); -#endif -} - -struct mbuf * -m_getm2(struct mbuf *m, int len, int how, short type, int flags, int allonebuf) -{ - struct mbuf *mb, *nm = NULL, *mtail = NULL; - int size, mbuf_threshold, space_needed = len; - - KASSERT(len >= 0, ("%s: len is < 0", __func__)); - - /* Validate flags. */ - flags &= (M_PKTHDR | M_EOR); - - /* Packet header mbuf must be first in chain. */ - if ((flags & M_PKTHDR) && m != NULL) { - flags &= ~M_PKTHDR; - } - - if (allonebuf == 0) - mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count); - else - mbuf_threshold = 1; - - /* Loop and append maximum sized mbufs to the chain tail. */ - while (len > 0) { - if ((!allonebuf && len >= MCLBYTES) || (len > (int)(((mbuf_threshold - 1) * MLEN) + MHLEN))) { - mb = m_gethdr(how, type); - MCLGET(mb, how); - size = MCLBYTES; - /* SCTP_BUF_LEN(mb) = MCLBYTES; */ - } else if (flags & M_PKTHDR) { - mb = m_gethdr(how, type); - if (len < MHLEN) { - size = len; - } else { - size = MHLEN; - } - } else { - mb = m_get(how, type); - if (len < MLEN) { - size = len; - } else { - size = MLEN; - } - } - - /* Fail the whole operation if one mbuf can't be allocated. */ - if (mb == NULL) { - if (nm != NULL) - m_freem(nm); - return (NULL); - } - - if (allonebuf != 0 && size < space_needed) { - m_freem(mb); - return (NULL); - } - - /* Book keeping. */ - len -= size; - if (mtail != NULL) - mtail->m_next = mb; - else - nm = mb; - mtail = mb; - flags &= ~M_PKTHDR; /* Only valid on the first mbuf. */ - } - if (flags & M_EOR) { - mtail->m_flags |= M_EOR; /* Only valid on the last mbuf. */ - } - - /* If mbuf was supplied, append new chain to the end of it. */ - if (m != NULL) { - for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next); - mtail->m_next = nm; - mtail->m_flags &= ~M_EOR; - } else { - m = nm; - } - - return (m); -} - -/* - * Copy the contents of uio into a properly sized mbuf chain. - */ -struct mbuf * -m_uiotombuf(struct uio *uio, int how, int len, int align, int flags) -{ - struct mbuf *m, *mb; - int error, length; - ssize_t total; - int progress = 0; - - /* - * len can be zero or an arbitrary large value bound by - * the total data supplied by the uio. - */ - if (len > 0) - total = min(uio->uio_resid, len); - else - total = uio->uio_resid; - /* - * The smallest unit returned by m_getm2() is a single mbuf - * with pkthdr. We can't align past it. - */ - if (align >= MHLEN) - return (NULL); - /* - * Give us the full allocation or nothing. - * If len is zero return the smallest empty mbuf. - */ - m = m_getm2(NULL, (int)max(total + align, 1), how, MT_DATA, flags, 0); - if (m == NULL) - return (NULL); - m->m_data += align; - - /* Fill all mbufs with uio data and update header information. */ - for (mb = m; mb != NULL; mb = mb->m_next) { - length = (int)min(M_TRAILINGSPACE(mb), total - progress); - error = uiomove(mtod(mb, void *), length, uio); - if (error) { - m_freem(m); - return (NULL); - } - - mb->m_len = length; - progress += length; - if (flags & M_PKTHDR) - m->m_pkthdr.len += length; - } - KASSERT(progress == total, ("%s: progress != total", __func__)); - - return (m); -} - -u_int -m_length(struct mbuf *m0, struct mbuf **last) -{ - struct mbuf *m; - u_int len; - - len = 0; - for (m = m0; m != NULL; m = m->m_next) { - len += m->m_len; - if (m->m_next == NULL) - break; - } - if (last != NULL) - *last = m; - return (len); -} - -struct mbuf * -m_last(struct mbuf *m) -{ - while (m->m_next) { - m = m->m_next; - } - return (m); -} - -/* - * Unlink a tag from the list of tags associated with an mbuf. - */ -static __inline void -m_tag_unlink(struct mbuf *m, struct m_tag *t) -{ - - SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link); -} - -/* - * Reclaim resources associated with a tag. - */ -static __inline void -m_tag_free(struct m_tag *t) -{ - - (*t->m_tag_free)(t); -} - -/* - * Set up the contents of a tag. Note that this does not fill in the free - * method; the caller is expected to do that. - * - * XXX probably should be called m_tag_init, but that was already taken. - */ -static __inline void -m_tag_setup(struct m_tag *t, uint32_t cookie, int type, int len) -{ - - t->m_tag_id = type; - t->m_tag_len = len; - t->m_tag_cookie = cookie; -} - -/************ End functions from user_mbuf.h ******************/ - - - -/************ End functions to substitute umem_cache_alloc and umem_cache_free **************/ - -void -mbuf_initialize(void *dummy) -{ - - /* - * __Userspace__Configure UMA zones for Mbufs and Clusters. - * (TODO: m_getcl() - using packet secondary zone). - * There is no provision for trash_init and trash_fini in umem. - * - */ - /* zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0, - mb_ctor_mbuf, mb_dtor_mbuf, NULL, - &mbuf_mb_args, - NULL, 0); - zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0, NULL, NULL, NULL, NULL, NULL, 0);*/ -#if defined(SCTP_SIMPLE_ALLOCATOR) - SCTP_ZONE_INIT(zone_mbuf, MBUF_MEM_NAME, MSIZE, 0); -#else - zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0, - mb_ctor_mbuf, mb_dtor_mbuf, NULL, - NULL, - NULL, 0); -#endif - /*zone_ext_refcnt = umem_cache_create(MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int), 0, - NULL, NULL, NULL, - NULL, - NULL, 0);*/ - SCTP_ZONE_INIT(zone_ext_refcnt, MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int), 0); - - /*zone_clust = umem_cache_create(MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0, - mb_ctor_clust, mb_dtor_clust, NULL, - &clust_mb_args, - NULL, 0); - zone_clust = umem_cache_create(MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0, NULL, NULL, NULL, NULL, NULL,0);*/ -#if defined(SCTP_SIMPLE_ALLOCATOR) - SCTP_ZONE_INIT(zone_clust, MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0); -#else - zone_clust = umem_cache_create(MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0, - mb_ctor_clust, mb_dtor_clust, NULL, - &clust_mb_args, - NULL, 0); -#endif - - /* uma_prealloc() goes here... */ - - /* __Userspace__ Add umem_reap here for low memory situation? - * - */ - -} - - - -/* - * __Userspace__ - * - * Constructor for Mbuf master zone. We have a different constructor - * for allocating the cluster. - * - * The 'arg' pointer points to a mb_args structure which - * contains call-specific information required to support the - * mbuf allocation API. See user_mbuf.h. - * - * The flgs parameter below can be UMEM_DEFAULT or UMEM_NOFAIL depending on what - * was passed when umem_cache_alloc was called. - * TODO: Use UMEM_NOFAIL in umem_cache_alloc and also define a failure handler - * and call umem_nofail_callback(my_failure_handler) in the stack initialization routines - * The advantage of using UMEM_NOFAIL is that we don't have to check if umem_cache_alloc - * was successful or not. The failure handler would take care of it, if we use the UMEM_NOFAIL - * flag. - * - * NOTE Ref: http://docs.sun.com/app/docs/doc/819-2243/6n4i099p2?l=en&a=view&q=umem_zalloc) - * The umem_nofail_callback() function sets the **process-wide** UMEM_NOFAIL callback. - * It also mentions that umem_nofail_callback is Evolving. - * - */ -static int -mb_ctor_mbuf(void *mem, void *arg, int flgs) -{ -#if USING_MBUF_CONSTRUCTOR - struct mbuf *m; - struct mb_args *args; - - int flags; - short type; - - m = (struct mbuf *)mem; - args = (struct mb_args *)arg; - flags = args->flags; - type = args->type; - - m->m_next = NULL; - m->m_nextpkt = NULL; - m->m_len = 0; - m->m_flags = flags; - m->m_type = type; - if (flags & M_PKTHDR) { - m->m_data = m->m_pktdat; - m->m_pkthdr.rcvif = NULL; - m->m_pkthdr.len = 0; - m->m_pkthdr.header = NULL; - m->m_pkthdr.csum_flags = 0; - m->m_pkthdr.csum_data = 0; - m->m_pkthdr.tso_segsz = 0; - m->m_pkthdr.ether_vtag = 0; - SLIST_INIT(&m->m_pkthdr.tags); - } else - m->m_data = m->m_dat; -#endif - return (0); -} - - -/* - * __Userspace__ - * The Mbuf master zone destructor. - * This would be called in response to umem_cache_destroy - * TODO: Recheck if this is what we want to do in this destructor. - * (Note: the number of times mb_dtor_mbuf is called is equal to the - * number of individual mbufs allocated from zone_mbuf. - */ -static void -mb_dtor_mbuf(void *mem, void *arg) -{ - struct mbuf *m; - - m = (struct mbuf *)mem; - if ((m->m_flags & M_PKTHDR) != 0) { - m_tag_delete_chain(m, NULL); - } -} - - -/* __Userspace__ - * The Cluster zone constructor. - * - * Here the 'arg' pointer points to the Mbuf which we - * are configuring cluster storage for. If 'arg' is - * empty we allocate just the cluster without setting - * the mbuf to it. See mbuf.h. - */ -static int -mb_ctor_clust(void *mem, void *arg, int flgs) -{ - -#if USING_MBUF_CONSTRUCTOR - struct mbuf *m; - struct clust_args * cla; - u_int *refcnt; - int type, size; - sctp_zone_t zone; - - /* Assigning cluster of MCLBYTES. TODO: Add jumbo frame functionality */ - type = EXT_CLUSTER; - zone = zone_clust; - size = MCLBYTES; - - cla = (struct clust_args *)arg; - m = cla->parent_mbuf; - - refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int); - /*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/ - *refcnt = 1; - - if (m != NULL) { - m->m_ext.ext_buf = (caddr_t)mem; - m->m_data = m->m_ext.ext_buf; - m->m_flags |= M_EXT; - m->m_ext.ext_free = NULL; - m->m_ext.ext_args = NULL; - m->m_ext.ext_size = size; - m->m_ext.ext_type = type; - m->m_ext.ref_cnt = refcnt; - } -#endif - return (0); -} - -/* __Userspace__ */ -static void -mb_dtor_clust(void *mem, void *arg) -{ - - /* mem is of type caddr_t. In sys/types.h we have typedef char * caddr_t; */ - /* mb_dtor_clust is called at time of umem_cache_destroy() (the number of times - * mb_dtor_clust is called is equal to the number of individual mbufs allocated - * from zone_clust. Similarly for mb_dtor_mbuf). - * At this point the following: - * struct mbuf *m; - * m = (struct mbuf *)arg; - * assert (*(m->m_ext.ref_cnt) == 0); is not meaningful since m->m_ext.ref_cnt = NULL; - * has been done in mb_free_ext(). - */ - -} - - - - -/* Unlink and free a packet tag. */ -void -m_tag_delete(struct mbuf *m, struct m_tag *t) -{ - KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", (void *)m, (void *)t)); - m_tag_unlink(m, t); - m_tag_free(t); -} - - -/* Unlink and free a packet tag chain, starting from given tag. */ -void -m_tag_delete_chain(struct mbuf *m, struct m_tag *t) -{ - - struct m_tag *p, *q; - - KASSERT(m, ("m_tag_delete_chain: null mbuf")); - if (t != NULL) - p = t; - else - p = SLIST_FIRST(&m->m_pkthdr.tags); - if (p == NULL) - return; - while ((q = SLIST_NEXT(p, m_tag_link)) != NULL) - m_tag_delete(m, q); - m_tag_delete(m, p); -} - -#if 0 -static void -sctp_print_mbuf_chain(struct mbuf *m) -{ - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "Printing mbuf chain %p.\n", (void *)m); - for(; m; m=m->m_next) { - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "%p: m_len = %ld, m_type = %x, m_next = %p.\n", (void *)m, m->m_len, m->m_type, (void *)m->m_next); - if (m->m_flags & M_EXT) - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "%p: extend_size = %d, extend_buffer = %p, ref_cnt = %d.\n", (void *)m, m->m_ext.ext_size, (void *)m->m_ext.ext_buf, *(m->m_ext.ref_cnt)); - } -} -#endif - -/* - * Free an entire chain of mbufs and associated external buffers, if - * applicable. - */ -void -m_freem(struct mbuf *mb) -{ - while (mb != NULL) - mb = m_free(mb); -} - -/* - * __Userspace__ - * clean mbufs with M_EXT storage attached to them - * if the reference count hits 1. - */ -void -mb_free_ext(struct mbuf *m) -{ - - int skipmbuf; - - KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__)); - KASSERT(m->m_ext.ref_cnt != NULL, ("%s: ref_cnt not set", __func__)); - - /* - * check if the header is embedded in the cluster - */ - skipmbuf = (m->m_flags & M_NOFREE); - - /* Free the external attached storage if this - * mbuf is the only reference to it. - *__Userspace__ TODO: jumbo frames - * - */ - /* NOTE: We had the same code that SCTP_DECREMENT_AND_CHECK_REFCOUNT - reduces to here before but the IPHONE malloc commit had changed - this to compare to 0 instead of 1 (see next line). Why? - . .. this caused a huge memory leak in Linux. - */ -#ifdef IPHONE - if (atomic_fetchadd_int(m->m_ext.ref_cnt, -1) == 0) -#else - if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(m->m_ext.ref_cnt)) -#endif - { - if (m->m_ext.ext_type == EXT_CLUSTER){ -#if defined(SCTP_SIMPLE_ALLOCATOR) - mb_dtor_clust(m->m_ext.ext_buf, &clust_mb_args); -#endif - SCTP_ZONE_FREE(zone_clust, m->m_ext.ext_buf); - SCTP_ZONE_FREE(zone_ext_refcnt, (u_int*)m->m_ext.ref_cnt); - m->m_ext.ref_cnt = NULL; - } - } - - if (skipmbuf) - return; - - - /* __Userspace__ Also freeing the storage for ref_cnt - * Free this mbuf back to the mbuf zone with all m_ext - * information purged. - */ - m->m_ext.ext_buf = NULL; - m->m_ext.ext_free = NULL; - m->m_ext.ext_args = NULL; - m->m_ext.ref_cnt = NULL; - m->m_ext.ext_size = 0; - m->m_ext.ext_type = 0; - m->m_flags &= ~M_EXT; -#if defined(SCTP_SIMPLE_ALLOCATOR) - mb_dtor_mbuf(m, NULL); -#endif - SCTP_ZONE_FREE(zone_mbuf, m); - - /*umem_cache_free(zone_mbuf, m);*/ -} - -/* - * "Move" mbuf pkthdr from "from" to "to". - * "from" must have M_PKTHDR set, and "to" must be empty. - */ -void -m_move_pkthdr(struct mbuf *to, struct mbuf *from) -{ - - to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT); - if ((to->m_flags & M_EXT) == 0) - to->m_data = to->m_pktdat; - to->m_pkthdr = from->m_pkthdr; /* especially tags */ - SLIST_INIT(&from->m_pkthdr.tags); /* purge tags from src */ - from->m_flags &= ~M_PKTHDR; -} - - -/* - * Rearange an mbuf chain so that len bytes are contiguous - * and in the data area of an mbuf (so that mtod and dtom - * will work for a structure of size len). Returns the resulting - * mbuf chain on success, frees it and returns null on failure. - * If there is room, it will add up to max_protohdr-len extra bytes to the - * contiguous region in an attempt to avoid being called next time. - */ -struct mbuf * -m_pullup(struct mbuf *n, int len) -{ - struct mbuf *m; - int count; - int space; - - /* - * If first mbuf has no cluster, and has room for len bytes - * without shifting current data, pullup into it, - * otherwise allocate a new mbuf to prepend to the chain. - */ - if ((n->m_flags & M_EXT) == 0 && - n->m_data + len < &n->m_dat[MLEN] && n->m_next) { - if (n->m_len >= len) - return (n); - m = n; - n = n->m_next; - len -= m->m_len; - } else { - if (len > MHLEN) - goto bad; - MGET(m, M_NOWAIT, n->m_type); - if (m == NULL) - goto bad; - m->m_len = 0; - if (n->m_flags & M_PKTHDR) - M_MOVE_PKTHDR(m, n); - } - space = (int)(&m->m_dat[MLEN] - (m->m_data + m->m_len)); - do { - count = min(min(max(len, max_protohdr), space), n->m_len); - memcpy(mtod(m, caddr_t) + m->m_len,mtod(n, caddr_t), (u_int)count); - len -= count; - m->m_len += count; - n->m_len -= count; - space -= count; - if (n->m_len) - n->m_data += count; - else - n = m_free(n); - } while (len > 0 && n); - if (len > 0) { - (void) m_free(m); - goto bad; - } - m->m_next = n; - return (m); -bad: - m_freem(n); - return (NULL); -} - - -static struct mbuf * -m_dup1(struct mbuf *m, int off, int len, int wait) -{ - struct mbuf *n = NULL; - int copyhdr; - - if (len > MCLBYTES) - return NULL; - if (off == 0 && (m->m_flags & M_PKTHDR) != 0) - copyhdr = 1; - else - copyhdr = 0; - if (len >= MINCLSIZE) { - if (copyhdr == 1) { - m_clget(n, wait); /* TODO: include code for copying the header */ - m_dup_pkthdr(n, m, wait); - } else - m_clget(n, wait); - } else { - if (copyhdr == 1) - n = m_gethdr(wait, m->m_type); - else - n = m_get(wait, m->m_type); - } - if (!n) - return NULL; /* ENOBUFS */ - - if (copyhdr && !m_dup_pkthdr(n, m, wait)) { - m_free(n); - return NULL; - } - m_copydata(m, off, len, mtod(n, caddr_t)); - n->m_len = len; - return n; -} - - -/* Taken from sys/kern/uipc_mbuf2.c */ -struct mbuf * -m_pulldown(struct mbuf *m, int off, int len, int *offp) -{ - struct mbuf *n, *o; - int hlen, tlen, olen; - int writable; - - /* check invalid arguments. */ - KASSERT(m, ("m == NULL in m_pulldown()")); - if (len > MCLBYTES) { - m_freem(m); - return NULL; /* impossible */ - } - -#ifdef PULLDOWN_DEBUG - { - struct mbuf *t; - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "before:"); - for (t = m; t; t = t->m_next) - SCTP_DEBUG_USR(SCTP_DEBUG_USR, " %d", t->m_len); - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "\n"); - } -#endif - n = m; - while (n != NULL && off > 0) { - if (n->m_len > off) - break; - off -= n->m_len; - n = n->m_next; - } - /* be sure to point non-empty mbuf */ - while (n != NULL && n->m_len == 0) - n = n->m_next; - if (!n) { - m_freem(m); - return NULL; /* mbuf chain too short */ - } - - writable = 0; - if ((n->m_flags & M_EXT) == 0 || - (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n))) - writable = 1; - - /* - * the target data is on . - * if we got enough data on the mbuf "n", we're done. - */ - if ((off == 0 || offp) && len <= n->m_len - off && writable) - goto ok; - - /* - * when len <= n->m_len - off and off != 0, it is a special case. - * len bytes from sits in single mbuf, but the caller does - * not like the starting position (off). - * chop the current mbuf into two pieces, set off to 0. - */ - if (len <= n->m_len - off) { - o = m_dup1(n, off, n->m_len - off, M_NOWAIT); - if (o == NULL) { - m_freem(m); - return NULL; /* ENOBUFS */ - } - n->m_len = off; - o->m_next = n->m_next; - n->m_next = o; - n = n->m_next; - off = 0; - goto ok; - } - /* - * we need to take hlen from and tlen from m_next, 0>, - * and construct contiguous mbuf with m_len == len. - * note that hlen + tlen == len, and tlen > 0. - */ - hlen = n->m_len - off; - tlen = len - hlen; - - /* - * ensure that we have enough trailing data on mbuf chain. - * if not, we can do nothing about the chain. - */ - olen = 0; - for (o = n->m_next; o != NULL; o = o->m_next) - olen += o->m_len; - if (hlen + olen < len) { - m_freem(m); - return NULL; /* mbuf chain too short */ - } - - /* - * easy cases first. - * we need to use m_copydata() to get data from m_next, 0>. - */ - if ((off == 0 || offp) && (M_TRAILINGSPACE(n) >= tlen) && writable) { - m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len); - n->m_len += tlen; - m_adj(n->m_next, tlen); - goto ok; - } - - if ((off == 0 || offp) && (M_LEADINGSPACE(n->m_next) >= hlen) && writable) { - n->m_next->m_data -= hlen; - n->m_next->m_len += hlen; - memcpy( mtod(n->m_next, caddr_t), mtod(n, caddr_t) + off,hlen); - n->m_len -= hlen; - n = n->m_next; - off = 0; - goto ok; - } - - /* - * now, we need to do the hard way. don't m_copy as there's no room - * on both end. - */ - if (len > MLEN) - m_clget(o, M_NOWAIT); - /* o = m_getcl(M_NOWAIT, m->m_type, 0);*/ - else - o = m_get(M_NOWAIT, m->m_type); - if (!o) { - m_freem(m); - return NULL; /* ENOBUFS */ - } - /* get hlen from into */ - o->m_len = hlen; - memcpy(mtod(o, caddr_t), mtod(n, caddr_t) + off, hlen); - n->m_len -= hlen; - /* get tlen from m_next, 0> into */ - m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len); - o->m_len += tlen; - m_adj(n->m_next, tlen); - o->m_next = n->m_next; - n->m_next = o; - n = o; - off = 0; -ok: -#ifdef PULLDOWN_DEBUG - { - struct mbuf *t; - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "after:"); - for (t = m; t; t = t->m_next) - SCTP_DEBUG_USR(SCTP_DEBUG_USR, "%c%d", t == n ? '*' : ' ', t->m_len); - SCTP_DEBUG_USR(SCTP_DEBUG_USR, " (off=%d)\n", off); - } -#endif - if (offp) - *offp = off; - return n; -} - -/* - * Attach the the cluster from *m to *n, set up m_ext in *n - * and bump the refcount of the cluster. - */ -static void -mb_dupcl(struct mbuf *n, struct mbuf *m) -{ - KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__)); - KASSERT(m->m_ext.ref_cnt != NULL, ("%s: ref_cnt not set", __func__)); - KASSERT((n->m_flags & M_EXT) == 0, ("%s: M_EXT set", __func__)); - - if (*(m->m_ext.ref_cnt) == 1) - *(m->m_ext.ref_cnt) += 1; - else - atomic_add_int(m->m_ext.ref_cnt, 1); - n->m_ext.ext_buf = m->m_ext.ext_buf; - n->m_ext.ext_free = m->m_ext.ext_free; - n->m_ext.ext_args = m->m_ext.ext_args; - n->m_ext.ext_size = m->m_ext.ext_size; - n->m_ext.ref_cnt = m->m_ext.ref_cnt; - n->m_ext.ext_type = m->m_ext.ext_type; - n->m_flags |= M_EXT; -} - - -/* - * Make a copy of an mbuf chain starting "off0" bytes from the beginning, - * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. - * The wait parameter is a choice of M_TRYWAIT/M_NOWAIT from caller. - * Note that the copy is read-only, because clusters are not copied, - * only their reference counts are incremented. - */ - -struct mbuf * -m_copym(struct mbuf *m, int off0, int len, int wait) -{ - struct mbuf *n, **np; - int off = off0; - struct mbuf *top; - int copyhdr = 0; - - KASSERT(off >= 0, ("m_copym, negative off %d", off)); - KASSERT(len >= 0, ("m_copym, negative len %d", len)); - KASSERT(m != NULL, ("m_copym, m is NULL")); - -#if !defined(INVARIANTS) - if (m == NULL) { - return (NULL); - } -#endif - if (off == 0 && m->m_flags & M_PKTHDR) - copyhdr = 1; - while (off > 0) { - KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain")); - if (off < m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - np = ⊤ - top = 0; - while (len > 0) { - if (m == NULL) { - KASSERT(len == M_COPYALL, ("m_copym, length > size of mbuf chain")); - break; - } - if (copyhdr) - MGETHDR(n, wait, m->m_type); - else - MGET(n, wait, m->m_type); - *np = n; - if (n == NULL) - goto nospace; - if (copyhdr) { - if (!m_dup_pkthdr(n, m, wait)) - goto nospace; - if (len == M_COPYALL) - n->m_pkthdr.len -= off0; - else - n->m_pkthdr.len = len; - copyhdr = 0; - } - n->m_len = min(len, m->m_len - off); - if (m->m_flags & M_EXT) { - n->m_data = m->m_data + off; - mb_dupcl(n, m); - } else - memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off, (u_int)n->m_len); - if (len != M_COPYALL) - len -= n->m_len; - off = 0; - m = m->m_next; - np = &n->m_next; - } - - return (top); -nospace: - m_freem(top); - return (NULL); -} - - -int -m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how) -{ - struct m_tag *p, *t, *tprev = NULL; - - KASSERT(to && from, ("m_tag_copy_chain: null argument, to %p from %p", (void *)to, (void *)from)); - m_tag_delete_chain(to, NULL); - SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) { - t = m_tag_copy(p, how); - if (t == NULL) { - m_tag_delete_chain(to, NULL); - return 0; - } - if (tprev == NULL) - SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link); - else - SLIST_INSERT_AFTER(tprev, t, m_tag_link); - tprev = t; - } - return 1; -} - -/* - * Duplicate "from"'s mbuf pkthdr in "to". - * "from" must have M_PKTHDR set, and "to" must be empty. - * In particular, this does a deep copy of the packet tags. - */ -int -m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how) -{ - - KASSERT(to, ("m_dup_pkthdr: to is NULL")); - KASSERT(from, ("m_dup_pkthdr: from is NULL")); - to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT); - if ((to->m_flags & M_EXT) == 0) - to->m_data = to->m_pktdat; - to->m_pkthdr = from->m_pkthdr; - SLIST_INIT(&to->m_pkthdr.tags); - return (m_tag_copy_chain(to, from, MBTOM(how))); -} - -/* Copy a single tag. */ -struct m_tag * -m_tag_copy(struct m_tag *t, int how) -{ - struct m_tag *p; - - KASSERT(t, ("m_tag_copy: null tag")); - p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how); - if (p == NULL) - return (NULL); - memcpy(p + 1, t + 1, t->m_tag_len); /* Copy the data */ - return p; -} - -/* Get a packet tag structure along with specified data following. */ -struct m_tag * -m_tag_alloc(uint32_t cookie, int type, int len, int wait) -{ - struct m_tag *t; - - if (len < 0) - return NULL; - t = malloc(len + sizeof(struct m_tag)); - if (t == NULL) - return NULL; - m_tag_setup(t, cookie, type, len); - t->m_tag_free = m_tag_free_default; - return t; -} - -/* Free a packet tag. */ -void -m_tag_free_default(struct m_tag *t) -{ - free(t); -} - -/* - * Copy data from a buffer back into the indicated mbuf chain, - * starting "off" bytes from the beginning, extending the mbuf - * chain if necessary. - */ -void -m_copyback(struct mbuf *m0, int off, int len, caddr_t cp) -{ - int mlen; - struct mbuf *m = m0, *n; - int totlen = 0; - - if (m0 == NULL) - return; - while (off > (mlen = m->m_len)) { - off -= mlen; - totlen += mlen; - if (m->m_next == NULL) { - n = m_get(M_NOWAIT, m->m_type); - if (n == NULL) - goto out; - memset(mtod(n, caddr_t), 0, MLEN); - n->m_len = min(MLEN, len + off); - m->m_next = n; - } - m = m->m_next; - } - while (len > 0) { - mlen = min (m->m_len - off, len); - memcpy(off + mtod(m, caddr_t), cp, (u_int)mlen); - cp += mlen; - len -= mlen; - mlen += off; - off = 0; - totlen += mlen; - if (len == 0) - break; - if (m->m_next == NULL) { - n = m_get(M_NOWAIT, m->m_type); - if (n == NULL) - break; - n->m_len = min(MLEN, len); - m->m_next = n; - } - m = m->m_next; - } -out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) - m->m_pkthdr.len = totlen; -} - -/* - * Apply function f to the data in an mbuf chain starting "off" bytes from - * the beginning, continuing for "len" bytes. - */ -int -m_apply(struct mbuf *m, int off, int len, - int (*f)(void *, void *, u_int), void *arg) -{ - u_int count; - int rval; - - KASSERT(off >= 0, ("m_apply, negative off %d", off)); - KASSERT(len >= 0, ("m_apply, negative len %d", len)); - while (off > 0) { - KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain")); - if (off < m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - while (len > 0) { - KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain")); - count = min(m->m_len - off, len); - rval = (*f)(arg, mtod(m, caddr_t) + off, count); - if (rval) - return (rval); - len -= count; - off = 0; - m = m->m_next; - } - return (0); -} - -/* - * Lesser-used path for M_PREPEND: - * allocate new mbuf to prepend to chain, - * copy junk along. - */ -struct mbuf * -m_prepend(struct mbuf *m, int len, int how) -{ - struct mbuf *mn; - - if (m->m_flags & M_PKTHDR) - MGETHDR(mn, how, m->m_type); - else - MGET(mn, how, m->m_type); - if (mn == NULL) { - m_freem(m); - return (NULL); - } - if (m->m_flags & M_PKTHDR) - M_MOVE_PKTHDR(mn, m); - mn->m_next = m; - m = mn; - if (m->m_flags & M_PKTHDR) { - if (len < MHLEN) - MH_ALIGN(m, len); - } else { - if (len < MLEN) - M_ALIGN(m, len); - } - m->m_len = len; - return (m); -} - -/* - * Copy data from an mbuf chain starting "off" bytes from the beginning, - * continuing for "len" bytes, into the indicated buffer. - */ -void -m_copydata(const struct mbuf *m, int off, int len, caddr_t cp) -{ - u_int count; - - KASSERT(off >= 0, ("m_copydata, negative off %d", off)); - KASSERT(len >= 0, ("m_copydata, negative len %d", len)); - while (off > 0) { - KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); - if (off < m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - while (len > 0) { - KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain")); - count = min(m->m_len - off, len); - memcpy(cp, mtod(m, caddr_t) + off, count); - len -= count; - cp += count; - off = 0; - m = m->m_next; - } -} - - -/* - * Concatenate mbuf chain n to m. - * Both chains must be of the same type (e.g. MT_DATA). - * Any m_pkthdr is not updated. - */ -void -m_cat(struct mbuf *m, struct mbuf *n) -{ - while (m->m_next) - m = m->m_next; - while (n) { - if (m->m_flags & M_EXT || - m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { - /* just join the two chains */ - m->m_next = n; - return; - } - /* splat the data from one into the other */ - memcpy(mtod(m, caddr_t) + m->m_len, mtod(n, caddr_t), (u_int)n->m_len); - m->m_len += n->m_len; - n = m_free(n); - } -} - - -void -m_adj(struct mbuf *mp, int req_len) -{ - int len = req_len; - struct mbuf *m; - int count; - - if ((m = mp) == NULL) - return; - if (len >= 0) { - /* - * Trim from head. - */ - while (m != NULL && len > 0) { - if (m->m_len <= len) { - len -= m->m_len; - m->m_len = 0; - m = m->m_next; - } else { - m->m_len -= len; - m->m_data += len; - len = 0; - } - } - m = mp; - if (mp->m_flags & M_PKTHDR) - m->m_pkthdr.len -= (req_len - len); - } else { - /* - * Trim from tail. Scan the mbuf chain, - * calculating its length and finding the last mbuf. - * If the adjustment only affects this mbuf, then just - * adjust and return. Otherwise, rescan and truncate - * after the remaining size. - */ - len = -len; - count = 0; - for (;;) { - count += m->m_len; - if (m->m_next == (struct mbuf *)0) - break; - m = m->m_next; - } - if (m->m_len >= len) { - m->m_len -= len; - if (mp->m_flags & M_PKTHDR) - mp->m_pkthdr.len -= len; - return; - } - count -= len; - if (count < 0) - count = 0; - /* - * Correct length for chain is "count". - * Find the mbuf with last data, adjust its length, - * and toss data from remaining mbufs on chain. - */ - m = mp; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len = count; - for (; m; m = m->m_next) { - if (m->m_len >= count) { - m->m_len = count; - if (m->m_next != NULL) { - m_freem(m->m_next); - m->m_next = NULL; - } - break; - } - count -= m->m_len; - } - } -} - - -/* m_split is used within sctp_handle_cookie_echo. */ - -/* - * Partition an mbuf chain in two pieces, returning the tail -- - * all but the first len0 bytes. In case of failure, it returns NULL and - * attempts to restore the chain to its original state. - * - * Note that the resulting mbufs might be read-only, because the new - * mbuf can end up sharing an mbuf cluster with the original mbuf if - * the "breaking point" happens to lie within a cluster mbuf. Use the - * M_WRITABLE() macro to check for this case. - */ -struct mbuf * -m_split(struct mbuf *m0, int len0, int wait) -{ - struct mbuf *m, *n; - u_int len = len0, remain; - - /* MBUF_CHECKSLEEP(wait); */ - for (m = m0; m && (int)len > m->m_len; m = m->m_next) - len -= m->m_len; - if (m == NULL) - return (NULL); - remain = m->m_len - len; - if (m0->m_flags & M_PKTHDR) { - MGETHDR(n, wait, m0->m_type); - if (n == NULL) - return (NULL); - n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; - n->m_pkthdr.len = m0->m_pkthdr.len - len0; - m0->m_pkthdr.len = len0; - if (m->m_flags & M_EXT) - goto extpacket; - if (remain > MHLEN) { - /* m can't be the lead packet */ - MH_ALIGN(n, 0); - n->m_next = m_split(m, len, wait); - if (n->m_next == NULL) { - (void) m_free(n); - return (NULL); - } else { - n->m_len = 0; - return (n); - } - } else - MH_ALIGN(n, remain); - } else if (remain == 0) { - n = m->m_next; - m->m_next = NULL; - return (n); - } else { - MGET(n, wait, m->m_type); - if (n == NULL) - return (NULL); - M_ALIGN(n, remain); - } -extpacket: - if (m->m_flags & M_EXT) { - n->m_data = m->m_data + len; - mb_dupcl(n, m); - } else { - memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + len, remain); - } - n->m_len = remain; - m->m_len = len; - n->m_next = m->m_next; - m->m_next = NULL; - return (n); -} - - - - -int -pack_send_buffer(caddr_t buffer, struct mbuf* mb){ - - int count_to_copy; - int total_count_copied = 0; - int offset = 0; - - do { - count_to_copy = mb->m_len; - memcpy(buffer+offset, mtod(mb, caddr_t), count_to_copy); - offset += count_to_copy; - total_count_copied += count_to_copy; - mb = mb->m_next; - } while(mb); - - return (total_count_copied); -} diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.h deleted file mode 100644 index 268988f9..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_mbuf.h +++ /dev/null @@ -1,412 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _USER_MBUF_H_ -#define _USER_MBUF_H_ - -/* __Userspace__ header file for mbufs */ -#include -#if !defined(SCTP_SIMPLE_ALLOCATOR) -#include "umem.h" -#endif -#include "user_malloc.h" -#include "netinet/sctp_os_userspace.h" - -#define USING_MBUF_CONSTRUCTOR 0 - -/* For Linux */ -#ifndef MSIZE -#define MSIZE 256 -/* #define MSIZE 1024 */ -#endif -#ifndef MCLBYTES -#define MCLBYTES 2048 -#endif - -struct mbuf * m_gethdr(int how, short type); -struct mbuf * m_get(int how, short type); -struct mbuf * m_free(struct mbuf *m); -void m_clget(struct mbuf *m, int how); -struct mbuf * m_getm2(struct mbuf *m, int len, int how, short type, int flags, int allonebuf); -struct mbuf *m_uiotombuf(struct uio *uio, int how, int len, int align, int flags); -u_int m_length(struct mbuf *m0, struct mbuf **last); -struct mbuf *m_last(struct mbuf *m); - -/* mbuf initialization function */ -void mbuf_initialize(void *); - -#define M_MOVE_PKTHDR(to, from) m_move_pkthdr((to), (from)) -#define MGET(m, how, type) ((m) = m_get((how), (type))) -#define MGETHDR(m, how, type) ((m) = m_gethdr((how), (type))) -#define MCLGET(m, how) m_clget((m), (how)) - - -#define M_HDR_PAD ((sizeof(intptr_t)==4) ? 2 : 6) /* modified for __Userspace__ */ - -/* Length to m_copy to copy all. */ -#define M_COPYALL 1000000000 - -/* umem_cache_t is defined in user_include/umem.h as - * typedef struct umem_cache umem_cache_t; - * Note:umem_zone_t is a pointer. - */ -#if defined(SCTP_SIMPLE_ALLOCATOR) -typedef size_t sctp_zone_t; -#else -typedef umem_cache_t *sctp_zone_t; -#endif - -extern sctp_zone_t zone_mbuf; -extern sctp_zone_t zone_clust; -extern sctp_zone_t zone_ext_refcnt; - -/*- - * Macros for type conversion: - * mtod(m, t) -- Convert mbuf pointer to data pointer of correct type. - * dtom(x) -- Convert data pointer within mbuf to mbuf pointer (XXX). - */ -#define mtod(m, t) ((t)((m)->m_data)) -#define dtom(x) ((struct mbuf *)((intptr_t)(x) & ~(MSIZE-1))) - -struct mb_args { - int flags; /* Flags for mbuf being allocated */ - short type; /* Type of mbuf being allocated */ -}; - -struct clust_args { - struct mbuf * parent_mbuf; -}; - -struct mbuf * m_split(struct mbuf *, int, int); -void m_cat(struct mbuf *m, struct mbuf *n); -void m_adj(struct mbuf *, int); -void mb_free_ext(struct mbuf *); -void m_freem(struct mbuf *); -struct m_tag *m_tag_alloc(uint32_t, int, int, int); -struct mbuf *m_copym(struct mbuf *, int, int, int); -void m_copyback(struct mbuf *, int, int, caddr_t); -int m_apply(struct mbuf *, int, int, int (*)(void *, void *, u_int), void *arg); -struct mbuf *m_pullup(struct mbuf *, int); -struct mbuf *m_pulldown(struct mbuf *, int off, int len, int *offp); -int m_dup_pkthdr(struct mbuf *, struct mbuf *, int); -struct m_tag *m_tag_copy(struct m_tag *, int); -int m_tag_copy_chain(struct mbuf *, struct mbuf *, int); -struct mbuf *m_prepend(struct mbuf *, int, int); -void m_copydata(const struct mbuf *, int, int, caddr_t); - -#define MBUF_MEM_NAME "mbuf" -#define MBUF_CLUSTER_MEM_NAME "mbuf_cluster" -#define MBUF_EXTREFCNT_MEM_NAME "mbuf_ext_refcnt" - -/* - * Mbufs are of a single size, MSIZE (sys/param.h), which includes overhead. - * An mbuf may add a single "mbuf cluster" of size MCLBYTES (also in - * sys/param.h), which has no additional overhead and is used instead of the - * internal data area; this is done when at least MINCLSIZE of data must be - * stored. Additionally, it is possible to allocate a separate buffer - * externally and attach it to the mbuf in a way similar to that of mbuf - * clusters. - */ -#define MLEN ((int)(MSIZE - sizeof(struct m_hdr))) /* normal data len */ -#define MHLEN ((int)(MLEN - sizeof(struct pkthdr))) /* data len w/pkthdr */ -#define MINCLSIZE ((int)(MHLEN + 1)) /* smallest amount to put in cluster */ -#define M_MAXCOMPRESS (MHLEN / 2) /* max amount to copy for compression */ - - -/* - * Header present at the beginning of every mbuf. - */ -struct m_hdr { - struct mbuf *mh_next; /* next buffer in chain */ - struct mbuf *mh_nextpkt; /* next chain in queue/record */ - caddr_t mh_data; /* location of data */ - int mh_len; /* amount of data in this mbuf */ - int mh_flags; /* flags; see below */ - short mh_type; /* type of data in this mbuf */ - uint8_t pad[M_HDR_PAD];/* word align */ -}; - -/* - * Packet tag structure (see below for details). - */ -struct m_tag { - SLIST_ENTRY(m_tag) m_tag_link; /* List of packet tags */ - uint16_t m_tag_id; /* Tag ID */ - uint16_t m_tag_len; /* Length of data */ - uint32_t m_tag_cookie; /* ABI/Module ID */ - void (*m_tag_free)(struct m_tag *); -}; - -/* - * Record/packet header in first mbuf of chain; valid only if M_PKTHDR is set. - */ -struct pkthdr { - struct ifnet *rcvif; /* rcv interface */ - /* variables for ip and tcp reassembly */ - void *header; /* pointer to packet header */ - int len; /* total packet length */ - /* variables for hardware checksum */ - int csum_flags; /* flags regarding checksum */ - int csum_data; /* data field used by csum routines */ - uint16_t tso_segsz; /* TSO segment size */ - uint16_t ether_vtag; /* Ethernet 802.1p+q vlan tag */ - SLIST_HEAD(packet_tags, m_tag) tags; /* list of packet tags */ -}; - -/* - * Description of external storage mapped into mbuf; valid only if M_EXT is - * set. - */ -struct m_ext { - caddr_t ext_buf; /* start of buffer */ - void (*ext_free) /* free routine if not the usual */ - (void *, void *); - void *ext_args; /* optional argument pointer */ - u_int ext_size; /* size of buffer, for ext_free */ - volatile u_int *ref_cnt; /* pointer to ref count info */ - int ext_type; /* type of external storage */ -}; - - -/* - * The core of the mbuf object along with some shortcut defined for practical - * purposes. - */ -struct mbuf { - struct m_hdr m_hdr; - union { - struct { - struct pkthdr MH_pkthdr; /* M_PKTHDR set */ - union { - struct m_ext MH_ext; /* M_EXT set */ - char MH_databuf[MHLEN]; - } MH_dat; - } MH; - char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */ - } M_dat; -}; - -#define m_next m_hdr.mh_next -#define m_len m_hdr.mh_len -#define m_data m_hdr.mh_data -#define m_type m_hdr.mh_type -#define m_flags m_hdr.mh_flags -#define m_nextpkt m_hdr.mh_nextpkt -#define m_act m_nextpkt -#define m_pkthdr M_dat.MH.MH_pkthdr -#define m_ext M_dat.MH.MH_dat.MH_ext -#define m_pktdat M_dat.MH.MH_dat.MH_databuf -#define m_dat M_dat.M_databuf - - -/* - * mbuf flags. - */ -#define M_EXT 0x0001 /* has associated external storage */ -#define M_PKTHDR 0x0002 /* start of record */ -#define M_EOR 0x0004 /* end of record */ -#define M_RDONLY 0x0008 /* associated data is marked read-only */ -#define M_PROTO1 0x0010 /* protocol-specific */ -#define M_PROTO2 0x0020 /* protocol-specific */ -#define M_PROTO3 0x0040 /* protocol-specific */ -#define M_PROTO4 0x0080 /* protocol-specific */ -#define M_PROTO5 0x0100 /* protocol-specific */ -#define M_FREELIST 0x8000 /* mbuf is on the free list */ - - -/* - * Flags copied when copying m_pkthdr. - */ -#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_RDONLY|M_PROTO1|M_PROTO1|M_PROTO2|\ - M_PROTO3|M_PROTO4|M_PROTO5|\ - M_BCAST|M_MCAST|M_FRAG|M_FIRSTFRAG|M_LASTFRAG|\ - M_VLANTAG|M_PROMISC) - - -/* - * mbuf pkthdr flags (also stored in m_flags). - */ -#define M_BCAST 0x0200 /* send/received as link-level broadcast */ -#define M_MCAST 0x0400 /* send/received as link-level multicast */ -#define M_FRAG 0x0800 /* packet is a fragment of a larger packet */ -#define M_FIRSTFRAG 0x1000 /* packet is first fragment */ -#define M_LASTFRAG 0x2000 /* packet is last fragment */ -#define M_VLANTAG 0x10000 /* ether_vtag is valid */ -#define M_PROMISC 0x20000 /* packet was not for us */ -#define M_NOFREE 0x40000 /* do not free mbuf - it is embedded in the cluster */ - - -/* - * External buffer types: identify ext_buf type. - */ -#define EXT_CLUSTER 1 /* mbuf cluster */ -#define EXT_SFBUF 2 /* sendfile(2)'s sf_bufs */ -#define EXT_JUMBOP 3 /* jumbo cluster 4096 bytes */ -#define EXT_JUMBO9 4 /* jumbo cluster 9216 bytes */ -#define EXT_JUMBO16 5 /* jumbo cluster 16184 bytes */ -#define EXT_PACKET 6 /* mbuf+cluster from packet zone */ -#define EXT_MBUF 7 /* external mbuf reference (M_IOVEC) */ -#define EXT_NET_DRV 100 /* custom ext_buf provided by net driver(s) */ -#define EXT_MOD_TYPE 200 /* custom module's ext_buf type */ -#define EXT_DISPOSABLE 300 /* can throw this buffer away w/page flipping */ -#define EXT_EXTREF 400 /* has externally maintained ref_cnt ptr */ - - -/* - * mbuf types. - */ -#define MT_NOTMBUF 0 /* USED INTERNALLY ONLY! Object is not mbuf */ -#define MT_DATA 1 /* dynamic (data) allocation */ -#define MT_HEADER MT_DATA /* packet header, use M_PKTHDR instead */ -#define MT_SONAME 8 /* socket name */ -#define MT_CONTROL 14 /* extra-data protocol message */ -#define MT_OOBDATA 15 /* expedited data */ -#define MT_NTYPES 16 /* number of mbuf types for mbtypes[] */ - -/* - * __Userspace__ flags like M_NOWAIT are defined in malloc.h - * Flags like these are used in functions like uma_zalloc() - * but don't have an equivalent in userland umem - * Flags specifying how an allocation should be made. - * - * The flag to use is as follows: - * - M_DONTWAIT or M_NOWAIT from an interrupt handler to not block allocation. - * - M_WAIT or M_WAITOK or M_TRYWAIT from wherever it is safe to block. - * - * M_DONTWAIT/M_NOWAIT means that we will not block the thread explicitly and - * if we cannot allocate immediately we may return NULL, whereas - * M_WAIT/M_WAITOK/M_TRYWAIT means that if we cannot allocate resources we - * will block until they are available, and thus never return NULL. - * - * XXX Eventually just phase this out to use M_WAITOK/M_NOWAIT. - */ -#define MBTOM(how) (how) - -void m_tag_delete(struct mbuf *, struct m_tag *); -void m_tag_delete_chain(struct mbuf *, struct m_tag *); -void m_move_pkthdr(struct mbuf *, struct mbuf *); -void m_tag_free_default(struct m_tag *); - -extern int max_linkhdr; /* Largest link-level header */ -extern int max_protohdr; /* Size of largest protocol layer header. See user_mbuf.c */ - -/* - * Evaluate TRUE if it's safe to write to the mbuf m's data region (this can - * be both the local data payload, or an external buffer area, depending on - * whether M_EXT is set). - */ -#define M_WRITABLE(m) (!((m)->m_flags & M_RDONLY) && \ - (!(((m)->m_flags & M_EXT)) || \ - (*((m)->m_ext.ref_cnt) == 1)) ) \ - -/* Check if the supplied mbuf has a packet header, or else panic. */ -#define M_ASSERTPKTHDR(m) \ - KASSERT((m) != NULL && (m)->m_flags & M_PKTHDR, \ - ("%s: no mbuf packet header!", __func__)) - -/* - * Compute the amount of space available before the current start of data in - * an mbuf. - * - * The M_WRITABLE() is a temporary, conservative safety measure: the burden - * of checking writability of the mbuf data area rests solely with the caller. - */ -#define M_LEADINGSPACE(m) \ - (((m)->m_flags & M_EXT) ? \ - (M_WRITABLE(m) ? (m)->m_data - (m)->m_ext.ext_buf : 0): \ - ((m)->m_flags & M_PKTHDR)? (m)->m_data - (m)->m_pktdat : \ - (m)->m_data - (m)->m_dat) - -/* - * Compute the amount of space available after the end of data in an mbuf. - * - * The M_WRITABLE() is a temporary, conservative safety measure: the burden - * of checking writability of the mbuf data area rests solely with the caller. - */ -#define M_TRAILINGSPACE(m) \ - (((m)->m_flags & M_EXT) ? \ - (M_WRITABLE(m) ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size \ - - ((m)->m_data + (m)->m_len) : 0) : \ - &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len)) - - - -/* - * Arrange to prepend space of size plen to mbuf m. If a new mbuf must be - * allocated, how specifies whether to wait. If the allocation fails, the - * original mbuf chain is freed and m is set to NULL. - */ -#define M_PREPEND(m, plen, how) do { \ - struct mbuf **_mmp = &(m); \ - struct mbuf *_mm = *_mmp; \ - int _mplen = (plen); \ - int __mhow = (how); \ - \ - if (M_LEADINGSPACE(_mm) >= _mplen) { \ - _mm->m_data -= _mplen; \ - _mm->m_len += _mplen; \ - } else \ - _mm = m_prepend(_mm, _mplen, __mhow); \ - if (_mm != NULL && _mm->m_flags & M_PKTHDR) \ - _mm->m_pkthdr.len += _mplen; \ - *_mmp = _mm; \ -} while (0) - -/* - * Set the m_data pointer of a newly-allocated mbuf (m_get/MGET) to place an - * object of the specified size at the end of the mbuf, longword aligned. - */ -#define M_ALIGN(m, len) do { \ - KASSERT(!((m)->m_flags & (M_PKTHDR|M_EXT)), \ - ("%s: M_ALIGN not normal mbuf", __func__)); \ - KASSERT((m)->m_data == (m)->m_dat, \ - ("%s: M_ALIGN not a virgin mbuf", __func__)); \ - (m)->m_data += (MLEN - (len)) & ~(sizeof(long) - 1); \ -} while (0) - -/* - * As above, for mbufs allocated with m_gethdr/MGETHDR or initialized by - * M_DUP/MOVE_PKTHDR. - */ -#define MH_ALIGN(m, len) do { \ - KASSERT((m)->m_flags & M_PKTHDR && !((m)->m_flags & M_EXT), \ - ("%s: MH_ALIGN not PKTHDR mbuf", __func__)); \ - KASSERT((m)->m_data == (m)->m_pktdat, \ - ("%s: MH_ALIGN not a virgin mbuf", __func__)); \ - (m)->m_data += (MHLEN - (len)) & ~(sizeof(long) - 1); \ -} while (0) - -#define M_SIZE(m) \ - (((m)->m_flags & M_EXT) ? (m)->m_ext.ext_size : \ - ((m)->m_flags & M_PKTHDR) ? MHLEN : \ - MLEN) - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_queue.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_queue.h deleted file mode 100644 index fcd368bd..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_queue.h +++ /dev/null @@ -1,639 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _USER_QUEUE_H_ -#define _USER_QUEUE_H_ - -/* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - - - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_AFTER + - + - - * _REMOVE_HEAD + - + - - * _REMOVE + + + + - * _SWAP + + + + - * - */ -#ifdef QUEUE_MACRO_DEBUG -/* Store the last 2 places the queue element or head was altered */ -struct qm_trace { - char * lastfile; - int lastline; - char * prevfile; - int prevline; -}; - -#define TRACEBUF struct qm_trace trace; -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) - -#define QMD_TRACE_HEAD(head) do { \ - (head)->trace.prevline = (head)->trace.lastline; \ - (head)->trace.prevfile = (head)->trace.lastfile; \ - (head)->trace.lastline = __LINE__; \ - (head)->trace.lastfile = __FILE__; \ -} while (0) - -#define QMD_TRACE_ELEM(elem) do { \ - (elem)->trace.prevline = (elem)->trace.lastline; \ - (elem)->trace.prevfile = (elem)->trace.lastfile; \ - (elem)->trace.lastline = __LINE__; \ - (elem)->trace.lastfile = __FILE__; \ -} while (0) - -#else -#define QMD_TRACE_ELEM(elem) -#define QMD_TRACE_HEAD(head) -#define QMD_SAVELINK(name, link) -#define TRACEBUF -#define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#if defined(_WIN32) -#if defined(SLIST_ENTRY) -#undef SLIST_ENTRY -#endif -#endif - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != NULL; \ - (varp) = &SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ -} while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_AFTER(curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define SLIST_REMOVE_AFTER(elm, field) do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ -} while (0) - -#define SLIST_SWAP(head1, head2, type) do { \ - struct type *swap_first = SLIST_FIRST(head1); \ - SLIST_FIRST(head1) = SLIST_FIRST(head2); \ - SLIST_FIRST(head2) = swap_first; \ -} while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ -} while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_SWAP(head1, head2, type) do { \ - struct type *swap_first = STAILQ_FIRST(head1); \ - struct type **swap_last = (head1)->stqh_last; \ - STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_FIRST(head2) = swap_first; \ - (head2)->stqh_last = swap_last; \ - if (STAILQ_EMPTY(head1)) \ - (head1)->stqh_last = &STAILQ_FIRST(head1); \ - if (STAILQ_EMPTY(head2)) \ - (head2)->stqh_last = &STAILQ_FIRST(head2); \ -} while (0) - - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#if defined(INVARIANTS) -#define QMD_LIST_CHECK_HEAD(head, field) do { \ - if (LIST_FIRST((head)) != NULL && \ - LIST_FIRST((head))->field.le_prev != \ - &LIST_FIRST((head))) \ - panic("Bad list head %p first->prev != head", (void *)(head)); \ -} while (0) - -#define QMD_LIST_CHECK_NEXT(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL && \ - LIST_NEXT((elm), field)->field.le_prev != \ - &((elm)->field.le_next)) \ - panic("Bad link elm %p next->prev != elm", (void *)(elm)); \ -} while (0) - -#define QMD_LIST_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.le_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (void *)(elm)); \ -} while (0) -#else -#define QMD_LIST_CHECK_HEAD(head, field) -#define QMD_LIST_CHECK_NEXT(elm, field) -#define QMD_LIST_CHECK_PREV(elm, field) -#endif /* (INVARIANTS) */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QMD_LIST_CHECK_NEXT(listelm, field); \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_LIST_CHECK_PREV(listelm, field); \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QMD_LIST_CHECK_HEAD((head), field); \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.le_next); \ - QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ - QMD_LIST_CHECK_NEXT(elm, field); \ - QMD_LIST_CHECK_PREV(elm, field); \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ -} while (0) - -#define LIST_SWAP(head1, head2, type, field) do { \ - struct type *swap_tmp = LIST_FIRST((head1)); \ - LIST_FIRST((head1)) = LIST_FIRST((head2)); \ - LIST_FIRST((head2)) = swap_tmp; \ - if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ - if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ -} while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ -} - -/* - * Tail queue functions. - */ -#if defined(INVARIANTS) -#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ - if (!TAILQ_EMPTY(head) && \ - TAILQ_FIRST((head))->field.tqe_prev != \ - &TAILQ_FIRST((head))) \ - panic("Bad tailq head %p first->prev != head", (void *)(head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ - if (*(head)->tqh_last != NULL) \ - panic("Bad tailq NEXT(%p->tqh_last) != NULL", (void *)(head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ - if (TAILQ_NEXT((elm), field) != NULL && \ - TAILQ_NEXT((elm), field)->field.tqe_prev != \ - &((elm)->field.tqe_next)) \ - panic("Bad link elm %p next->prev != elm", (void *)(elm)); \ -} while (0) - -#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.tqe_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (void *)(elm)); \ -} while (0) -#else -#define QMD_TAILQ_CHECK_HEAD(head, field) -#define QMD_TAILQ_CHECK_TAIL(head, headname) -#define QMD_TAILQ_CHECK_NEXT(elm, field) -#define QMD_TAILQ_CHECK_PREV(elm, field) -#endif /* (INVARIANTS) */ - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - QMD_TRACE_HEAD(head1); \ - QMD_TRACE_HEAD(head2); \ - } \ -} while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QMD_TAILQ_CHECK_NEXT(listelm, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else { \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - } \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_TAILQ_CHECK_PREV(listelm, field); \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QMD_TAILQ_CHECK_HEAD(head, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QMD_TAILQ_CHECK_TAIL(head, field); \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ - QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ - QMD_TAILQ_CHECK_NEXT(elm, field); \ - QMD_TAILQ_CHECK_PREV(elm, field); \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - QMD_TRACE_HEAD(head); \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_SWAP(head1, head2, type, field) do { \ - struct type *swap_first = (head1)->tqh_first; \ - struct type **swap_last = (head1)->tqh_last; \ - (head1)->tqh_first = (head2)->tqh_first; \ - (head1)->tqh_last = (head2)->tqh_last; \ - (head2)->tqh_first = swap_first; \ - (head2)->tqh_last = swap_last; \ - if ((swap_first = (head1)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head1)->tqh_first; \ - else \ - (head1)->tqh_last = &(head1)->tqh_first; \ - if ((swap_first = (head2)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head2)->tqh_first; \ - else \ - (head2)->tqh_last = &(head2)->tqh_first; \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.c deleted file mode 100644 index 66be13d7..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.c +++ /dev/null @@ -1,1566 +0,0 @@ -/*- - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#if defined(INET) || defined(INET6) -#include -#if !defined(_WIN32) -#include -#include -#include -#include -#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#include -#else -#include -#endif -#endif -#include -#include -#include -#include -#if 0 -#if defined(__linux__) -#include -#ifdef HAVE_LINUX_IF_ADDR_H -#include -#endif -#ifdef HAVE_LINUX_RTNETLINK_H -#include -#endif -#endif -#endif -#if defined(HAVE_NET_ROUTE_H) -# include -#elif defined(__APPLE__) -/* Apple SDKs for iOS, tvOS, watchOS, etc. don't ship this header */ -# define RTM_NEWADDR 0xc -# define RTM_DELADDR 0xd -# define RTAX_IFA 5 -# define RTAX_MAX 8 -#endif -/* local macros and datatypes used to get IP addresses system independently */ -#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) -# error "Can't determine socket option to use to get UDP IP" -#endif - -void recv_thread_destroy(void); - -#define MAXLEN_MBUF_CHAIN 128 - -#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) - -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) -#define NEXT_SA(ap) ap = (struct sockaddr *) \ - ((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (uint32_t)) : sizeof(uint32_t))) -#endif - -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) -static void -sctp_get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) -{ - int i; - - for (i = 0; i < RTAX_MAX; i++) { - if (addrs & (1 << i)) { - rti_info[i] = sa; - NEXT_SA(sa); - } else { - rti_info[i] = NULL; - } - } -} - -static void -sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa) -{ - int rc; - struct ifaddrs *ifa, *ifas; - - /* handle only the types we want */ - if ((type != RTM_NEWADDR) && (type != RTM_DELADDR)) { - return; - } - - rc = getifaddrs(&ifas); - if (rc != 0) { - return; - } - for (ifa = ifas; ifa; ifa = ifa->ifa_next) { - if (index == if_nametoindex(ifa->ifa_name)) { - break; - } - } - if (ifa == NULL) { - freeifaddrs(ifas); - return; - } - - /* relay the appropriate address change to the base code */ - if (type == RTM_NEWADDR) { - (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, - NULL, - if_nametoindex(ifa->ifa_name), - 0, - ifa->ifa_name, - NULL, - sa, - 0, - 1); - } else { - sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, - if_nametoindex(ifa->ifa_name), - ifa->ifa_name); - } - freeifaddrs(ifas); -} - -static void * -recv_function_route(void *arg) -{ - ssize_t ret; - struct ifa_msghdr *ifa; - char rt_buffer[1024]; - struct sockaddr *sa, *rti_info[RTAX_MAX]; - - sctp_userspace_set_threadname("SCTP addr mon"); - - while (1) { - memset(rt_buffer, 0, sizeof(rt_buffer)); - ret = recv(SCTP_BASE_VAR(userspace_route), rt_buffer, sizeof(rt_buffer), 0); - - if (ret > 0) { - ifa = (struct ifa_msghdr *) rt_buffer; - if (ifa->ifam_type != RTM_DELADDR && ifa->ifam_type != RTM_NEWADDR) { - continue; - } - sa = (struct sockaddr *) (ifa + 1); - sctp_get_rtaddrs(ifa->ifam_addrs, sa, rti_info); - switch (ifa->ifam_type) { - case RTM_DELADDR: - case RTM_NEWADDR: - sctp_handle_ifamsg(ifa->ifam_type, ifa->ifam_index, rti_info[RTAX_IFA]); - break; - default: - /* ignore this routing event */ - break; - } - } - if (ret < 0) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } - } - return (NULL); -} -#endif - -#if 0 -/* This does not yet work on Linux */ -static void * -recv_function_route(void *arg) -{ - int len; - char buf[4096]; - struct iovec iov = { buf, sizeof(buf) }; - struct msghdr msg; - struct nlmsghdr *nh; - struct ifaddrmsg *rtmsg; - struct rtattr *rtatp; - struct in_addr *inp; - struct sockaddr_nl sanl; -#ifdef INET - struct sockaddr_in *sa; -#endif -#ifdef INET6 - struct sockaddr_in6 *sa6; -#endif - - for (;;) { - memset(&sanl, 0, sizeof(sanl)); - sanl.nl_family = AF_NETLINK; - sanl.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR; - memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_name = (void *)&sanl; - msg.msg_namelen = sizeof(sanl); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - - len = recvmsg(SCTP_BASE_VAR(userspace_route), &msg, 0); - - if (len < 0) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } - for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len); - nh = NLMSG_NEXT (nh, len)) { - if (nh->nlmsg_type == NLMSG_DONE) - break; - - if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) { - rtmsg = (struct ifaddrmsg *)NLMSG_DATA(nh); - rtatp = (struct rtattr *)IFA_RTA(rtmsg); - if (rtatp->rta_type == IFA_ADDRESS) { - inp = (struct in_addr *)RTA_DATA(rtatp); - switch (rtmsg->ifa_family) { -#ifdef INET - case AF_INET: - sa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); - sa->sin_family = rtmsg->ifa_family; - sa->sin_port = 0; - memcpy(&sa->sin_addr, inp, sizeof(struct in_addr)); - sctp_handle_ifamsg(nh->nlmsg_type, rtmsg->ifa_index, (struct sockaddr *)sa); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); - sa6->sin6_family = rtmsg->ifa_family; - sa6->sin6_port = 0; - memcpy(&sa6->sin6_addr, inp, sizeof(struct in6_addr)); - sctp_handle_ifamsg(nh->nlmsg_type, rtmsg->ifa_index, (struct sockaddr *)sa6); - break; -#endif - default: - SCTPDBG(SCTP_DEBUG_USR, "Address family %d not supported.\n", rtmsg->ifa_family); - break; - } - } - } - } - } - return (NULL); -} -#endif - -#ifdef INET -static void * -recv_function_raw(void *arg) -{ - struct mbuf **recvmbuf; - struct ip *iphdr; - struct sctphdr *sh; - uint16_t port; - int offset, ecn = 0; - int compute_crc = 1; - struct sctp_chunkhdr *ch; - struct sockaddr_in src, dst; -#if !defined(_WIN32) - ssize_t res; - unsigned int ncounter; - struct msghdr msg; - struct iovec recv_iovec[MAXLEN_MBUF_CHAIN]; -#else - WSABUF recv_iovec[MAXLEN_MBUF_CHAIN]; - int nResult, m_ErrorCode; - DWORD flags; - DWORD ncounter; - struct sockaddr_in from; - int fromlen; -#endif - /*Initially the entire set of mbufs is to be allocated. - to_fill indicates this amount. */ - int to_fill = MAXLEN_MBUF_CHAIN; - /* iovlen is the size of each mbuf in the chain */ - int i, n; - unsigned int iovlen = MCLBYTES; - int want_ext = (iovlen > MLEN)? 1 : 0; - int want_header = 0; - - sctp_userspace_set_threadname("SCTP/IP4 rcv"); - - memset(&src, 0, sizeof(struct sockaddr_in)); - memset(&dst, 0, sizeof(struct sockaddr_in)); - - recvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); - - while (1) { - for (i = 0; i < to_fill; i++) { - /* Not getting the packet header. Tests with chain of one run - as usual without having the packet header. - Have tried both sending and receiving - */ - recvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); -#if !defined(_WIN32) - recv_iovec[i].iov_base = (caddr_t)recvmbuf[i]->m_data; - recv_iovec[i].iov_len = iovlen; -#else - recv_iovec[i].buf = (caddr_t)recvmbuf[i]->m_data; - recv_iovec[i].len = iovlen; -#endif - } - to_fill = 0; -#if defined(_WIN32) - flags = 0; - ncounter = 0; - fromlen = sizeof(struct sockaddr_in); - memset(&from, 0, sizeof(struct sockaddr_in)); - - nResult = WSARecvFrom(SCTP_BASE_VAR(userspace_rawsctp), recv_iovec, MAXLEN_MBUF_CHAIN, &ncounter, &flags, (struct sockaddr *)&from, &fromlen, NULL, NULL); - if (nResult != 0) { - m_ErrorCode = WSAGetLastError(); - if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { - break; - } - continue; - } - n = ncounter; -#else - memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = recv_iovec; - msg.msg_iovlen = MAXLEN_MBUF_CHAIN; - msg.msg_control = NULL; - msg.msg_controllen = 0; - res = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0); - if (res < 0) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } - ncounter = (unsigned int)res; - n = (int)res; -#endif - SCTP_HEADER_LEN(recvmbuf[0]) = n; /* length of total packet */ - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - - if ((unsigned int)n <= iovlen) { - SCTP_BUF_LEN(recvmbuf[0]) = n; - (to_fill)++; - } else { - i = 0; - SCTP_BUF_LEN(recvmbuf[0]) = iovlen; - - ncounter -= min(ncounter, iovlen); - (to_fill)++; - do { - recvmbuf[i]->m_next = recvmbuf[i+1]; - SCTP_BUF_LEN(recvmbuf[i]->m_next) = min(ncounter, iovlen); - i++; - ncounter -= min(ncounter, iovlen); - (to_fill)++; - } while (ncounter > 0); - } - - offset = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (SCTP_BUF_LEN(recvmbuf[0]) < offset) { - if ((recvmbuf[0] = m_pullup(recvmbuf[0], offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - continue; - } - } - iphdr = mtod(recvmbuf[0], struct ip *); - sh = (struct sctphdr *)((caddr_t)iphdr + sizeof(struct ip)); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - - if (iphdr->ip_tos != 0) { - ecn = iphdr->ip_tos & 0x03; - } - - dst.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - dst.sin_addr = iphdr->ip_dst; - dst.sin_port = sh->dest_port; - - src.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - src.sin_len = sizeof(struct sockaddr_in); -#endif - src.sin_addr = iphdr->ip_src; - src.sin_port = sh->src_port; - - /* SCTP does not allow broadcasts or multicasts */ - if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { - m_freem(recvmbuf[0]); - continue; - } - if (SCTP_IS_IT_BROADCAST(dst.sin_addr, recvmbuf[0])) { - m_freem(recvmbuf[0]); - continue; - } - - port = 0; - - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - ((IN4_ISLOOPBACK_ADDRESS(&src.sin_addr) && - IN4_ISLOOPBACK_ADDRESS(&dst.sin_addr)) || - (src.sin_addr.s_addr == dst.sin_addr.s_addr))) { - compute_crc = 0; - SCTP_STAT_INCR(sctps_recvhwcrc); - } else { - SCTP_STAT_INCR(sctps_recvswcrc); - } - SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); - SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); - sctp_common_input_processing(&recvmbuf[0], sizeof(struct ip), offset, n, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - compute_crc, - ecn, - SCTP_DEFAULT_VRFID, port); - if (recvmbuf[0]) { - m_freem(recvmbuf[0]); - } - } - for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { - m_free(recvmbuf[i]); - } - /* free the array itself */ - free(recvmbuf); - SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP4 rcv\n", __func__); - return (NULL); -} -#endif - -#if defined(INET6) -static void * -recv_function_raw6(void *arg) -{ - struct mbuf **recvmbuf6; -#if !defined(_WIN32) - ssize_t res; - unsigned int ncounter; - struct iovec recv_iovec[MAXLEN_MBUF_CHAIN]; - struct msghdr msg; - struct cmsghdr *cmsgptr; - char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; -#else - WSABUF recv_iovec[MAXLEN_MBUF_CHAIN]; - int nResult, m_ErrorCode; - DWORD ncounter = 0; - struct sockaddr_in6 from; - GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; - LPFN_WSARECVMSG WSARecvMsg; - WSACMSGHDR *cmsgptr; - WSAMSG msg; - char ControlBuffer[1024]; -#endif - struct sockaddr_in6 src, dst; - struct sctphdr *sh; - int offset; - struct sctp_chunkhdr *ch; - /*Initially the entire set of mbufs is to be allocated. - to_fill indicates this amount. */ - int to_fill = MAXLEN_MBUF_CHAIN; - /* iovlen is the size of each mbuf in the chain */ - int i, n; - int compute_crc = 1; - unsigned int iovlen = MCLBYTES; - int want_ext = (iovlen > MLEN)? 1 : 0; - int want_header = 0; - - sctp_userspace_set_threadname("SCTP/IP6 rcv"); - - recvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); - - for (;;) { - for (i = 0; i < to_fill; i++) { - /* Not getting the packet header. Tests with chain of one run - as usual without having the packet header. - Have tried both sending and receiving - */ - recvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); -#if !defined(_WIN32) - recv_iovec[i].iov_base = (caddr_t)recvmbuf6[i]->m_data; - recv_iovec[i].iov_len = iovlen; -#else - recv_iovec[i].buf = (caddr_t)recvmbuf6[i]->m_data; - recv_iovec[i].len = iovlen; -#endif - } - to_fill = 0; -#if defined(_WIN32) - ncounter = 0; - memset(&from, 0, sizeof(struct sockaddr_in6)); - nResult = WSAIoctl(SCTP_BASE_VAR(userspace_rawsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER, - &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, - &WSARecvMsg, sizeof WSARecvMsg, - &ncounter, NULL, NULL); - if (nResult == 0) { - msg.name = (void *)&src; - msg.namelen = sizeof(struct sockaddr_in6); - msg.lpBuffers = recv_iovec; - msg.dwBufferCount = MAXLEN_MBUF_CHAIN; - msg.Control.len = sizeof ControlBuffer; - msg.Control.buf = ControlBuffer; - msg.dwFlags = 0; - nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, &ncounter, NULL, NULL); - } - if (nResult != 0) { - m_ErrorCode = WSAGetLastError(); - if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { - break; - } - continue; - } - n = ncounter; -#else - memset(&msg, 0, sizeof(struct msghdr)); - memset(&src, 0, sizeof(struct sockaddr_in6)); - memset(&dst, 0, sizeof(struct sockaddr_in6)); - memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo))); - msg.msg_name = (void *)&src; - msg.msg_namelen = sizeof(struct sockaddr_in6); - msg.msg_iov = recv_iovec; - msg.msg_iovlen = MAXLEN_MBUF_CHAIN; - msg.msg_control = (void *)cmsgbuf; - msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo)); - msg.msg_flags = 0; - res = recvmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, 0); - if (res < 0) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } - ncounter = (unsigned int)res; - n = (int)res; -#endif - SCTP_HEADER_LEN(recvmbuf6[0]) = n; /* length of total packet */ - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - - if ((unsigned int)n <= iovlen) { - SCTP_BUF_LEN(recvmbuf6[0]) = n; - (to_fill)++; - } else { - i = 0; - SCTP_BUF_LEN(recvmbuf6[0]) = iovlen; - - ncounter -= min(ncounter, iovlen); - (to_fill)++; - do { - recvmbuf6[i]->m_next = recvmbuf6[i+1]; - SCTP_BUF_LEN(recvmbuf6[i]->m_next) = min(ncounter, iovlen); - i++; - ncounter -= min(ncounter, iovlen); - (to_fill)++; - } while (ncounter > 0); - } - - for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { - if ((cmsgptr->cmsg_level == IPPROTO_IPV6) && (cmsgptr->cmsg_type == IPV6_PKTINFO)) { - struct in6_pktinfo * info; - - info = (struct in6_pktinfo *)CMSG_DATA(cmsgptr); - memcpy((void *)&dst.sin6_addr, (const void *) &(info->ipi6_addr), sizeof(struct in6_addr)); - break; - } - } - - /* SCTP does not allow broadcasts or multicasts */ - if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) { - m_freem(recvmbuf6[0]); - continue; - } - - offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (SCTP_BUF_LEN(recvmbuf6[0]) < offset) { - if ((recvmbuf6[0] = m_pullup(recvmbuf6[0], offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - continue; - } - } - sh = mtod(recvmbuf6[0], struct sctphdr *); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - - dst.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - dst.sin6_len = sizeof(struct sockaddr_in6); -#endif - dst.sin6_port = sh->dest_port; - - src.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - src.sin6_len = sizeof(struct sockaddr_in6); -#endif - src.sin6_port = sh->src_port; - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) { - compute_crc = 0; - SCTP_STAT_INCR(sctps_recvhwcrc); - } else { - SCTP_STAT_INCR(sctps_recvswcrc); - } - SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); - SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); - sctp_common_input_processing(&recvmbuf6[0], 0, offset, n, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - compute_crc, - 0, - SCTP_DEFAULT_VRFID, 0); - if (recvmbuf6[0]) { - m_freem(recvmbuf6[0]); - } - } - for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { - m_free(recvmbuf6[i]); - } - /* free the array itself */ - free(recvmbuf6); - SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP6 rcv\n", __func__); - return (NULL); -} -#endif - -#ifdef INET -static void * -recv_function_udp(void *arg) -{ - struct mbuf **udprecvmbuf; - /*Initially the entire set of mbufs is to be allocated. - to_fill indicates this amount. */ - int to_fill = MAXLEN_MBUF_CHAIN; - /* iovlen is the size of each mbuf in the chain */ - int i, n, offset; - unsigned int iovlen = MCLBYTES; - int want_ext = (iovlen > MLEN)? 1 : 0; - int want_header = 0; - struct sctphdr *sh; - uint16_t port; - struct sctp_chunkhdr *ch; - struct sockaddr_in src, dst; -#if defined(IP_PKTINFO) - char cmsgbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#else - char cmsgbuf[CMSG_SPACE(sizeof(struct in_addr))]; -#endif - int compute_crc = 1; -#if !defined(_WIN32) - ssize_t res; - unsigned int ncounter; - struct iovec iov[MAXLEN_MBUF_CHAIN]; - struct msghdr msg; - struct cmsghdr *cmsgptr; -#else - GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; - LPFN_WSARECVMSG WSARecvMsg; - char ControlBuffer[1024]; - WSABUF iov[MAXLEN_MBUF_CHAIN]; - WSAMSG msg; - int nResult, m_ErrorCode; - WSACMSGHDR *cmsgptr; - DWORD ncounter; -#endif - - sctp_userspace_set_threadname("SCTP/UDP/IP4 rcv"); - - udprecvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); - - while (1) { - for (i = 0; i < to_fill; i++) { - /* Not getting the packet header. Tests with chain of one run - as usual without having the packet header. - Have tried both sending and receiving - */ - udprecvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); -#if !defined(_WIN32) - iov[i].iov_base = (caddr_t)udprecvmbuf[i]->m_data; - iov[i].iov_len = iovlen; -#else - iov[i].buf = (caddr_t)udprecvmbuf[i]->m_data; - iov[i].len = iovlen; -#endif - } - to_fill = 0; -#if !defined(_WIN32) - memset(&msg, 0, sizeof(struct msghdr)); -#else - memset(&msg, 0, sizeof(WSAMSG)); -#endif - memset(&src, 0, sizeof(struct sockaddr_in)); - memset(&dst, 0, sizeof(struct sockaddr_in)); - memset(cmsgbuf, 0, sizeof(cmsgbuf)); - -#if !defined(_WIN32) - msg.msg_name = (void *)&src; - msg.msg_namelen = sizeof(struct sockaddr_in); - msg.msg_iov = iov; - msg.msg_iovlen = MAXLEN_MBUF_CHAIN; - msg.msg_control = (void *)cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - msg.msg_flags = 0; - - res = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0); - if (res < 0) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } - ncounter = (unsigned int)res; - n = (int)res; -#else - nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp), SIO_GET_EXTENSION_FUNCTION_POINTER, - &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, - &WSARecvMsg, sizeof WSARecvMsg, - &ncounter, NULL, NULL); - if (nResult == 0) { - msg.name = (void *)&src; - msg.namelen = sizeof(struct sockaddr_in); - msg.lpBuffers = iov; - msg.dwBufferCount = MAXLEN_MBUF_CHAIN; - msg.Control.len = sizeof ControlBuffer; - msg.Control.buf = ControlBuffer; - msg.dwFlags = 0; - nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, &ncounter, NULL, NULL); - } - if (nResult != 0) { - m_ErrorCode = WSAGetLastError(); - if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { - break; - } - continue; - } - n = ncounter; -#endif - SCTP_HEADER_LEN(udprecvmbuf[0]) = n; /* length of total packet */ - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - - if ((unsigned int)n <= iovlen) { - SCTP_BUF_LEN(udprecvmbuf[0]) = n; - (to_fill)++; - } else { - i = 0; - SCTP_BUF_LEN(udprecvmbuf[0]) = iovlen; - - ncounter -= min(ncounter, iovlen); - (to_fill)++; - do { - udprecvmbuf[i]->m_next = udprecvmbuf[i+1]; - SCTP_BUF_LEN(udprecvmbuf[i]->m_next) = min(ncounter, iovlen); - i++; - ncounter -= min(ncounter, iovlen); - (to_fill)++; - } while (ncounter > 0); - } - - for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { -#if defined(IP_PKTINFO) - if ((cmsgptr->cmsg_level == IPPROTO_IP) && (cmsgptr->cmsg_type == IP_PKTINFO)) { - struct in_pktinfo *info; - - dst.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - info = (struct in_pktinfo *)CMSG_DATA(cmsgptr); - memcpy((void *)&dst.sin_addr, (const void *)&(info->ipi_addr), sizeof(struct in_addr)); - break; - } -#else - if ((cmsgptr->cmsg_level == IPPROTO_IP) && (cmsgptr->cmsg_type == IP_RECVDSTADDR)) { - struct in_addr *addr; - - dst.sin_family = AF_INET; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - addr = (struct in_addr *)CMSG_DATA(cmsgptr); - memcpy((void *)&dst.sin_addr, (const void *)addr, sizeof(struct in_addr)); - break; - } -#endif - } - - /* SCTP does not allow broadcasts or multicasts */ - if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { - m_freem(udprecvmbuf[0]); - continue; - } - if (SCTP_IS_IT_BROADCAST(dst.sin_addr, udprecvmbuf[0])) { - m_freem(udprecvmbuf[0]); - continue; - } - - offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (SCTP_BUF_LEN(udprecvmbuf[0]) < offset) { - if ((udprecvmbuf[0] = m_pullup(udprecvmbuf[0], offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - continue; - } - } - sh = mtod(udprecvmbuf[0], struct sctphdr *); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - - port = src.sin_port; - src.sin_port = sh->src_port; - dst.sin_port = sh->dest_port; - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (src.sin_addr.s_addr == dst.sin_addr.s_addr)) { - compute_crc = 0; - SCTP_STAT_INCR(sctps_recvhwcrc); - } else { - SCTP_STAT_INCR(sctps_recvswcrc); - } - SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); - SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); - sctp_common_input_processing(&udprecvmbuf[0], 0, offset, n, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - compute_crc, - 0, - SCTP_DEFAULT_VRFID, port); - if (udprecvmbuf[0]) { - m_freem(udprecvmbuf[0]); - } - } - for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { - m_free(udprecvmbuf[i]); - } - /* free the array itself */ - free(udprecvmbuf); - SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP4 rcv\n", __func__); - return (NULL); -} -#endif - -#if defined(INET6) -static void * -recv_function_udp6(void *arg) -{ - struct mbuf **udprecvmbuf6; - /*Initially the entire set of mbufs is to be allocated. - to_fill indicates this amount. */ - int to_fill = MAXLEN_MBUF_CHAIN; - /* iovlen is the size of each mbuf in the chain */ - int i, n, offset; - unsigned int iovlen = MCLBYTES; - int want_ext = (iovlen > MLEN)? 1 : 0; - int want_header = 0; - struct sockaddr_in6 src, dst; - struct sctphdr *sh; - uint16_t port; - struct sctp_chunkhdr *ch; - char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; - int compute_crc = 1; -#if !defined(_WIN32) - struct iovec iov[MAXLEN_MBUF_CHAIN]; - struct msghdr msg; - struct cmsghdr *cmsgptr; - ssize_t res; - unsigned int ncounter; -#else - GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; - LPFN_WSARECVMSG WSARecvMsg; - char ControlBuffer[1024]; - WSABUF iov[MAXLEN_MBUF_CHAIN]; - WSAMSG msg; - int nResult, m_ErrorCode; - WSACMSGHDR *cmsgptr; - DWORD ncounter; -#endif - - sctp_userspace_set_threadname("SCTP/UDP/IP6 rcv"); - - udprecvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); - while (1) { - for (i = 0; i < to_fill; i++) { - /* Not getting the packet header. Tests with chain of one run - as usual without having the packet header. - Have tried both sending and receiving - */ - udprecvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); -#if !defined(_WIN32) - iov[i].iov_base = (caddr_t)udprecvmbuf6[i]->m_data; - iov[i].iov_len = iovlen; -#else - iov[i].buf = (caddr_t)udprecvmbuf6[i]->m_data; - iov[i].len = iovlen; -#endif - } - to_fill = 0; - -#if !defined(_WIN32) - memset(&msg, 0, sizeof(struct msghdr)); -#else - memset(&msg, 0, sizeof(WSAMSG)); -#endif - memset(&src, 0, sizeof(struct sockaddr_in6)); - memset(&dst, 0, sizeof(struct sockaddr_in6)); - memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo))); - -#if !defined(_WIN32) - msg.msg_name = (void *)&src; - msg.msg_namelen = sizeof(struct sockaddr_in6); - msg.msg_iov = iov; - msg.msg_iovlen = MAXLEN_MBUF_CHAIN; - msg.msg_control = (void *)cmsgbuf; - msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo)); - msg.msg_flags = 0; - - res = recvmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, 0); - if (res < 0) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } - ncounter = (unsigned int)res; - n = (int)res; -#else - nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER, - &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, - &WSARecvMsg, sizeof WSARecvMsg, - &ncounter, NULL, NULL); - if (nResult == SOCKET_ERROR) { - m_ErrorCode = WSAGetLastError(); - WSARecvMsg = NULL; - } - if (nResult == 0) { - msg.name = (void *)&src; - msg.namelen = sizeof(struct sockaddr_in6); - msg.lpBuffers = iov; - msg.dwBufferCount = MAXLEN_MBUF_CHAIN; - msg.Control.len = sizeof ControlBuffer; - msg.Control.buf = ControlBuffer; - msg.dwFlags = 0; - nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, &ncounter, NULL, NULL); - } - if (nResult != 0) { - m_ErrorCode = WSAGetLastError(); - if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { - break; - } - continue; - } - n = ncounter; -#endif - SCTP_HEADER_LEN(udprecvmbuf6[0]) = n; /* length of total packet */ - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - - if ((unsigned int)n <= iovlen) { - SCTP_BUF_LEN(udprecvmbuf6[0]) = n; - (to_fill)++; - } else { - i = 0; - SCTP_BUF_LEN(udprecvmbuf6[0]) = iovlen; - - ncounter -= min(ncounter, iovlen); - (to_fill)++; - do { - udprecvmbuf6[i]->m_next = udprecvmbuf6[i+1]; - SCTP_BUF_LEN(udprecvmbuf6[i]->m_next) = min(ncounter, iovlen); - i++; - ncounter -= min(ncounter, iovlen); - (to_fill)++; - } while (ncounter > 0); - } - - for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { - if ((cmsgptr->cmsg_level == IPPROTO_IPV6) && (cmsgptr->cmsg_type == IPV6_PKTINFO)) { - struct in6_pktinfo *info; - - dst.sin6_family = AF_INET6; -#ifdef HAVE_SIN6_LEN - dst.sin6_len = sizeof(struct sockaddr_in6); -#endif - info = (struct in6_pktinfo *)CMSG_DATA(cmsgptr); - /*dst.sin6_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));*/ - memcpy((void *)&dst.sin6_addr, (const void *)&(info->ipi6_addr), sizeof(struct in6_addr)); - } - } - - /* SCTP does not allow broadcasts or multicasts */ - if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) { - m_freem(udprecvmbuf6[0]); - continue; - } - - offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (SCTP_BUF_LEN(udprecvmbuf6[0]) < offset) { - if ((udprecvmbuf6[0] = m_pullup(udprecvmbuf6[0], offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - continue; - } - } - sh = mtod(udprecvmbuf6[0], struct sctphdr *); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - - port = src.sin6_port; - src.sin6_port = sh->src_port; - dst.sin6_port = sh->dest_port; - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) { - compute_crc = 0; - SCTP_STAT_INCR(sctps_recvhwcrc); - } else { - SCTP_STAT_INCR(sctps_recvswcrc); - } - SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); - SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", (int)sizeof(struct sctphdr)); - sctp_common_input_processing(&udprecvmbuf6[0], 0, offset, n, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - compute_crc, - 0, - SCTP_DEFAULT_VRFID, port); - if (udprecvmbuf6[0]) { - m_freem(udprecvmbuf6[0]); - } - } - for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { - m_free(udprecvmbuf6[i]); - } - /* free the array itself */ - free(udprecvmbuf6); - SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP6 rcv\n", __func__); - return (NULL); -} -#endif - -#if defined(_WIN32) -static void -setReceiveBufferSize(SOCKET sfd, int new_size) -#else -static void -setReceiveBufferSize(int sfd, int new_size) -#endif -{ - int ch = new_size; - - if (setsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)&ch, sizeof(ch)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", errno); -#endif - } - return; -} - -#if defined(_WIN32) -static void -setSendBufferSize(SOCKET sfd, int new_size) -#else -static void -setSendBufferSize(int sfd, int new_size) -#endif -{ - int ch = new_size; - - if (setsockopt (sfd, SOL_SOCKET, SO_SNDBUF, (void*)&ch, sizeof(ch)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", errno); -#endif - } - return; -} - -#define SOCKET_TIMEOUT 100 /* in ms */ -void -recv_thread_init(void) -{ -#if defined(INET) - struct sockaddr_in addr_ipv4; - const int hdrincl = 1; -#endif -#if defined(INET6) - struct sockaddr_in6 addr_ipv6; -#endif -#if defined(INET) || defined(INET6) - const int on = 1; -#endif -#if !defined(_WIN32) - struct timeval timeout; - - memset(&timeout, 0, sizeof(struct timeval)); - timeout.tv_sec = (SOCKET_TIMEOUT / 1000); - timeout.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000; -#else - unsigned int timeout = SOCKET_TIMEOUT; /* Timeout in milliseconds */ -#endif -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) - if (SCTP_BASE_VAR(userspace_route) == -1) { - if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { - SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d).\n", errno); - } -#if 0 - struct sockaddr_nl sanl; - - if ((SCTP_BASE_VAR(userspace_route) = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { - SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d.\n", errno); - } - memset(&sanl, 0, sizeof(sanl)); - sanl.nl_family = AF_NETLINK; - sanl.nl_groups = 0; -#ifdef INET - sanl.nl_groups |= RTMGRP_IPV4_IFADDR; -#endif -#ifdef INET6 - sanl.nl_groups |= RTMGRP_IPV6_IFADDR; -#endif - if (bind(SCTP_BASE_VAR(userspace_route), (struct sockaddr *) &sanl, sizeof(sanl)) < 0) { - SCTPDBG(SCTP_DEBUG_USR, "Can't bind routing socket (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_route)); - SCTP_BASE_VAR(userspace_route) = -1; - } -#endif - if (SCTP_BASE_VAR(userspace_route) != -1) { - if (setsockopt(SCTP_BASE_VAR(userspace_route), SOL_SOCKET, SO_RCVTIMEO,(const void*)&timeout, sizeof(struct timeval)) < 0) { - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on routing socket (errno = %d).\n", errno); -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_route)); -#else - close(SCTP_BASE_VAR(userspace_route)); -#endif - SCTP_BASE_VAR(userspace_route) = -1; - } - } - } -#endif -#if defined(INET) - if (SCTP_BASE_VAR(userspace_rawsctp) == -1) { - if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) == -1) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", errno); -#endif - } else { - /* complete setting up the raw SCTP socket */ - if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), IPPROTO_IP, IP_HDRINCL,(const void*)&hdrincl, sizeof(int)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp)); -#endif - SCTP_BASE_VAR(userspace_rawsctp) = -1; - } else if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp)); -#endif - SCTP_BASE_VAR(userspace_rawsctp) = -1; - } else { - memset((void *)&addr_ipv4, 0, sizeof(struct sockaddr_in)); -#ifdef HAVE_SIN_LEN - addr_ipv4.sin_len = sizeof(struct sockaddr_in); -#endif - addr_ipv4.sin_family = AF_INET; - addr_ipv4.sin_port = htons(0); - addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(SCTP_BASE_VAR(userspace_rawsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp)); -#endif - SCTP_BASE_VAR(userspace_rawsctp) = -1; - } else { - setReceiveBufferSize(SCTP_BASE_VAR(userspace_rawsctp), SB_RAW); /* 128K */ - setSendBufferSize(SCTP_BASE_VAR(userspace_rawsctp), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ - } - } - } - } - if ((SCTP_BASE_VAR(userspace_udpsctp) == -1) && (SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) != 0)) { - if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); -#endif - } else { -#if defined(IP_PKTINFO) - if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) { -#else - if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_RECVDSTADDR, (const void *)&on, (int)sizeof(int)) < 0) { -#endif -#if defined(_WIN32) -#if defined(IP_PKTINFO) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_RECVDSTADDR on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); -#endif - closesocket(SCTP_BASE_VAR(userspace_udpsctp)); -#else -#if defined(IP_PKTINFO) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_RECVDSTADDR on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); -#endif - close(SCTP_BASE_VAR(userspace_udpsctp)); -#endif - SCTP_BASE_VAR(userspace_udpsctp) = -1; - } else if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_udpsctp)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_udpsctp)); -#endif - SCTP_BASE_VAR(userspace_udpsctp) = -1; - } else { - memset((void *)&addr_ipv4, 0, sizeof(struct sockaddr_in)); -#ifdef HAVE_SIN_LEN - addr_ipv4.sin_len = sizeof(struct sockaddr_in); -#endif - addr_ipv4.sin_family = AF_INET; - addr_ipv4.sin_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(SCTP_BASE_VAR(userspace_udpsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_udpsctp)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_udpsctp)); -#endif - SCTP_BASE_VAR(userspace_udpsctp) = -1; - } else { - setReceiveBufferSize(SCTP_BASE_VAR(userspace_udpsctp), SB_RAW); /* 128K */ - setSendBufferSize(SCTP_BASE_VAR(userspace_udpsctp), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ - } - } - } - } -#endif -#if defined(INET6) - if (SCTP_BASE_VAR(userspace_rawsctp6) == -1) { - if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) == -1) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", errno); -#endif - } else { - /* complete setting up the raw SCTP socket */ -#if defined(IPV6_RECVPKTINFO) - if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, sizeof(on)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp6)); -#endif - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - } else { -#else - if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_PKTINFO,(const void*)&on, sizeof(on)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp6)); -#endif - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - } else { -#endif - if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&on, (socklen_t)sizeof(on)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", errno); -#endif - } - if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp6)); -#endif - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - } else { - memset((void *)&addr_ipv6, 0, sizeof(struct sockaddr_in6)); -#ifdef HAVE_SIN6_LEN - addr_ipv6.sin6_len = sizeof(struct sockaddr_in6); -#endif - addr_ipv6.sin6_family = AF_INET6; - addr_ipv6.sin6_port = htons(0); - addr_ipv6.sin6_addr = in6addr_any; - if (bind(SCTP_BASE_VAR(userspace_rawsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_rawsctp6)); -#endif - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - } else { - setReceiveBufferSize(SCTP_BASE_VAR(userspace_rawsctp6), SB_RAW); /* 128K */ - setSendBufferSize(SCTP_BASE_VAR(userspace_rawsctp6), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ - } - } - } - } - } - if ((SCTP_BASE_VAR(userspace_udpsctp6) == -1) && (SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) != 0)) { - if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); -#endif - } -#if defined(IPV6_RECVPKTINFO) - if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, (int)sizeof(int)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_udpsctp6)); -#endif - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - } else { -#else - if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_udpsctp6)); -#endif - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - } else { -#endif - if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, (socklen_t)sizeof(on)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); -#endif - } - if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_udpsctp6)); -#endif - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - } else { - memset((void *)&addr_ipv6, 0, sizeof(struct sockaddr_in6)); -#ifdef HAVE_SIN6_LEN - addr_ipv6.sin6_len = sizeof(struct sockaddr_in6); -#endif - addr_ipv6.sin6_family = AF_INET6; - addr_ipv6.sin6_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - addr_ipv6.sin6_addr = in6addr_any; - if (bind(SCTP_BASE_VAR(userspace_udpsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) { -#if defined(_WIN32) - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); - closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); -#else - SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); - close(SCTP_BASE_VAR(userspace_udpsctp6)); -#endif - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - } else { - setReceiveBufferSize(SCTP_BASE_VAR(userspace_udpsctp6), SB_RAW); /* 128K */ - setSendBufferSize(SCTP_BASE_VAR(userspace_udpsctp6), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ - } - } - } - } -#endif -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) -#if defined(INET) || defined(INET6) - if (SCTP_BASE_VAR(userspace_route) != -1) { - int rc; - - if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadroute), &recv_function_route))) { - SCTPDBG(SCTP_DEBUG_USR, "Can't start routing thread (%d).\n", rc); - close(SCTP_BASE_VAR(userspace_route)); - SCTP_BASE_VAR(userspace_route) = -1; - } - } -#endif -#endif -#if defined(INET) - if (SCTP_BASE_VAR(userspace_rawsctp) != -1) { - int rc; - - if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw), &recv_function_raw))) { - SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv4 recv thread (%d).\n", rc); -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_rawsctp)); -#else - close(SCTP_BASE_VAR(userspace_rawsctp)); -#endif - SCTP_BASE_VAR(userspace_rawsctp) = -1; - } - } - if (SCTP_BASE_VAR(userspace_udpsctp) != -1) { - int rc; - - if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp), &recv_function_udp))) { - SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv4 recv thread (%d).\n", rc); -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_udpsctp)); -#else - close(SCTP_BASE_VAR(userspace_udpsctp)); -#endif - SCTP_BASE_VAR(userspace_udpsctp) = -1; - } - } -#endif -#if defined(INET6) - if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) { - int rc; - - if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw6), &recv_function_raw6))) { - SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv6 recv thread (%d).\n", rc); -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); -#else - close(SCTP_BASE_VAR(userspace_rawsctp6)); -#endif - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - } - } - if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) { - int rc; - - if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp6), &recv_function_udp6))) { - SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv6 recv thread (%d).\n", rc); -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); -#else - close(SCTP_BASE_VAR(userspace_udpsctp6)); -#endif - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - } - } -#endif -} - -void -recv_thread_destroy(void) -{ -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) -#if defined(INET) || defined(INET6) - if (SCTP_BASE_VAR(userspace_route) != -1) { - close(SCTP_BASE_VAR(userspace_route)); - pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL); - } -#endif -#endif -#if defined(INET) - if (SCTP_BASE_VAR(userspace_rawsctp) != -1) { -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_rawsctp)); - SCTP_BASE_VAR(userspace_rawsctp) = -1; - WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE); - CloseHandle(SCTP_BASE_VAR(recvthreadraw)); -#else - close(SCTP_BASE_VAR(userspace_rawsctp)); - SCTP_BASE_VAR(userspace_rawsctp) = -1; - pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL); -#endif - } - if (SCTP_BASE_VAR(userspace_udpsctp) != -1) { -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_udpsctp)); - SCTP_BASE_VAR(userspace_udpsctp) = -1; - WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE); - CloseHandle(SCTP_BASE_VAR(recvthreadudp)); -#else - close(SCTP_BASE_VAR(userspace_udpsctp)); - SCTP_BASE_VAR(userspace_udpsctp) = -1; - pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL); -#endif - } -#endif -#if defined(INET6) - if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) { -#if defined(_WIN32) - closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE); - CloseHandle(SCTP_BASE_VAR(recvthreadraw6)); -#else - close(SCTP_BASE_VAR(userspace_rawsctp6)); - SCTP_BASE_VAR(userspace_rawsctp6) = -1; - pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL); -#endif - } - if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) { -#if defined(_WIN32) - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); - WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE); - CloseHandle(SCTP_BASE_VAR(recvthreadudp6)); -#else - close(SCTP_BASE_VAR(userspace_udpsctp6)); - SCTP_BASE_VAR(userspace_udpsctp6) = -1; - pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL); -#endif - } -#endif -} -#else -int foo; -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.h deleted file mode 100644 index 61cdf172..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_recv_thread.h +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * Copyright (c) 2012 Michael Tuexen - * Copyright (c) 2012 Irene Ruengeler - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USER_RECV_THREAD_H_ -#define _USER_RECV_THREAD_H_ - -void recv_thread_init(void); -void recv_thread_destroy(void); - -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_route.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_route.h deleted file mode 100644 index 4abf2eac..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_route.h +++ /dev/null @@ -1,130 +0,0 @@ -/*- - * Copyright (c) 1980, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _USER_ROUTE_H_ -#define _USER_ROUTE_H_ - -/* - * Kernel resident routing tables. - * - * The routing tables are initialized when interface addresses - * are set by making entries for all directly connected interfaces. - */ - -/* - * A route consists of a destination address and a reference - * to a routing entry. These are often held by protocols - * in their control blocks, e.g. inpcb. - */ - -struct sctp_route { - struct sctp_rtentry *ro_rt; - struct sockaddr ro_dst; -}; - -/* - * These numbers are used by reliable protocols for determining - * retransmission behavior and are included in the routing structure. - */ -struct sctp_rt_metrics_lite { - uint32_t rmx_mtu; /* MTU for this path */ -#if 0 - u_long rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_pksent; /* packets sent using this route */ -#endif -}; - -/* - * We distinguish between routes to hosts and routes to networks, - * preferring the former if available. For each route we infer - * the interface to use from the gateway address supplied when - * the route was entered. Routes that forward packets through - * gateways are marked so that the output routines know to address the - * gateway rather than the ultimate destination. - */ -struct sctp_rtentry { -#if 0 - struct radix_node rt_nodes[2]; /* tree glue, and other values */ - /* - * XXX struct rtentry must begin with a struct radix_node (or two!) - * because the code does some casts of a 'struct radix_node *' - * to a 'struct rtentry *' - */ -#define rt_key(r) (*((struct sockaddr **)(&(r)->rt_nodes->rn_key))) -#define rt_mask(r) (*((struct sockaddr **)(&(r)->rt_nodes->rn_mask))) - struct sockaddr *rt_gateway; /* value */ - u_long rt_flags; /* up/down?, host/net */ -#endif - struct ifnet *rt_ifp; /* the answer: interface to use */ - struct ifaddr *rt_ifa; /* the answer: interface address to use */ - struct sctp_rt_metrics_lite rt_rmx; /* metrics used by rx'ing protocols */ - long rt_refcnt; /* # held references */ -#if 0 - struct sockaddr *rt_genmask; /* for generation of cloned routes */ - caddr_t rt_llinfo; /* pointer to link level info cache */ - struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ - struct rtentry *rt_parent; /* cloning parent of this route */ -#endif - struct mtx rt_mtx; /* mutex for routing entry */ -}; - -#define RT_LOCK_INIT(_rt) mtx_init(&(_rt)->rt_mtx, "rtentry", NULL, MTX_DEF | MTX_DUPOK) -#define RT_LOCK(_rt) mtx_lock(&(_rt)->rt_mtx) -#define RT_UNLOCK(_rt) mtx_unlock(&(_rt)->rt_mtx) -#define RT_LOCK_DESTROY(_rt) mtx_destroy(&(_rt)->rt_mtx) -#define RT_LOCK_ASSERT(_rt) mtx_assert(&(_rt)->rt_mtx, MA_OWNED) - -#define RT_ADDREF(_rt) do { \ - RT_LOCK_ASSERT(_rt); \ - KASSERT((_rt)->rt_refcnt >= 0, \ - ("negative refcnt %ld", (_rt)->rt_refcnt)); \ - (_rt)->rt_refcnt++; \ -} while (0) -#define RT_REMREF(_rt) do { \ - RT_LOCK_ASSERT(_rt); \ - KASSERT((_rt)->rt_refcnt > 0, \ - ("bogus refcnt %ld", (_rt)->rt_refcnt)); \ - (_rt)->rt_refcnt--; \ -} while (0) -#define RTFREE_LOCKED(_rt) do { \ - if ((_rt)->rt_refcnt <= 1) { \ - rtfree(_rt); \ - } else { \ - RT_REMREF(_rt); \ - RT_UNLOCK(_rt); \ - } \ - /* guard against invalid refs */ \ - _rt = NULL; \ - } while (0) -#define RTFREE(_rt) do { \ - RT_LOCK(_rt); \ - RTFREE_LOCKED(_rt); \ -} while (0) -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socket.c b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socket.c deleted file mode 100644 index 66583904..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socket.c +++ /dev/null @@ -1,3571 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. - * Copyright (c) 2004 The FreeBSD Foundation - * Copyright (c) 2004-2008 Robert N. M. Watson - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef INET6 -#include -#endif -#if defined(__FreeBSD__) -#include -#endif -#if defined(__linux__) -#define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */ -#endif -#if !defined(_WIN32) -#if defined INET || defined INET6 -#include -#endif -#include -#else -#include -#endif -userland_mutex_t accept_mtx; -userland_cond_t accept_cond; -#ifdef _WIN32 -#include -#include -#endif - -MALLOC_DEFINE(M_PCB, "sctp_pcb", "sctp pcb"); -MALLOC_DEFINE(M_SONAME, "sctp_soname", "sctp soname"); -#define MAXLEN_MBUF_CHAIN 32 - -/* Prototypes */ -extern int sctp_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, - struct mbuf *top, struct mbuf *control, int flags, - /* proc is a dummy in __Userspace__ and will not be passed to sctp_lower_sosend */ - struct proc *p); - -extern int sctp_attach(struct socket *so, int proto, uint32_t vrf_id); -extern int sctpconn_attach(struct socket *so, int proto, uint32_t vrf_id); - -static void init_sync(void) { -#if defined(_WIN32) -#if defined(INET) || defined(INET6) - WSADATA wsaData; - - if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { - SCTP_PRINTF("WSAStartup failed\n"); - exit (-1); - } -#endif - InitializeConditionVariable(&accept_cond); - InitializeCriticalSection(&accept_mtx); -#else - pthread_mutexattr_t mutex_attr; - - pthread_mutexattr_init(&mutex_attr); -#ifdef INVARIANTS - pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK); -#endif - pthread_mutex_init(&accept_mtx, &mutex_attr); - pthread_mutexattr_destroy(&mutex_attr); - pthread_cond_init(&accept_cond, NULL); -#endif -} - -void -usrsctp_init(uint16_t port, - int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), - void (*debug_printf)(const char *format, ...)) -{ - init_sync(); - sctp_init(port, conn_output, debug_printf, 1); -} - - -void -usrsctp_init_nothreads(uint16_t port, - int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), - void (*debug_printf)(const char *format, ...)) -{ - init_sync(); - sctp_init(port, conn_output, debug_printf, 0); -} - - -/* Taken from usr/src/sys/kern/uipc_sockbuf.c and modified for __Userspace__*/ -/* - * Socantsendmore indicates that no more data will be sent on the socket; it - * would normally be applied to a socket when the user informs the system - * that no more data is to be sent, by the protocol code (in case - * PRU_SHUTDOWN). Socantrcvmore indicates that no more data will be - * received, and will normally be applied to the socket by a protocol when it - * detects that the peer will send no more data. Data queued for reading in - * the socket may yet be read. - */ - -void socantrcvmore_locked(struct socket *so) -{ - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - so->so_rcv.sb_state |= SBS_CANTRCVMORE; - sorwakeup_locked(so); -} - -void socantrcvmore(struct socket *so) -{ - SOCKBUF_LOCK(&so->so_rcv); - socantrcvmore_locked(so); -} - -void -socantsendmore_locked(struct socket *so) -{ - SOCKBUF_LOCK_ASSERT(&so->so_snd); - so->so_snd.sb_state |= SBS_CANTSENDMORE; - sowwakeup_locked(so); -} - -void -socantsendmore(struct socket *so) -{ - SOCKBUF_LOCK(&so->so_snd); - socantsendmore_locked(so); -} - - - -/* Taken from usr/src/sys/kern/uipc_sockbuf.c and called within sctp_lower_sosend. - */ -int -sbwait(struct sockbuf *sb) -{ - SOCKBUF_LOCK_ASSERT(sb); - - sb->sb_flags |= SB_WAIT; -#if defined(_WIN32) - if (SleepConditionVariableCS(&(sb->sb_cond), &(sb->sb_mtx), INFINITE)) - return (0); - else - return (-1); -#else - return (pthread_cond_wait(&(sb->sb_cond), &(sb->sb_mtx))); -#endif -} - - - - -/* Taken from /src/sys/kern/uipc_socket.c - * and modified for __Userspace__ - */ -static struct socket * -soalloc(void) -{ - struct socket *so; - - /* - * soalloc() sets of socket layer state for a socket, - * called only by socreate() and sonewconn(). - * - * sodealloc() tears down socket layer state for a socket, - * called only by sofree() and sonewconn(). - * __Userspace__ TODO : Make sure so is properly deallocated - * when tearing down the connection. - */ - - so = (struct socket *)malloc(sizeof(struct socket)); - - if (so == NULL) { - return (NULL); - } - memset(so, 0, sizeof(struct socket)); - - /* __Userspace__ Initializing the socket locks here */ - SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd"); - SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv"); - SOCKBUF_COND_INIT(&so->so_snd); - SOCKBUF_COND_INIT(&so->so_rcv); - SOCK_COND_INIT(so); /* timeo_cond */ - - /* __Userspace__ Any ref counting required here? Will we have any use for aiojobq? - What about gencnt and numopensockets?*/ - TAILQ_INIT(&so->so_aiojobq); - return (so); -} - -static void -sodealloc(struct socket *so) -{ - - KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count)); - KASSERT(so->so_pcb == NULL, ("sodealloc(): so_pcb != NULL")); - - SOCKBUF_COND_DESTROY(&so->so_snd); - SOCKBUF_COND_DESTROY(&so->so_rcv); - - SOCK_COND_DESTROY(so); - - SOCKBUF_LOCK_DESTROY(&so->so_snd); - SOCKBUF_LOCK_DESTROY(&so->so_rcv); - - free(so); -} - -/* Taken from /src/sys/kern/uipc_socket.c - * and modified for __Userspace__ - */ -void -sofree(struct socket *so) -{ - struct socket *head; - - ACCEPT_LOCK_ASSERT(); - SOCK_LOCK_ASSERT(so); - /* SS_NOFDREF unset in accept call. this condition seems irrelevant - * for __Userspace__... - */ - if (so->so_count != 0 || - (so->so_state & SS_PROTOREF) || (so->so_qstate & SQ_COMP)) { - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - return; - } - head = so->so_head; - if (head != NULL) { - KASSERT((so->so_qstate & SQ_COMP) != 0 || - (so->so_qstate & SQ_INCOMP) != 0, - ("sofree: so_head != NULL, but neither SQ_COMP nor " - "SQ_INCOMP")); - KASSERT((so->so_qstate & SQ_COMP) == 0 || - (so->so_qstate & SQ_INCOMP) == 0, - ("sofree: so->so_qstate is SQ_COMP and also SQ_INCOMP")); - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - so->so_qstate &= ~SQ_INCOMP; - so->so_head = NULL; - } - KASSERT((so->so_qstate & SQ_COMP) == 0 && - (so->so_qstate & SQ_INCOMP) == 0, - ("sofree: so_head == NULL, but still SQ_COMP(%d) or SQ_INCOMP(%d)", - so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP)); - if (so->so_options & SCTP_SO_ACCEPTCONN) { - KASSERT((TAILQ_EMPTY(&so->so_comp)), ("sofree: so_comp populated")); - KASSERT((TAILQ_EMPTY(&so->so_incomp)), ("sofree: so_comp populated")); - } - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - sctp_close(so); /* was... sctp_detach(so); */ - /* - * From this point on, we assume that no other references to this - * socket exist anywhere else in the stack. Therefore, no locks need - * to be acquired or held. - * - * We used to do a lot of socket buffer and socket locking here, as - * well as invoke sorflush() and perform wakeups. The direct call to - * dom_dispose() and sbrelease_internal() are an inlining of what was - * necessary from sorflush(). - * - * Notice that the socket buffer and kqueue state are torn down - * before calling pru_detach. This means that protocols should not - * assume they can perform socket wakeups, etc, in their detach code. - */ - sodealloc(so); -} - - - -/* Taken from /src/sys/kern/uipc_socket.c */ -void -soabort(struct socket *so) -{ - sctp_abort(so); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sofree(so); -} - - -/* Taken from usr/src/sys/kern/uipc_socket.c and called within sctp_connect (sctp_usrreq.c). - * We use sctp_connect for send_one_init_real in ms1. - */ -void -soisconnecting(struct socket *so) -{ - - SOCK_LOCK(so); - so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= SS_ISCONNECTING; - SOCK_UNLOCK(so); -} - -/* Taken from usr/src/sys/kern/uipc_socket.c and called within sctp_disconnect (sctp_usrreq.c). - * TODO Do we use sctp_disconnect? - */ -void -soisdisconnecting(struct socket *so) -{ - - /* - * Note: This code assumes that SOCK_LOCK(so) and - * SOCKBUF_LOCK(&so->so_rcv) are the same. - */ - SOCKBUF_LOCK(&so->so_rcv); - so->so_state &= ~SS_ISCONNECTING; - so->so_state |= SS_ISDISCONNECTING; - so->so_rcv.sb_state |= SBS_CANTRCVMORE; - sorwakeup_locked(so); - SOCKBUF_LOCK(&so->so_snd); - so->so_snd.sb_state |= SBS_CANTSENDMORE; - sowwakeup_locked(so); - wakeup("dummy",so); - /* requires 2 args but this was in orig */ - /* wakeup(&so->so_timeo); */ -} - - -/* Taken from sys/kern/kern_synch.c and - modified for __Userspace__ -*/ - -/* - * Make all threads sleeping on the specified identifier runnable. - * Associating wakeup with so_timeo identifier and timeo_cond - * condition variable. TODO. If we use iterator thread then we need to - * modify wakeup so it can distinguish between iterator identifier and - * timeo identifier. - */ -void -wakeup(void *ident, struct socket *so) -{ - SOCK_LOCK(so); -#if defined(_WIN32) - WakeAllConditionVariable(&(so)->timeo_cond); -#else - pthread_cond_broadcast(&(so)->timeo_cond); -#endif - SOCK_UNLOCK(so); -} - - -/* - * Make a thread sleeping on the specified identifier runnable. - * May wake more than one thread if a target thread is currently - * swapped out. - */ -void -wakeup_one(void *ident) -{ - /* __Userspace__ Check: We are using accept_cond for wakeup_one. - It seems that wakeup_one is only called within - soisconnected() and sonewconn() with ident &head->so_timeo - head is so->so_head, which is back pointer to listen socket - This seems to indicate that the use of accept_cond is correct - since socket where accepts occur is so_head in all - subsidiary sockets. - */ - ACCEPT_LOCK(); -#if defined(_WIN32) - WakeAllConditionVariable(&accept_cond); -#else - pthread_cond_broadcast(&accept_cond); -#endif - ACCEPT_UNLOCK(); -} - - -/* Called within sctp_process_cookie_[existing/new] */ -void -soisconnected(struct socket *so) -{ - struct socket *head; - - ACCEPT_LOCK(); - SOCK_LOCK(so); - so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); - so->so_state |= SS_ISCONNECTED; - head = so->so_head; - if (head != NULL && (so->so_qstate & SQ_INCOMP)) { - SOCK_UNLOCK(so); - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - so->so_qstate &= ~SQ_INCOMP; - TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); - head->so_qlen++; - so->so_qstate |= SQ_COMP; - ACCEPT_UNLOCK(); - sorwakeup(head); - wakeup_one(&head->so_timeo); - return; - } - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - wakeup(&so->so_timeo, so); - sorwakeup(so); - sowwakeup(so); - -} - -/* called within sctp_handle_cookie_echo */ - -struct socket * -sonewconn(struct socket *head, int connstatus) -{ - struct socket *so; - int over; - - ACCEPT_LOCK(); - over = (head->so_qlen > 3 * head->so_qlimit / 2); - ACCEPT_UNLOCK(); -#ifdef REGRESSION - if (regression_sonewconn_earlytest && over) -#else - if (over) -#endif - return (NULL); - so = soalloc(); - if (so == NULL) - return (NULL); - so->so_head = head; - so->so_type = head->so_type; - so->so_options = head->so_options &~ SCTP_SO_ACCEPTCONN; - so->so_linger = head->so_linger; - so->so_state = head->so_state | SS_NOFDREF; - so->so_dom = head->so_dom; -#ifdef MAC - SOCK_LOCK(head); - mac_create_socket_from_socket(head, so); - SOCK_UNLOCK(head); -#endif - if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) { - sodealloc(so); - return (NULL); - } - switch (head->so_dom) { -#ifdef INET - case AF_INET: - if (sctp_attach(so, IPPROTO_SCTP, SCTP_DEFAULT_VRFID)) { - sodealloc(so); - return (NULL); - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (sctp6_attach(so, IPPROTO_SCTP, SCTP_DEFAULT_VRFID)) { - sodealloc(so); - return (NULL); - } - break; -#endif - case AF_CONN: - if (sctpconn_attach(so, IPPROTO_SCTP, SCTP_DEFAULT_VRFID)) { - sodealloc(so); - return (NULL); - } - break; - default: - sodealloc(so); - return (NULL); - break; - } - so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; - so->so_snd.sb_lowat = head->so_snd.sb_lowat; - so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; - so->so_snd.sb_timeo = head->so_snd.sb_timeo; - so->so_rcv.sb_flags |= head->so_rcv.sb_flags & SB_AUTOSIZE; - so->so_snd.sb_flags |= head->so_snd.sb_flags & SB_AUTOSIZE; - so->so_state |= connstatus; - ACCEPT_LOCK(); - if (connstatus) { - TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); - so->so_qstate |= SQ_COMP; - head->so_qlen++; - } else { - /* - * Keep removing sockets from the head until there's room for - * us to insert on the tail. In pre-locking revisions, this - * was a simple if (), but as we could be racing with other - * threads and soabort() requires dropping locks, we must - * loop waiting for the condition to be true. - */ - while (head->so_incqlen > head->so_qlimit) { - struct socket *sp; - sp = TAILQ_FIRST(&head->so_incomp); - TAILQ_REMOVE(&head->so_incomp, sp, so_list); - head->so_incqlen--; - sp->so_qstate &= ~SQ_INCOMP; - sp->so_head = NULL; - ACCEPT_UNLOCK(); - soabort(sp); - ACCEPT_LOCK(); - } - TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list); - so->so_qstate |= SQ_INCOMP; - head->so_incqlen++; - } - ACCEPT_UNLOCK(); - if (connstatus) { - sorwakeup(head); - wakeup_one(&head->so_timeo); - } - return (so); - -} - - /* - Source: /src/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c - */ -static __inline__ int -copy_to_user(void *dst, void *src, size_t len) { - memcpy(dst, src, len); - return 0; -} - -static __inline__ int -copy_from_user(void *dst, void *src, size_t len) { - memcpy(dst, src, len); - return 0; -} - -/* - References: - src/sys/dev/lmc/if_lmc.h: - src/sys/powerpc/powerpc/copyinout.c - src/sys/sys/systm.h -*/ -# define copyin(u, k, len) copy_from_user(k, u, len) - -/* References: - src/sys/powerpc/powerpc/copyinout.c - src/sys/sys/systm.h -*/ -# define copyout(k, u, len) copy_to_user(u, k, len) - - -/* copyiniov definition copied/modified from src/sys/kern/kern_subr.c */ -int -copyiniov(struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error) -{ - u_int iovlen; - - *iov = NULL; - if (iovcnt > UIO_MAXIOV) - return (error); - iovlen = iovcnt * sizeof (struct iovec); - *iov = malloc(iovlen); /*, M_IOV, M_WAITOK); */ - error = copyin(iovp, *iov, iovlen); - if (error) { - free(*iov); /*, M_IOV); */ - *iov = NULL; - } - return (error); -} - -/* (__Userspace__) version of uiomove */ -int -uiomove(void *cp, int n, struct uio *uio) -{ - struct iovec *iov; - size_t cnt; - int error = 0; - - if ((uio->uio_rw != UIO_READ) && - (uio->uio_rw != UIO_WRITE)) { - return (EINVAL); - } - - while (n > 0 && uio->uio_resid) { - iov = uio->uio_iov; - cnt = iov->iov_len; - if (cnt == 0) { - uio->uio_iov++; - uio->uio_iovcnt--; - continue; - } - if (cnt > (size_t)n) - cnt = n; - - switch (uio->uio_segflg) { - - case UIO_USERSPACE: - if (uio->uio_rw == UIO_READ) - error = copyout(cp, iov->iov_base, cnt); - else - error = copyin(iov->iov_base, cp, cnt); - if (error) - goto out; - break; - - case UIO_SYSSPACE: - if (uio->uio_rw == UIO_READ) - memcpy(iov->iov_base, cp, cnt); - else - memcpy(cp, iov->iov_base, cnt); - break; - } - iov->iov_base = (char *)iov->iov_base + cnt; - iov->iov_len -= cnt; - uio->uio_resid -= cnt; - uio->uio_offset += (off_t)cnt; - cp = (char *)cp + cnt; - n -= (int)cnt; - } -out: - return (error); -} - - -/* Source: src/sys/kern/uipc_syscalls.c */ -int -getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len) -{ - struct sockaddr *sa; - int error; - - if (len > SOCK_MAXADDRLEN) - return (ENAMETOOLONG); - if (len < offsetof(struct sockaddr, sa_data)) - return (EINVAL); - MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK); - error = copyin(uaddr, sa, len); - if (error) { - FREE(sa, M_SONAME); - } else { -#ifdef HAVE_SA_LEN - sa->sa_len = len; -#endif - *namp = sa; - } - return (error); -} - -int -usrsctp_getsockopt(struct socket *so, int level, int option_name, - void *option_value, socklen_t *option_len); - -sctp_assoc_t -usrsctp_getassocid(struct socket *sock, struct sockaddr *sa) -{ - struct sctp_paddrinfo sp; - socklen_t siz; -#ifndef HAVE_SA_LEN - size_t sa_len; -#endif - - /* First get the assoc id */ - siz = sizeof(sp); - memset(&sp, 0, sizeof(sp)); -#ifdef HAVE_SA_LEN - memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); -#else - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sa_len = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa_len = sizeof(struct sockaddr_in6); - break; -#endif - case AF_CONN: - sa_len = sizeof(struct sockaddr_conn); - break; - default: - sa_len = 0; - break; - } - memcpy((caddr_t)&sp.spinfo_address, sa, sa_len); -#endif - if (usrsctp_getsockopt(sock, IPPROTO_SCTP, SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { - /* We depend on the fact that 0 can never be returned */ - return ((sctp_assoc_t) 0); - } - return (sp.spinfo_assoc_id); -} - - -/* Taken from /src/lib/libc/net/sctp_sys_calls.c - * and modified for __Userspace__ - * calling sctp_generic_sendmsg from this function - */ -ssize_t -userspace_sctp_sendmsg(struct socket *so, - const void *data, - size_t len, - struct sockaddr *to, - socklen_t tolen, - uint32_t ppid, - uint32_t flags, - uint16_t stream_no, - uint32_t timetolive, - uint32_t context) -{ - struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo; - struct uio auio; - struct iovec iov[1]; - - memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); - sinfo->sinfo_ppid = ppid; - sinfo->sinfo_flags = flags; - sinfo->sinfo_stream = stream_no; - sinfo->sinfo_timetolive = timetolive; - sinfo->sinfo_context = context; - sinfo->sinfo_assoc_id = 0; - - - /* Perform error checks on destination (to) */ - if (tolen > SOCK_MAXADDRLEN) { - errno = ENAMETOOLONG; - return (-1); - } - if ((tolen > 0) && - ((to == NULL) || (tolen < (socklen_t)sizeof(struct sockaddr)))) { - errno = EINVAL; - return (-1); - } - if (data == NULL) { - errno = EFAULT; - return (-1); - } - /* Adding the following as part of defensive programming, in case the application - does not do it when preparing the destination address.*/ -#ifdef HAVE_SA_LEN - if (to != NULL) { - to->sa_len = tolen; - } -#endif - - iov[0].iov_base = (caddr_t)data; - iov[0].iov_len = len; - - auio.uio_iov = iov; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_offset = 0; /* XXX */ - auio.uio_resid = len; - errno = sctp_lower_sosend(so, to, &auio, NULL, NULL, 0, sinfo); - if (errno == 0) { - return (len - auio.uio_resid); - } else { - return (-1); - } -} - - -ssize_t -usrsctp_sendv(struct socket *so, - const void *data, - size_t len, - struct sockaddr *to, - int addrcnt, - void *info, - socklen_t infolen, - unsigned int infotype, - int flags) -{ - struct sctp_sndrcvinfo sinfo; - struct uio auio; - struct iovec iov[1]; - int use_sinfo; - sctp_assoc_t *assoc_id; - - if (so == NULL) { - errno = EBADF; - return (-1); - } - if (data == NULL) { - errno = EFAULT; - return (-1); - } - memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); - assoc_id = NULL; - use_sinfo = 0; - switch (infotype) { - case SCTP_SENDV_NOINFO: - if ((infolen != 0) || (info != NULL)) { - errno = EINVAL; - return (-1); - } - break; - case SCTP_SENDV_SNDINFO: - if ((info == NULL) || (infolen != sizeof(struct sctp_sndinfo))) { - errno = EINVAL; - return (-1); - } - sinfo.sinfo_stream = ((struct sctp_sndinfo *)info)->snd_sid; - sinfo.sinfo_flags = ((struct sctp_sndinfo *)info)->snd_flags; - sinfo.sinfo_ppid = ((struct sctp_sndinfo *)info)->snd_ppid; - sinfo.sinfo_context = ((struct sctp_sndinfo *)info)->snd_context; - sinfo.sinfo_assoc_id = ((struct sctp_sndinfo *)info)->snd_assoc_id; - assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id); - use_sinfo = 1; - break; - case SCTP_SENDV_PRINFO: - if ((info == NULL) || (infolen != sizeof(struct sctp_prinfo))) { - errno = EINVAL; - return (-1); - } - sinfo.sinfo_stream = 0; - sinfo.sinfo_flags = PR_SCTP_POLICY(((struct sctp_prinfo *)info)->pr_policy); - sinfo.sinfo_timetolive = ((struct sctp_prinfo *)info)->pr_value; - use_sinfo = 1; - break; - case SCTP_SENDV_AUTHINFO: - errno = EINVAL; - return (-1); - case SCTP_SENDV_SPA: - if ((info == NULL) || (infolen != sizeof(struct sctp_sendv_spa))) { - errno = EINVAL; - return (-1); - } - if (((struct sctp_sendv_spa *)info)->sendv_flags & SCTP_SEND_SNDINFO_VALID) { - sinfo.sinfo_stream = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_sid; - sinfo.sinfo_flags = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_flags; - sinfo.sinfo_ppid = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_ppid; - sinfo.sinfo_context = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_context; - sinfo.sinfo_assoc_id = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id; - assoc_id = &(((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id); - } else { - sinfo.sinfo_flags = 0; - sinfo.sinfo_stream = 0; - } - if (((struct sctp_sendv_spa *)info)->sendv_flags & SCTP_SEND_PRINFO_VALID) { - sinfo.sinfo_flags |= PR_SCTP_POLICY(((struct sctp_sendv_spa *)info)->sendv_prinfo.pr_policy); - sinfo.sinfo_timetolive = ((struct sctp_sendv_spa *)info)->sendv_prinfo.pr_value; - } - if (((struct sctp_sendv_spa *)info)->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { - errno = EINVAL; - return (-1); - } - use_sinfo = 1; - break; - default: - errno = EINVAL; - return (-1); - } - - /* Perform error checks on destination (to) */ - if (addrcnt > 1) { - errno = EINVAL; - return (-1); - } - - iov[0].iov_base = (caddr_t)data; - iov[0].iov_len = len; - - auio.uio_iov = iov; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_offset = 0; /* XXX */ - auio.uio_resid = len; - errno = sctp_lower_sosend(so, to, &auio, NULL, NULL, flags, use_sinfo ? &sinfo : NULL); - if (errno == 0) { - if ((to != NULL) && (assoc_id != NULL)) { - *assoc_id = usrsctp_getassocid(so, to); - } - return (len - auio.uio_resid); - } else { - return (-1); - } -} - - -ssize_t -userspace_sctp_sendmbuf(struct socket *so, - struct mbuf* mbufdata, - size_t len, - struct sockaddr *to, - socklen_t tolen, - uint32_t ppid, - uint32_t flags, - uint16_t stream_no, - uint32_t timetolive, - uint32_t context) -{ - - struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo; - /* struct uio auio; - struct iovec iov[1]; */ - int error = 0; - int uflags = 0; - ssize_t retval; - - sinfo->sinfo_ppid = ppid; - sinfo->sinfo_flags = flags; - sinfo->sinfo_stream = stream_no; - sinfo->sinfo_timetolive = timetolive; - sinfo->sinfo_context = context; - sinfo->sinfo_assoc_id = 0; - - /* Perform error checks on destination (to) */ - if (tolen > SOCK_MAXADDRLEN){ - error = (ENAMETOOLONG); - goto sendmsg_return; - } - if (tolen < (socklen_t)offsetof(struct sockaddr, sa_data)){ - error = (EINVAL); - goto sendmsg_return; - } - /* Adding the following as part of defensive programming, in case the application - does not do it when preparing the destination address.*/ -#ifdef HAVE_SA_LEN - to->sa_len = tolen; -#endif - - error = sctp_lower_sosend(so, to, NULL/*uio*/, - (struct mbuf *)mbufdata, (struct mbuf *)NULL, - uflags, sinfo); -sendmsg_return: - /* TODO: Needs a condition for non-blocking when error is EWOULDBLOCK */ - if (0 == error) - retval = len; - else if (error == EWOULDBLOCK) { - errno = EWOULDBLOCK; - retval = -1; - } else { - SCTP_PRINTF("%s: error = %d\n", __func__, error); - errno = error; - retval = -1; - } - return (retval); -} - - -/* taken from usr.lib/sctp_sys_calls.c and needed here */ -#define SCTP_SMALL_IOVEC_SIZE 2 - -/* Taken from /src/lib/libc/net/sctp_sys_calls.c - * and modified for __Userspace__ - * calling sctp_generic_recvmsg from this function - */ -ssize_t -userspace_sctp_recvmsg(struct socket *so, - void *dbuf, - size_t len, - struct sockaddr *from, - socklen_t *fromlenp, - struct sctp_sndrcvinfo *sinfo, - int *msg_flags) -{ - struct uio auio; - struct iovec iov[SCTP_SMALL_IOVEC_SIZE]; - struct iovec *tiov; - int iovlen = 1; - int error = 0; - ssize_t ulen; - int i; - socklen_t fromlen; - - iov[0].iov_base = dbuf; - iov[0].iov_len = len; - - auio.uio_iov = iov; - auio.uio_iovcnt = iovlen; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; /* XXX */ - auio.uio_resid = 0; - tiov = iov; - for (i = 0; i iov_len) < 0) { - error = EINVAL; - SCTP_PRINTF("%s: error = %d\n", __func__, error); - return (-1); - } - } - ulen = auio.uio_resid; - if (fromlenp != NULL) { - fromlen = *fromlenp; - } else { - fromlen = 0; - } - error = sctp_sorecvmsg(so, &auio, (struct mbuf **)NULL, - from, fromlen, msg_flags, - (struct sctp_sndrcvinfo *)sinfo, 1); - - if (error) { - if ((auio.uio_resid != ulen) && - (error == EINTR || -#if !defined(__NetBSD__) - error == ERESTART || -#endif - error == EWOULDBLOCK)) { - error = 0; - } - } - if ((fromlenp != NULL) && (fromlen > 0) && (from != NULL)) { - switch (from->sa_family) { -#if defined(INET) - case AF_INET: - *fromlenp = sizeof(struct sockaddr_in); - break; -#endif -#if defined(INET6) - case AF_INET6: - *fromlenp = sizeof(struct sockaddr_in6); - break; -#endif - case AF_CONN: - *fromlenp = sizeof(struct sockaddr_conn); - break; - default: - *fromlenp = 0; - break; - } - if (*fromlenp > fromlen) { - *fromlenp = fromlen; - } - } - if (error == 0) { - /* ready return value */ - return (ulen - auio.uio_resid); - } else { - SCTP_PRINTF("%s: error = %d\n", __func__, error); - return (-1); - } -} - -ssize_t -usrsctp_recvv(struct socket *so, - void *dbuf, - size_t len, - struct sockaddr *from, - socklen_t *fromlenp, - void *info, - socklen_t *infolen, - unsigned int *infotype, - int *msg_flags) -{ - struct uio auio; - struct iovec iov[SCTP_SMALL_IOVEC_SIZE]; - struct iovec *tiov; - int iovlen = 1; - ssize_t ulen; - int i; - socklen_t fromlen; - struct sctp_rcvinfo *rcv; - struct sctp_recvv_rn *rn; - struct sctp_extrcvinfo seinfo; - - if (so == NULL) { - errno = EBADF; - return (-1); - } - iov[0].iov_base = dbuf; - iov[0].iov_len = len; - - auio.uio_iov = iov; - auio.uio_iovcnt = iovlen; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; /* XXX */ - auio.uio_resid = 0; - tiov = iov; - for (i = 0; i iov_len) < 0) { - errno = EINVAL; - return (-1); - } - } - ulen = auio.uio_resid; - if (fromlenp != NULL) { - fromlen = *fromlenp; - } else { - fromlen = 0; - } - errno = sctp_sorecvmsg(so, &auio, (struct mbuf **)NULL, - from, fromlen, msg_flags, - (struct sctp_sndrcvinfo *)&seinfo, 1); - if (errno) { - if ((auio.uio_resid != ulen) && - (errno == EINTR || -#if !defined(__NetBSD__) - errno == ERESTART || -#endif - errno == EWOULDBLOCK)) { - errno = 0; - } - } - if (errno != 0) { - goto out; - } - if ((*msg_flags & MSG_NOTIFICATION) == 0) { - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) && - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && - *infolen >= (socklen_t)sizeof(struct sctp_recvv_rn) && - seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_AVAIL) { - rn = (struct sctp_recvv_rn *)info; - rn->recvv_rcvinfo.rcv_sid = seinfo.sinfo_stream; - rn->recvv_rcvinfo.rcv_ssn = seinfo.sinfo_ssn; - rn->recvv_rcvinfo.rcv_flags = seinfo.sinfo_flags; - rn->recvv_rcvinfo.rcv_ppid = seinfo.sinfo_ppid; - rn->recvv_rcvinfo.rcv_context = seinfo.sinfo_context; - rn->recvv_rcvinfo.rcv_tsn = seinfo.sinfo_tsn; - rn->recvv_rcvinfo.rcv_cumtsn = seinfo.sinfo_cumtsn; - rn->recvv_rcvinfo.rcv_assoc_id = seinfo.sinfo_assoc_id; - rn->recvv_nxtinfo.nxt_sid = seinfo.sreinfo_next_stream; - rn->recvv_nxtinfo.nxt_flags = 0; - if (seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) { - rn->recvv_nxtinfo.nxt_flags |= SCTP_UNORDERED; - } - if (seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) { - rn->recvv_nxtinfo.nxt_flags |= SCTP_NOTIFICATION; - } - if (seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) { - rn->recvv_nxtinfo.nxt_flags |= SCTP_COMPLETE; - } - rn->recvv_nxtinfo.nxt_ppid = seinfo.sreinfo_next_ppid; - rn->recvv_nxtinfo.nxt_length = seinfo.sreinfo_next_length; - rn->recvv_nxtinfo.nxt_assoc_id = seinfo.sreinfo_next_aid; - *infolen = (socklen_t)sizeof(struct sctp_recvv_rn); - *infotype = SCTP_RECVV_RN; - } else if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && - *infolen >= (socklen_t)sizeof(struct sctp_rcvinfo)) { - rcv = (struct sctp_rcvinfo *)info; - rcv->rcv_sid = seinfo.sinfo_stream; - rcv->rcv_ssn = seinfo.sinfo_ssn; - rcv->rcv_flags = seinfo.sinfo_flags; - rcv->rcv_ppid = seinfo.sinfo_ppid; - rcv->rcv_context = seinfo.sinfo_context; - rcv->rcv_tsn = seinfo.sinfo_tsn; - rcv->rcv_cumtsn = seinfo.sinfo_cumtsn; - rcv->rcv_assoc_id = seinfo.sinfo_assoc_id; - *infolen = (socklen_t)sizeof(struct sctp_rcvinfo); - *infotype = SCTP_RECVV_RCVINFO; - } else { - *infotype = SCTP_RECVV_NOINFO; - *infolen = 0; - } - } - if ((fromlenp != NULL) && - (fromlen > 0) && - (from != NULL) && - (ulen > auio.uio_resid)) { - switch (from->sa_family) { -#if defined(INET) - case AF_INET: - *fromlenp = sizeof(struct sockaddr_in); - break; -#endif -#if defined(INET6) - case AF_INET6: - *fromlenp = sizeof(struct sockaddr_in6); - break; -#endif - case AF_CONN: - *fromlenp = sizeof(struct sockaddr_conn); - break; - default: - *fromlenp = 0; - break; - } - if (*fromlenp > fromlen) { - *fromlenp = fromlen; - } - } -out: - if (errno == 0) { - /* ready return value */ - return (ulen - auio.uio_resid); - } else { - return (-1); - } -} - - - - -/* Taken from /src/sys/kern/uipc_socket.c - * and modified for __Userspace__ - * socreate returns a socket. The socket should be - * closed with soclose(). - */ -int -socreate(int dom, struct socket **aso, int type, int proto) -{ - struct socket *so; - int error; - - if ((dom != AF_CONN) && (dom != AF_INET) && (dom != AF_INET6)) { - return (EINVAL); - } - if ((type != SOCK_STREAM) && (type != SOCK_SEQPACKET)) { - return (EINVAL); - } - if (proto != IPPROTO_SCTP) { - return (EINVAL); - } - - so = soalloc(); - if (so == NULL) { - return (ENOBUFS); - } - - /* - * so_incomp represents a queue of connections that - * must be completed at protocol level before being - * returned. so_comp field heads a list of sockets - * that are ready to be returned to the listening process - *__Userspace__ These queues are being used at a number of places like accept etc. - */ - TAILQ_INIT(&so->so_incomp); - TAILQ_INIT(&so->so_comp); - so->so_type = type; - so->so_count = 1; - so->so_dom = dom; - /* - * Auto-sizing of socket buffers is managed by the protocols and - * the appropriate flags must be set in the pru_attach function. - * For __Userspace__ The pru_attach function in this case is sctp_attach. - */ - switch (dom) { -#if defined(INET) - case AF_INET: - error = sctp_attach(so, proto, SCTP_DEFAULT_VRFID); - break; -#endif -#if defined(INET6) - case AF_INET6: - error = sctp6_attach(so, proto, SCTP_DEFAULT_VRFID); - break; -#endif - case AF_CONN: - error = sctpconn_attach(so, proto, SCTP_DEFAULT_VRFID); - break; - default: - error = EAFNOSUPPORT; - break; - } - if (error) { - KASSERT(so->so_count == 1, ("socreate: so_count %d", so->so_count)); - so->so_count = 0; - sodealloc(so); - return (error); - } - *aso = so; - return (0); -} - - -/* Taken from /src/sys/kern/uipc_syscalls.c - * and modified for __Userspace__ - * Removing struct thread td. - */ -struct socket * -userspace_socket(int domain, int type, int protocol) -{ - struct socket *so = NULL; - - errno = socreate(domain, &so, type, protocol); - if (errno) { - return (NULL); - } - /* - * The original socket call returns the file descriptor fd. - * td->td_retval[0] = fd. - * We are returning struct socket *so. - */ - return (so); -} - -struct socket * -usrsctp_socket(int domain, int type, int protocol, - int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data, - size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info), - int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info), - uint32_t sb_threshold, - void *ulp_info) -{ - struct socket *so = NULL; - - if ((protocol == IPPROTO_SCTP) && (SCTP_BASE_VAR(sctp_pcb_initialized) == 0)) { - errno = EPROTONOSUPPORT; - return (NULL); - } - if ((receive_cb == NULL) && - ((send_cb != NULL) || (sb_threshold != 0) || (ulp_info != NULL))) { - errno = EINVAL; - return (NULL); - } - if ((domain == AF_CONN) && (SCTP_BASE_VAR(conn_output) == NULL)) { - errno = EAFNOSUPPORT; - return (NULL); - } - errno = socreate(domain, &so, type, protocol); - if (errno) { - return (NULL); - } - /* - * The original socket call returns the file descriptor fd. - * td->td_retval[0] = fd. - * We are returning struct socket *so. - */ - register_recv_cb(so, receive_cb); - register_send_cb(so, sb_threshold, send_cb); - register_ulp_info(so, ulp_info); - return (so); -} - - -u_long sb_max = SB_MAX; -u_long sb_max_adj = - SB_MAX * MCLBYTES / (MSIZE + MCLBYTES); /* adjusted sb_max */ - -static u_long sb_efficiency = 8; /* parameter for sbreserve() */ - -/* - * Allot mbufs to a sockbuf. Attempt to scale mbmax so that mbcnt doesn't - * become limiting if buffering efficiency is near the normal case. - */ -int -sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so) -{ - SOCKBUF_LOCK_ASSERT(sb); - sb->sb_mbmax = (u_int)min(cc * sb_efficiency, sb_max); - sb->sb_hiwat = (u_int)cc; - if (sb->sb_lowat > (int)sb->sb_hiwat) - sb->sb_lowat = (int)sb->sb_hiwat; - return (1); -} - -static int -sbreserve(struct sockbuf *sb, u_long cc, struct socket *so) -{ - int error; - - SOCKBUF_LOCK(sb); - error = sbreserve_locked(sb, cc, so); - SOCKBUF_UNLOCK(sb); - return (error); -} - -int -soreserve(struct socket *so, u_long sndcc, u_long rcvcc) -{ - SOCKBUF_LOCK(&so->so_snd); - SOCKBUF_LOCK(&so->so_rcv); - so->so_snd.sb_hiwat = (uint32_t)sndcc; - so->so_rcv.sb_hiwat = (uint32_t)rcvcc; - - if (sbreserve_locked(&so->so_snd, sndcc, so) == 0) { - goto bad; - } - if (sbreserve_locked(&so->so_rcv, rcvcc, so) == 0) { - goto bad; - } - if (so->so_rcv.sb_lowat == 0) - so->so_rcv.sb_lowat = 1; - if (so->so_snd.sb_lowat == 0) - so->so_snd.sb_lowat = MCLBYTES; - if (so->so_snd.sb_lowat > (int)so->so_snd.sb_hiwat) - so->so_snd.sb_lowat = (int)so->so_snd.sb_hiwat; - SOCKBUF_UNLOCK(&so->so_rcv); - SOCKBUF_UNLOCK(&so->so_snd); - return (0); - - bad: - SOCKBUF_UNLOCK(&so->so_rcv); - SOCKBUF_UNLOCK(&so->so_snd); - return (ENOBUFS); -} - - -/* Taken from /src/sys/kern/uipc_sockbuf.c - * and modified for __Userspace__ - */ - -void -sowakeup(struct socket *so, struct sockbuf *sb) -{ - - SOCKBUF_LOCK_ASSERT(sb); - - sb->sb_flags &= ~SB_SEL; - if (sb->sb_flags & SB_WAIT) { - sb->sb_flags &= ~SB_WAIT; -#if defined(_WIN32) - WakeAllConditionVariable(&(sb)->sb_cond); -#else - pthread_cond_broadcast(&(sb)->sb_cond); -#endif - } - SOCKBUF_UNLOCK(sb); -} - - -/* Taken from /src/sys/kern/uipc_socket.c - * and modified for __Userspace__ - */ - -int -sobind(struct socket *so, struct sockaddr *nam) -{ - switch (nam->sa_family) { -#if defined(INET) - case AF_INET: - return (sctp_bind(so, nam)); -#endif -#if defined(INET6) - case AF_INET6: - return (sctp6_bind(so, nam, NULL)); -#endif - case AF_CONN: - return (sctpconn_bind(so, nam)); - default: - return EAFNOSUPPORT; - } -} - -/* Taken from /src/sys/kern/uipc_syscalls.c - * and modified for __Userspace__ - */ - -int -usrsctp_bind(struct socket *so, struct sockaddr *name, int namelen) -{ - struct sockaddr *sa; - - if (so == NULL) { - errno = EBADF; - return (-1); - } - if ((errno = getsockaddr(&sa, (caddr_t)name, namelen)) != 0) - return (-1); - - errno = sobind(so, sa); - FREE(sa, M_SONAME); - if (errno) { - return (-1); - } else { - return (0); - } -} - -int -userspace_bind(struct socket *so, struct sockaddr *name, int namelen) -{ - return (usrsctp_bind(so, name, namelen)); -} - -/* Taken from /src/sys/kern/uipc_socket.c - * and modified for __Userspace__ - */ - -int -solisten(struct socket *so, int backlog) -{ - if (so == NULL) { - return (EBADF); - } else { - return (sctp_listen(so, backlog, NULL)); - } -} - - -int -solisten_proto_check(struct socket *so) -{ - - SOCK_LOCK_ASSERT(so); - - if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | - SS_ISDISCONNECTING)) - return (EINVAL); - return (0); -} - -static int somaxconn = SOMAXCONN; - -void -solisten_proto(struct socket *so, int backlog) -{ - - SOCK_LOCK_ASSERT(so); - - if (backlog < 0 || backlog > somaxconn) - backlog = somaxconn; - so->so_qlimit = backlog; - so->so_options |= SCTP_SO_ACCEPTCONN; -} - - - - -/* Taken from /src/sys/kern/uipc_syscalls.c - * and modified for __Userspace__ - */ - -int -usrsctp_listen(struct socket *so, int backlog) -{ - errno = solisten(so, backlog); - if (errno) { - return (-1); - } else { - return (0); - } -} - -int -userspace_listen(struct socket *so, int backlog) -{ - return (usrsctp_listen(so, backlog)); -} - -/* Taken from /src/sys/kern/uipc_socket.c - * and modified for __Userspace__ - */ - -int -soaccept(struct socket *so, struct sockaddr **nam) -{ - int error; - - SOCK_LOCK(so); - KASSERT((so->so_state & SS_NOFDREF) != 0, ("soaccept: !NOFDREF")); - so->so_state &= ~SS_NOFDREF; - SOCK_UNLOCK(so); - error = sctp_accept(so, nam); - return (error); -} - - - -/* Taken from /src/sys/kern/uipc_syscalls.c - * kern_accept modified for __Userspace__ - */ -int -user_accept(struct socket *head, struct sockaddr **name, socklen_t *namelen, struct socket **ptr_accept_ret_sock) -{ - struct sockaddr *sa = NULL; - int error; - struct socket *so = NULL; - - - if (name) { - *name = NULL; - } - - if ((head->so_options & SCTP_SO_ACCEPTCONN) == 0) { - error = EINVAL; - goto done; - } - - ACCEPT_LOCK(); - if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) { - ACCEPT_UNLOCK(); - error = EWOULDBLOCK; - goto noconnection; - } - while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) { - if (head->so_rcv.sb_state & SBS_CANTRCVMORE) { - head->so_error = ECONNABORTED; - break; - } -#if defined(_WIN32) - if (SleepConditionVariableCS(&accept_cond, &accept_mtx, INFINITE)) - error = 0; - else - error = GetLastError(); -#else - error = pthread_cond_wait(&accept_cond, &accept_mtx); -#endif - if (error) { - ACCEPT_UNLOCK(); - goto noconnection; - } - } - if (head->so_error) { - error = head->so_error; - head->so_error = 0; - ACCEPT_UNLOCK(); - goto noconnection; - } - so = TAILQ_FIRST(&head->so_comp); - KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP")); - KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP")); - - /* - * Before changing the flags on the socket, we have to bump the - * reference count. Otherwise, if the protocol calls sofree(), - * the socket will be released due to a zero refcount. - */ - SOCK_LOCK(so); /* soref() and so_state update */ - soref(so); /* file descriptor reference */ - - TAILQ_REMOVE(&head->so_comp, so, so_list); - head->so_qlen--; - so->so_state |= (head->so_state & SS_NBIO); - so->so_qstate &= ~SQ_COMP; - so->so_head = NULL; - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - - - /* - * The original accept returns fd value via td->td_retval[0] = fd; - * we will return the socket for accepted connection. - */ - - error = soaccept(so, &sa); - if (error) { - /* - * return a namelen of zero for older code which might - * ignore the return value from accept. - */ - if (name) - *namelen = 0; - goto noconnection; - } - if (sa == NULL) { - if (name) - *namelen = 0; - goto done; - } - if (name) { -#ifdef HAVE_SA_LEN - /* check sa_len before it is destroyed */ - if (*namelen > sa->sa_len) { - *namelen = sa->sa_len; - } -#else - socklen_t sa_len; - - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sa_len = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa_len = sizeof(struct sockaddr_in6); - break; -#endif - case AF_CONN: - sa_len = sizeof(struct sockaddr_conn); - break; - default: - sa_len = 0; - break; - } - if (*namelen > sa_len) { - *namelen = sa_len; - } -#endif - *name = sa; - sa = NULL; - } -noconnection: - if (sa) { - FREE(sa, M_SONAME); - } - -done: - *ptr_accept_ret_sock = so; - return (error); -} - - - -/* Taken from /src/sys/kern/uipc_syscalls.c - * and modified for __Userspace__ - */ -/* - * accept1() - */ -static int -accept1(struct socket *so, struct sockaddr *aname, socklen_t *anamelen, struct socket **ptr_accept_ret_sock) -{ - struct sockaddr *name; - socklen_t namelen; - int error; - - if (so == NULL) { - return (EBADF); - } - if (aname == NULL) { - return (user_accept(so, NULL, NULL, ptr_accept_ret_sock)); - } - - error = copyin(anamelen, &namelen, sizeof (namelen)); - if (error) - return (error); - - error = user_accept(so, &name, &namelen, ptr_accept_ret_sock); - - /* - * return a namelen of zero for older code which might - * ignore the return value from accept. - */ - if (error) { - (void) copyout(&namelen, - anamelen, sizeof(*anamelen)); - return (error); - } - - if (error == 0 && name != NULL) { - error = copyout(name, aname, namelen); - } - if (error == 0) { - error = copyout(&namelen, anamelen, sizeof(namelen)); - } - - if (name) { - FREE(name, M_SONAME); - } - return (error); -} - -struct socket * -usrsctp_accept(struct socket *so, struct sockaddr *aname, socklen_t *anamelen) -{ - struct socket *accept_return_sock = NULL; - - errno = accept1(so, aname, anamelen, &accept_return_sock); - if (errno) { - return (NULL); - } else { - return (accept_return_sock); - } -} - -struct socket * -userspace_accept(struct socket *so, struct sockaddr *aname, socklen_t *anamelen) -{ - return (usrsctp_accept(so, aname, anamelen)); -} - -struct socket * -usrsctp_peeloff(struct socket *head, sctp_assoc_t id) -{ - struct socket *so; - - if ((errno = sctp_can_peel_off(head, id)) != 0) { - return (NULL); - } - if ((so = sonewconn(head, SS_ISCONNECTED)) == NULL) { - return (NULL); - } - ACCEPT_LOCK(); - SOCK_LOCK(so); - soref(so); - TAILQ_REMOVE(&head->so_comp, so, so_list); - head->so_qlen--; - so->so_state |= (head->so_state & SS_NBIO); - so->so_qstate &= ~SQ_COMP; - so->so_head = NULL; - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - if ((errno = sctp_do_peeloff(head, so, id)) != 0) { - so->so_count = 0; - sodealloc(so); - return (NULL); - } - return (so); -} - -int -sodisconnect(struct socket *so) -{ - int error; - - if ((so->so_state & SS_ISCONNECTED) == 0) - return (ENOTCONN); - if (so->so_state & SS_ISDISCONNECTING) - return (EALREADY); - error = sctp_disconnect(so); - return (error); -} - -int -usrsctp_set_non_blocking(struct socket *so, int onoff) -{ - if (so == NULL) { - errno = EBADF; - return (-1); - } - SOCK_LOCK(so); - if (onoff != 0) { - so->so_state |= SS_NBIO; - } else { - so->so_state &= ~SS_NBIO; - } - SOCK_UNLOCK(so); - return (0); -} - -int -usrsctp_get_non_blocking(struct socket *so) -{ - int result; - - if (so == NULL) { - errno = EBADF; - return (-1); - } - SOCK_LOCK(so); - if (so->so_state & SS_NBIO) { - result = 1; - } else { - result = 0; - } - SOCK_UNLOCK(so); - return (result); -} - -int -soconnect(struct socket *so, struct sockaddr *nam) -{ - int error; - - if (so->so_options & SCTP_SO_ACCEPTCONN) - return (EOPNOTSUPP); - /* - * If protocol is connection-based, can only connect once. - * Otherwise, if connected, try to disconnect first. This allows - * user to disconnect by connecting to, e.g., a null address. - */ - if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && (sodisconnect(so) != 0)) { - error = EISCONN; - } else { - /* - * Prevent accumulated error from previous connection from - * biting us. - */ - so->so_error = 0; - switch (nam->sa_family) { -#if defined(INET) - case AF_INET: - error = sctp_connect(so, nam); - break; -#endif -#if defined(INET6) - case AF_INET6: - error = sctp6_connect(so, nam); - break; -#endif - case AF_CONN: - error = sctpconn_connect(so, nam); - break; - default: - error = EAFNOSUPPORT; - } - } - - return (error); -} - - - -int user_connect(struct socket *so, struct sockaddr *sa) -{ - int error; - int interrupted = 0; - - if (so == NULL) { - error = EBADF; - goto done1; - } - if (so->so_state & SS_ISCONNECTING) { - error = EALREADY; - goto done1; - } - - error = soconnect(so, sa); - if (error) { - goto bad; - } - if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { - error = EINPROGRESS; - goto done1; - } - - SOCK_LOCK(so); - while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { -#if defined(_WIN32) - if (SleepConditionVariableCS(SOCK_COND(so), SOCK_MTX(so), INFINITE)) - error = 0; - else - error = -1; -#else - error = pthread_cond_wait(SOCK_COND(so), SOCK_MTX(so)); -#endif - if (error) { -#if defined(__NetBSD__) - if (error == EINTR) { -#else - if (error == EINTR || error == ERESTART) { -#endif - interrupted = 1; - } - break; - } - } - if (error == 0) { - error = so->so_error; - so->so_error = 0; - } - SOCK_UNLOCK(so); - -bad: - if (!interrupted) { - so->so_state &= ~SS_ISCONNECTING; - } -#if !defined(__NetBSD__) - if (error == ERESTART) { - error = EINTR; - } -#endif -done1: - return (error); -} - -int usrsctp_connect(struct socket *so, struct sockaddr *name, int namelen) -{ - struct sockaddr *sa = NULL; - - errno = getsockaddr(&sa, (caddr_t)name, namelen); - if (errno) - return (-1); - - errno = user_connect(so, sa); - FREE(sa, M_SONAME); - if (errno) { - return (-1); - } else { - return (0); - } -} - -int userspace_connect(struct socket *so, struct sockaddr *name, int namelen) -{ - return (usrsctp_connect(so, name, namelen)); -} - -#define SCTP_STACK_BUF_SIZE 2048 - -void -usrsctp_close(struct socket *so) { - if (so != NULL) { - if (so->so_options & SCTP_SO_ACCEPTCONN) { - struct socket *sp; - - ACCEPT_LOCK(); - while ((sp = TAILQ_FIRST(&so->so_comp)) != NULL) { - TAILQ_REMOVE(&so->so_comp, sp, so_list); - so->so_qlen--; - sp->so_qstate &= ~SQ_COMP; - sp->so_head = NULL; - ACCEPT_UNLOCK(); - soabort(sp); - ACCEPT_LOCK(); - } - ACCEPT_UNLOCK(); - } - ACCEPT_LOCK(); - SOCK_LOCK(so); - sorele(so); - } -} - -void -userspace_close(struct socket *so) -{ - usrsctp_close(so); -} - -int -usrsctp_shutdown(struct socket *so, int how) -{ - if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR)) { - errno = EINVAL; - return (-1); - } - if (so == NULL) { - errno = EBADF; - return (-1); - } - sctp_flush(so, how); - if (how != SHUT_WR) - socantrcvmore(so); - if (how != SHUT_RD) { - errno = sctp_shutdown(so); - if (errno) { - return (-1); - } else { - return (0); - } - } - return (0); -} - -int -userspace_shutdown(struct socket *so, int how) -{ - return (usrsctp_shutdown(so, how)); -} - -int -usrsctp_finish(void) -{ - if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { - return (0); - } - if (SCTP_INP_INFO_TRYLOCK()) { - if (!LIST_EMPTY(&SCTP_BASE_INFO(listhead))) { - SCTP_INP_INFO_RUNLOCK(); - return (-1); - } - SCTP_INP_INFO_RUNLOCK(); - } else { - return (-1); - } - sctp_finish(); -#if defined(_WIN32) - DeleteConditionVariable(&accept_cond); - DeleteCriticalSection(&accept_mtx); -#if defined(INET) || defined(INET6) - WSACleanup(); -#endif -#else - pthread_cond_destroy(&accept_cond); - pthread_mutex_destroy(&accept_mtx); -#endif - return (0); -} - -int -userspace_finish(void) -{ - return (usrsctp_finish()); -} - -/* needed from sctp_usrreq.c */ -int -sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, void *p); - -int -usrsctp_setsockopt(struct socket *so, int level, int option_name, - const void *option_value, socklen_t option_len) -{ - if (so == NULL) { - errno = EBADF; - return (-1); - } - switch (level) { - case SOL_SOCKET: - { - switch (option_name) { - case SO_RCVBUF: - if (option_len < (socklen_t)sizeof(int)) { - errno = EINVAL; - return (-1); - } else { - int *buf_size; - - buf_size = (int *)option_value; - if (*buf_size < 1) { - errno = EINVAL; - return (-1); - } - sbreserve(&so->so_rcv, (u_long)*buf_size, so); - return (0); - } - break; - case SO_SNDBUF: - if (option_len < (socklen_t)sizeof(int)) { - errno = EINVAL; - return (-1); - } else { - int *buf_size; - - buf_size = (int *)option_value; - if (*buf_size < 1) { - errno = EINVAL; - return (-1); - } - sbreserve(&so->so_snd, (u_long)*buf_size, so); - return (0); - } - break; - case SO_LINGER: - if (option_len < (socklen_t)sizeof(struct linger)) { - errno = EINVAL; - return (-1); - } else { - struct linger *l; - - l = (struct linger *)option_value; - so->so_linger = l->l_linger; - if (l->l_onoff) { - so->so_options |= SCTP_SO_LINGER; - } else { - so->so_options &= ~SCTP_SO_LINGER; - } - return (0); - } - default: - errno = EINVAL; - return (-1); - } - } - case IPPROTO_SCTP: - errno = sctp_setopt(so, option_name, (void *) option_value, (size_t)option_len, NULL); - if (errno) { - return (-1); - } else { - return (0); - } - default: - errno = ENOPROTOOPT; - return (-1); - } -} - -int -userspace_setsockopt(struct socket *so, int level, int option_name, - const void *option_value, socklen_t option_len) -{ - return (usrsctp_setsockopt(so, level, option_name, option_value, option_len)); -} - -/* needed from sctp_usrreq.c */ -int -sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, - void *p); - -int -usrsctp_getsockopt(struct socket *so, int level, int option_name, - void *option_value, socklen_t *option_len) -{ - if (so == NULL) { - errno = EBADF; - return (-1); - } - if (option_len == NULL) { - errno = EFAULT; - return (-1); - } - switch (level) { - case SOL_SOCKET: - switch (option_name) { - case SO_RCVBUF: - if (*option_len < (socklen_t)sizeof(int)) { - errno = EINVAL; - return (-1); - } else { - int *buf_size; - - buf_size = (int *)option_value; - *buf_size = so->so_rcv.sb_hiwat; - *option_len = (socklen_t)sizeof(int); - return (0); - } - break; - case SO_SNDBUF: - if (*option_len < (socklen_t)sizeof(int)) { - errno = EINVAL; - return (-1); - } else { - int *buf_size; - - buf_size = (int *)option_value; - *buf_size = so->so_snd.sb_hiwat; - *option_len = (socklen_t)sizeof(int); - return (0); - } - break; - case SO_LINGER: - if (*option_len < (socklen_t)sizeof(struct linger)) { - errno = EINVAL; - return (-1); - } else { - struct linger *l; - - l = (struct linger *)option_value; - l->l_linger = so->so_linger; - if (so->so_options & SCTP_SO_LINGER) { - l->l_onoff = 1; - } else { - l->l_onoff = 0; - } - *option_len = (socklen_t)sizeof(struct linger); - return (0); - } - break; - case SO_ERROR: - if (*option_len < (socklen_t)sizeof(int)) { - errno = EINVAL; - return (-1); - } else { - int *intval; - - intval = (int *)option_value; - *intval = so->so_error; - *option_len = (socklen_t)sizeof(int); - return (0); - } - break; - default: - errno = EINVAL; - return (-1); - } - case IPPROTO_SCTP: - { - size_t len; - - len = (size_t)*option_len; - errno = sctp_getopt(so, option_name, option_value, &len, NULL); - *option_len = (socklen_t)len; - if (errno) { - return (-1); - } else { - return (0); - } - } - default: - errno = ENOPROTOOPT; - return (-1); - } -} - -int -userspace_getsockopt(struct socket *so, int level, int option_name, - void *option_value, socklen_t *option_len) -{ - return (usrsctp_getsockopt(so, level, option_name, option_value, option_len)); -} - -int -usrsctp_opt_info(struct socket *so, sctp_assoc_t id, int opt, void *arg, socklen_t *size) -{ - if (arg == NULL) { - errno = EINVAL; - return (-1); - } - if ((id == SCTP_CURRENT_ASSOC) || - (id == SCTP_ALL_ASSOC)) { - errno = EINVAL; - return (-1); - } - switch (opt) { - case SCTP_RTOINFO: - ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id; - break; - case SCTP_ASSOCINFO: - ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; - break; - case SCTP_DEFAULT_SEND_PARAM: - ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id; - break; - case SCTP_PRIMARY_ADDR: - ((struct sctp_setprim *)arg)->ssp_assoc_id = id; - break; - case SCTP_PEER_ADDR_PARAMS: - ((struct sctp_paddrparams *)arg)->spp_assoc_id = id; - break; - case SCTP_MAXSEG: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_AUTH_KEY: - ((struct sctp_authkey *)arg)->sca_assoc_id = id; - break; - case SCTP_AUTH_ACTIVE_KEY: - ((struct sctp_authkeyid *)arg)->scact_assoc_id = id; - break; - case SCTP_DELAYED_SACK: - ((struct sctp_sack_info *)arg)->sack_assoc_id = id; - break; - case SCTP_CONTEXT: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_STATUS: - ((struct sctp_status *)arg)->sstat_assoc_id = id; - break; - case SCTP_GET_PEER_ADDR_INFO: - ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id; - break; - case SCTP_PEER_AUTH_CHUNKS: - ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; - break; - case SCTP_LOCAL_AUTH_CHUNKS: - ((struct sctp_authchunks *)arg)->gauth_assoc_id = id; - break; - case SCTP_TIMEOUTS: - ((struct sctp_timeouts *)arg)->stimo_assoc_id = id; - break; - case SCTP_EVENT: - ((struct sctp_event *)arg)->se_assoc_id = id; - break; - case SCTP_DEFAULT_SNDINFO: - ((struct sctp_sndinfo *)arg)->snd_assoc_id = id; - break; - case SCTP_DEFAULT_PRINFO: - ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; - break; - case SCTP_PEER_ADDR_THLDS: - ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; - break; - case SCTP_REMOTE_UDP_ENCAPS_PORT: - ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; - break; - case SCTP_ECN_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_PR_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_AUTH_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_ASCONF_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_RECONFIG_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_NRSACK_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_PKTDROP_SUPPORTED: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_MAX_BURST: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_ENABLE_STREAM_RESET: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - case SCTP_PR_STREAM_STATUS: - ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; - break; - case SCTP_PR_ASSOC_STATUS: - ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id; - break; - case SCTP_MAX_CWND: - ((struct sctp_assoc_value *)arg)->assoc_id = id; - break; - default: - break; - } - return (usrsctp_getsockopt(so, IPPROTO_SCTP, opt, arg, size)); -} - -int -usrsctp_set_ulpinfo(struct socket *so, void *ulp_info) -{ - return (register_ulp_info(so, ulp_info)); -} - - -int -usrsctp_get_ulpinfo(struct socket *so, void **pulp_info) -{ - return (retrieve_ulp_info(so, pulp_info)); -} - -int -usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags) -{ - struct sockaddr *sa; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - int i; -#if defined(INET) || defined(INET6) - uint16_t sport; - bool fix_port; -#endif - - /* validate the flags */ - if ((flags != SCTP_BINDX_ADD_ADDR) && - (flags != SCTP_BINDX_REM_ADDR)) { - errno = EFAULT; - return (-1); - } - /* validate the address count and list */ - if ((addrcnt <= 0) || (addrs == NULL)) { - errno = EINVAL; - return (-1); - } -#if defined(INET) || defined(INET6) - sport = 0; - fix_port = false; -#endif - /* First pre-screen the addresses */ - sa = addrs; - for (i = 0; i < addrcnt; i++) { - switch (sa->sa_family) { -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (sa->sa_len != sizeof(struct sockaddr_in)) { - errno = EINVAL; - return (-1); - } -#endif - sin = (struct sockaddr_in *)sa; - if (sin->sin_port) { - /* non-zero port, check or save */ - if (sport) { - /* Check against our port */ - if (sport != sin->sin_port) { - errno = EINVAL; - return (-1); - } - } else { - /* save off the port */ - sport = sin->sin_port; - fix_port = (i > 0); - } - } -#ifndef HAVE_SA_LEN - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (sa->sa_len != sizeof(struct sockaddr_in6)) { - errno = EINVAL; - return (-1); - } -#endif - sin6 = (struct sockaddr_in6 *)sa; - if (sin6->sin6_port) { - /* non-zero port, check or save */ - if (sport) { - /* Check against our port */ - if (sport != sin6->sin6_port) { - errno = EINVAL; - return (-1); - } - } else { - /* save off the port */ - sport = sin6->sin6_port; - fix_port = (i > 0); - } - } -#ifndef HAVE_SA_LEN - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); -#endif - break; -#endif - default: - /* Invalid address family specified. */ - errno = EAFNOSUPPORT; - return (-1); - } -#ifdef HAVE_SA_LEN - sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); -#endif - } - sa = addrs; - for (i = 0; i < addrcnt; i++) { -#ifndef HAVE_SA_LEN - size_t sa_len; - -#endif -#ifdef HAVE_SA_LEN -#if defined(INET) || defined(INET6) - if (fix_port) { - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - ((struct sockaddr_in *)sa)->sin_port = sport; - break; -#endif -#ifdef INET6 - case AF_INET6: - ((struct sockaddr_in6 *)sa)->sin6_port = sport; - break; -#endif - } - } -#endif - if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, sa, sa->sa_len) != 0) { - return (-1); - } - sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); -#else - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sa_len = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa_len = sizeof(struct sockaddr_in6); - break; -#endif - default: - sa_len = 0; - break; - } - /* - * Now, if there was a port mentioned, assure that the - * first address has that port to make sure it fails or - * succeeds correctly. - */ -#if defined(INET) || defined(INET6) - if (fix_port) { - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - ((struct sockaddr_in *)sa)->sin_port = sport; - break; -#endif -#ifdef INET6 - case AF_INET6: - ((struct sockaddr_in6 *)sa)->sin6_port = sport; - break; -#endif - } - } -#endif - if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, sa, (socklen_t)sa_len) != 0) { - return (-1); - } - sa = (struct sockaddr *)((caddr_t)sa + sa_len); -#endif - } - return (0); -} - -int -usrsctp_connectx(struct socket *so, - const struct sockaddr *addrs, int addrcnt, - sctp_assoc_t *id) -{ -#if defined(INET) || defined(INET6) - char buf[SCTP_STACK_BUF_SIZE]; - int i, ret, cnt, *aa; - char *cpto; - const struct sockaddr *at; - sctp_assoc_t *p_id; - size_t len = sizeof(int); - - /* validate the address count and list */ - if ((addrs == NULL) || (addrcnt <= 0)) { - errno = EINVAL; - return (-1); - } - at = addrs; - cnt = 0; - cpto = ((caddr_t)buf + sizeof(int)); - /* validate all the addresses and get the size */ - for (i = 0; i < addrcnt; i++) { - switch (at->sa_family) { -#ifdef INET - case AF_INET: -#ifdef HAVE_SA_LEN - if (at->sa_len != sizeof(struct sockaddr_in)) { - errno = EINVAL; - return (-1); - } -#endif - len += sizeof(struct sockaddr_in); - if (len > SCTP_STACK_BUF_SIZE) { - errno = ENOMEM; - return (-1); - } - memcpy(cpto, at, sizeof(struct sockaddr_in)); - cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); - at = (struct sockaddr *)((caddr_t)at + sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: -#ifdef HAVE_SA_LEN - if (at->sa_len != sizeof(struct sockaddr_in6)) { - errno = EINVAL; - return (-1); - } -#endif -#ifdef INET - if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) { - len += sizeof(struct sockaddr_in); - if (len > SCTP_STACK_BUF_SIZE) { - errno = ENOMEM; - return (-1); - } - in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at); - cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in)); - } else { - len += sizeof(struct sockaddr_in6); - if (len > SCTP_STACK_BUF_SIZE) { - errno = ENOMEM; - return (-1); - } - memcpy(cpto, at, sizeof(struct sockaddr_in6)); - cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6)); - } -#else - len += sizeof(struct sockaddr_in6); - if (len > SCTP_STACK_BUF_SIZE) { - errno = ENOMEM; - return (-1); - } - memcpy(cpto, at, sizeof(struct sockaddr_in6)); - cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6)); -#endif - at = (struct sockaddr *)((caddr_t)at + sizeof(struct sockaddr_in6)); - break; -#endif - default: - errno = EINVAL; - return (-1); - } - cnt++; - } - aa = (int *)buf; - *aa = cnt; - ret = usrsctp_setsockopt(so, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, (socklen_t)len); - if ((ret == 0) && id) { - p_id = (sctp_assoc_t *)buf; - *id = *p_id; - } - return (ret); -#else - errno = EINVAL; - return (-1); -#endif -} - -int -usrsctp_getpaddrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs) -{ - struct sctp_getaddresses *addrs; - struct sockaddr *sa; - caddr_t lim; - socklen_t opt_len; - uint32_t size_of_addresses; - int cnt; - - if (raddrs == NULL) { - errno = EFAULT; - return (-1); - } - /* When calling getsockopt(), the value contains the assoc_id. */ - size_of_addresses = (uint32_t)id; - opt_len = (socklen_t)sizeof(uint32_t); - if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, &size_of_addresses, &opt_len) != 0) { - if (errno == ENOENT) { - return (0); - } else { - return (-1); - } - } - opt_len = (socklen_t)((size_t)size_of_addresses + sizeof(struct sctp_getaddresses)); - addrs = calloc(1, (size_t)opt_len); - if (addrs == NULL) { - errno = ENOMEM; - return (-1); - } - addrs->sget_assoc_id = id; - /* Now lets get the array of addresses */ - if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, addrs, &opt_len) != 0) { - free(addrs); - return (-1); - } - *raddrs = &addrs->addr[0].sa; - cnt = 0; - sa = &addrs->addr[0].sa; - lim = (caddr_t)addrs + opt_len; -#ifdef HAVE_SA_LEN - while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { - sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); -#else - while ((caddr_t)sa < lim) { - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); - break; -#endif - case AF_CONN: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_conn)); - break; - default: - return (cnt); - break; - } -#endif - cnt++; - } - return (cnt); -} - -void -usrsctp_freepaddrs(struct sockaddr *addrs) -{ - /* Take away the hidden association id */ - void *fr_addr; - - fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr)); - /* Now free it */ - free(fr_addr); -} - -int -usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs) -{ - struct sctp_getaddresses *addrs; - struct sockaddr *sa; - caddr_t lim; - socklen_t opt_len; - uint32_t size_of_addresses; - int cnt; - - if (raddrs == NULL) { - errno = EFAULT; - return (-1); - } - size_of_addresses = 0; - opt_len = (socklen_t)sizeof(uint32_t); - if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, &size_of_addresses, &opt_len) != 0) { - return (-1); - } - opt_len = (socklen_t)(size_of_addresses + sizeof(struct sctp_getaddresses)); - addrs = calloc(1, (size_t)opt_len); - if (addrs == NULL) { - errno = ENOMEM; - return (-1); - } - addrs->sget_assoc_id = id; - /* Now lets get the array of addresses */ - if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, &opt_len) != 0) { - free(addrs); - return (-1); - } - if (size_of_addresses == 0) { - free(addrs); - return (0); - } - *raddrs = &addrs->addr[0].sa; - cnt = 0; - sa = &addrs->addr[0].sa; - lim = (caddr_t)addrs + opt_len; -#ifdef HAVE_SA_LEN - while (((caddr_t)sa < lim) && (sa->sa_len > 0)) { - sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len); -#else - while ((caddr_t)sa < lim) { - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); - break; -#endif - case AF_CONN: - sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_conn)); - break; - default: - return (cnt); - break; - } -#endif - cnt++; - } - return (cnt); -} - -void -usrsctp_freeladdrs(struct sockaddr *addrs) -{ - /* Take away the hidden association id */ - void *fr_addr; - - fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr)); - /* Now free it */ - free(fr_addr); -} - -#ifdef INET -void -sctp_userspace_ip_output(int *result, struct mbuf *o_pak, - sctp_route_t *ro, void *inp, - uint32_t vrf_id) -{ - struct mbuf *m; - struct mbuf *m_orig; - int iovcnt; - int len; - struct ip *ip; - struct udphdr *udp; - struct sockaddr_in dst; -#if defined(_WIN32) - WSAMSG win_msg_hdr; - DWORD win_sent_len; - WSABUF send_iovec[MAXLEN_MBUF_CHAIN]; - WSABUF winbuf; -#else - struct iovec send_iovec[MAXLEN_MBUF_CHAIN]; - struct msghdr msg_hdr; -#endif - int use_udp_tunneling; - - *result = 0; - - m = SCTP_HEADER_TO_CHAIN(o_pak); - m_orig = m; - - len = sizeof(struct ip); - if (SCTP_BUF_LEN(m) < len) { - if ((m = m_pullup(m, len)) == 0) { - SCTP_PRINTF("Can not get the IP header in the first mbuf.\n"); - return; - } - } - ip = mtod(m, struct ip *); - use_udp_tunneling = (ip->ip_p == IPPROTO_UDP); - - if (use_udp_tunneling) { - len = sizeof(struct ip) + sizeof(struct udphdr); - if (SCTP_BUF_LEN(m) < len) { - if ((m = m_pullup(m, len)) == 0) { - SCTP_PRINTF("Can not get the UDP/IP header in the first mbuf.\n"); - return; - } - ip = mtod(m, struct ip *); - } - udp = (struct udphdr *)(ip + 1); - } else { - udp = NULL; - } - - if (!use_udp_tunneling) { - if (ip->ip_src.s_addr == INADDR_ANY) { - /* TODO get addr of outgoing interface */ - SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n"); - } - /* TODO need to worry about ro->ro_dst as in ip_output? */ -#if defined(__linux__) || defined(_WIN32) || (defined(__FreeBSD__) && (__FreeBSD_version >= 1100030)) - /* need to put certain fields into network order for Linux */ - ip->ip_len = htons(ip->ip_len); -#endif - } - - memset((void *)&dst, 0, sizeof(struct sockaddr_in)); - dst.sin_family = AF_INET; - dst.sin_addr.s_addr = ip->ip_dst.s_addr; -#ifdef HAVE_SIN_LEN - dst.sin_len = sizeof(struct sockaddr_in); -#endif - if (use_udp_tunneling) { - dst.sin_port = udp->uh_dport; - } else { - dst.sin_port = 0; - } - - /* tweak the mbuf chain */ - if (use_udp_tunneling) { - m_adj(m, sizeof(struct ip) + sizeof(struct udphdr)); - } - - for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) { -#if !defined(_WIN32) - send_iovec[iovcnt].iov_base = (caddr_t)m->m_data; - send_iovec[iovcnt].iov_len = SCTP_BUF_LEN(m); -#else - send_iovec[iovcnt].buf = (caddr_t)m->m_data; - send_iovec[iovcnt].len = SCTP_BUF_LEN(m); -#endif - } - - if (m != NULL) { - SCTP_PRINTF("mbuf chain couldn't be copied completely\n"); - goto free_mbuf; - } - -#if !defined(_WIN32) - msg_hdr.msg_name = (struct sockaddr *) &dst; - msg_hdr.msg_namelen = sizeof(struct sockaddr_in); - msg_hdr.msg_iov = send_iovec; - msg_hdr.msg_iovlen = iovcnt; - msg_hdr.msg_control = NULL; - msg_hdr.msg_controllen = 0; - msg_hdr.msg_flags = 0; - - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) != -1)) { - if (sendmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg_hdr, MSG_DONTWAIT) < 0) { - *result = errno; - } - } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) != -1)) { - if (sendmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg_hdr, MSG_DONTWAIT) < 0) { - *result = errno; - } - } -#else - win_msg_hdr.name = (struct sockaddr *) &dst; - win_msg_hdr.namelen = sizeof(struct sockaddr_in); - win_msg_hdr.lpBuffers = (LPWSABUF)send_iovec; - win_msg_hdr.dwBufferCount = iovcnt; - winbuf.len = 0; - winbuf.buf = NULL; - win_msg_hdr.Control = winbuf; - win_msg_hdr.dwFlags = 0; - - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) != -1)) { - if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { - *result = WSAGetLastError(); - } - } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) != -1)) { - if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { - *result = WSAGetLastError(); - } - } -#endif -free_mbuf: - sctp_m_freem(m_orig); -} -#endif - -#if defined(INET6) -void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, - struct route_in6 *ro, void *inp, - uint32_t vrf_id) -{ - struct mbuf *m; - struct mbuf *m_orig; - int iovcnt; - int len; - struct ip6_hdr *ip6; - struct udphdr *udp; - struct sockaddr_in6 dst; -#if defined(_WIN32) - WSAMSG win_msg_hdr; - DWORD win_sent_len; - WSABUF send_iovec[MAXLEN_MBUF_CHAIN]; - WSABUF winbuf; -#else - struct iovec send_iovec[MAXLEN_MBUF_CHAIN]; - struct msghdr msg_hdr; -#endif - int use_udp_tunneling; - - *result = 0; - - m = SCTP_HEADER_TO_CHAIN(o_pak); - m_orig = m; - - len = sizeof(struct ip6_hdr); - - if (SCTP_BUF_LEN(m) < len) { - if ((m = m_pullup(m, len)) == 0) { - SCTP_PRINTF("Can not get the IP header in the first mbuf.\n"); - return; - } - } - - ip6 = mtod(m, struct ip6_hdr *); - use_udp_tunneling = (ip6->ip6_nxt == IPPROTO_UDP); - - if (use_udp_tunneling) { - len = sizeof(struct ip6_hdr) + sizeof(struct udphdr); - if (SCTP_BUF_LEN(m) < len) { - if ((m = m_pullup(m, len)) == 0) { - SCTP_PRINTF("Can not get the UDP/IP header in the first mbuf.\n"); - return; - } - ip6 = mtod(m, struct ip6_hdr *); - } - udp = (struct udphdr *)(ip6 + 1); - } else { - udp = NULL; - } - - if (!use_udp_tunneling) { - if (ip6->ip6_src.s6_addr == in6addr_any.s6_addr) { - /* TODO get addr of outgoing interface */ - SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n"); - } - /* TODO need to worry about ro->ro_dst as in ip_output? */ - } - - memset((void *)&dst, 0, sizeof(struct sockaddr_in6)); - dst.sin6_family = AF_INET6; - dst.sin6_addr = ip6->ip6_dst; -#ifdef HAVE_SIN6_LEN - dst.sin6_len = sizeof(struct sockaddr_in6); -#endif - - if (use_udp_tunneling) { - dst.sin6_port = udp->uh_dport; - } else { - dst.sin6_port = 0; - } - - /* tweak the mbuf chain */ - if (use_udp_tunneling) { - m_adj(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - } else { - m_adj(m, sizeof(struct ip6_hdr)); - } - - for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) { -#if !defined(_WIN32) - send_iovec[iovcnt].iov_base = (caddr_t)m->m_data; - send_iovec[iovcnt].iov_len = SCTP_BUF_LEN(m); -#else - send_iovec[iovcnt].buf = (caddr_t)m->m_data; - send_iovec[iovcnt].len = SCTP_BUF_LEN(m); -#endif - } - if (m != NULL) { - SCTP_PRINTF("mbuf chain couldn't be copied completely\n"); - goto free_mbuf; - } - -#if !defined(_WIN32) - msg_hdr.msg_name = (struct sockaddr *) &dst; - msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); - msg_hdr.msg_iov = send_iovec; - msg_hdr.msg_iovlen = iovcnt; - msg_hdr.msg_control = NULL; - msg_hdr.msg_controllen = 0; - msg_hdr.msg_flags = 0; - - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) != -1)) { - if (sendmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg_hdr, MSG_DONTWAIT)< 0) { - *result = errno; - } - } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) != -1)) { - if (sendmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg_hdr, MSG_DONTWAIT) < 0) { - *result = errno; - } - } -#else - win_msg_hdr.name = (struct sockaddr *) &dst; - win_msg_hdr.namelen = sizeof(struct sockaddr_in6); - win_msg_hdr.lpBuffers = (LPWSABUF)send_iovec; - win_msg_hdr.dwBufferCount = iovcnt; - winbuf.len = 0; - winbuf.buf = NULL; - win_msg_hdr.Control = winbuf; - win_msg_hdr.dwFlags = 0; - - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) != -1)) { - if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { - *result = WSAGetLastError(); - } - } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) != -1)) { - if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { - *result = WSAGetLastError(); - } - } -#endif -free_mbuf: - sctp_m_freem(m_orig); -} -#endif - -void -usrsctp_register_address(void *addr) -{ - struct sockaddr_conn sconn; - - memset(&sconn, 0, sizeof(struct sockaddr_conn)); - sconn.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - sconn.sconn_len = sizeof(struct sockaddr_conn); -#endif - sconn.sconn_port = 0; - sconn.sconn_addr = addr; - sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, - NULL, - 0xffffffff, - 0, - "conn", - NULL, - (struct sockaddr *)&sconn, - 0, - 0); -} - -void -usrsctp_deregister_address(void *addr) -{ - struct sockaddr_conn sconn; - - memset(&sconn, 0, sizeof(struct sockaddr_conn)); - sconn.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - sconn.sconn_len = sizeof(struct sockaddr_conn); -#endif - sconn.sconn_port = 0; - sconn.sconn_addr = addr; - sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, - (struct sockaddr *)&sconn, - 0xffffffff, - "conn"); -} - -#define PREAMBLE_FORMAT "\n%c %02d:%02d:%02d.%06ld " -#define PREAMBLE_LENGTH 19 -#define HEADER "0000 " -#define TRAILER "# SCTP_PACKET\n" - -char * -usrsctp_dumppacket(const void *buf, size_t len, int outbound) -{ - size_t i, pos; - char *dump_buf, *packet; - struct tm t; -#ifdef _WIN32 - struct timeb tb; -#else - struct timeval tv; - time_t sec; -#endif - - if ((len == 0) || (buf == NULL)) { - return (NULL); - } - if ((dump_buf = malloc(PREAMBLE_LENGTH + strlen(HEADER) + 3 * len + strlen(TRAILER) + 1)) == NULL) { - return (NULL); - } - pos = 0; -#ifdef _WIN32 - ftime(&tb); - localtime_s(&t, &tb.time); -#if defined(__MINGW32__) - if (snprintf(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_FORMAT, - outbound ? 'O' : 'I', - t.tm_hour, t.tm_min, t.tm_sec, (long)(1000 * tb.millitm)) < 0) { - free(dump_buf); - return (NULL); - } -#else - if (_snprintf_s(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_LENGTH, PREAMBLE_FORMAT, - outbound ? 'O' : 'I', - t.tm_hour, t.tm_min, t.tm_sec, (long)(1000 * tb.millitm)) < 0) { - free(dump_buf); - return (NULL); - } -#endif -#else - gettimeofday(&tv, NULL); - sec = (time_t)tv.tv_sec; - localtime_r((const time_t *)&sec, &t); - if (snprintf(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_FORMAT, - outbound ? 'O' : 'I', - t.tm_hour, t.tm_min, t.tm_sec, (long)tv.tv_usec) < 0) { - free(dump_buf); - return (NULL); - } -#endif - pos += PREAMBLE_LENGTH; -#if defined(_WIN32) && !defined(__MINGW32__) - strncpy_s(dump_buf + pos, strlen(HEADER) + 1, HEADER, strlen(HEADER)); -#else - strcpy(dump_buf + pos, HEADER); -#endif - pos += strlen(HEADER); - packet = (char *)buf; - for (i = 0; i < len; i++) { - uint8_t byte, low, high; - - byte = (uint8_t)packet[i]; - high = byte / 16; - low = byte % 16; - dump_buf[pos++] = high < 10 ? '0' + high : 'a' + (high - 10); - dump_buf[pos++] = low < 10 ? '0' + low : 'a' + (low - 10); - dump_buf[pos++] = ' '; - } -#if defined(_WIN32) && !defined(__MINGW32__) - strncpy_s(dump_buf + pos, strlen(TRAILER) + 1, TRAILER, strlen(TRAILER)); -#else - strcpy(dump_buf + pos, TRAILER); -#endif - pos += strlen(TRAILER); - dump_buf[pos++] = '\0'; - return (dump_buf); -} - -void -usrsctp_freedumpbuffer(char *buf) -{ - free(buf); -} - -void -usrsctp_enable_crc32c_offload(void) -{ - SCTP_BASE_VAR(crc32c_offloaded) = 1; -} - -void -usrsctp_disable_crc32c_offload(void) -{ - SCTP_BASE_VAR(crc32c_offloaded) = 0; -} - -/* Compute the CRC32C in network byte order */ -uint32_t -usrsctp_crc32c(void *buffer, size_t length) -{ - uint32_t base = 0xffffffff; - - base = calculate_crc32c(0xffffffff, (unsigned char *)buffer, (unsigned int) length); - base = sctp_finalize_crc32c(base); - return (base); -} - -void -usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bits) -{ - struct sockaddr_conn src, dst; - struct mbuf *m, *mm; - struct sctphdr *sh; - struct sctp_chunkhdr *ch; - int remaining, offset; - - SCTP_STAT_INCR(sctps_recvpackets); - SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - memset(&src, 0, sizeof(struct sockaddr_conn)); - src.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - src.sconn_len = sizeof(struct sockaddr_conn); -#endif - src.sconn_addr = addr; - memset(&dst, 0, sizeof(struct sockaddr_conn)); - dst.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - dst.sconn_len = sizeof(struct sockaddr_conn); -#endif - dst.sconn_addr = addr; - if ((m = sctp_get_mbuf_for_msg((unsigned int)length, 1, M_NOWAIT, 0, MT_DATA)) == NULL) { - return; - } - /* Set the lengths fields of the mbuf chain. - * This is expected by m_copyback(). - */ - remaining = (int)length; - for (mm = m; mm != NULL; mm = mm->m_next) { - mm->m_len = min((int)M_SIZE(mm), remaining); - m->m_pkthdr.len += mm->m_len; - remaining -= mm->m_len; - } - KASSERT(remaining == 0, ("usrsctp_conninput: %zu bytes left", remaining)); - m_copyback(m, 0, (int)length, (caddr_t)buffer); - offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - if (SCTP_BUF_LEN(m) < offset) { - if ((m = m_pullup(m, offset)) == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - return; - } - } - sh = mtod(m, struct sctphdr *); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); - offset -= sizeof(struct sctp_chunkhdr); - src.sconn_port = sh->src_port; - dst.sconn_port = sh->dest_port; - sctp_common_input_processing(&m, 0, offset, (int)length, - (struct sockaddr *)&src, - (struct sockaddr *)&dst, - sh, ch, - SCTP_BASE_VAR(crc32c_offloaded) == 1 ? 0 : 1, - ecn_bits, - SCTP_DEFAULT_VRFID, 0); - if (m) { - sctp_m_freem(m); - } - return; -} - -void usrsctp_handle_timers(uint32_t elapsed_milliseconds) -{ - sctp_handle_tick(sctp_msecs_to_ticks(elapsed_milliseconds)); -} - -int -usrsctp_get_events(struct socket *so) -{ - int events = 0; - - if (so == NULL) { - errno = EBADF; - return -1; - } - - SOCK_LOCK(so); - if (soreadable(so)) { - events |= SCTP_EVENT_READ; - } - if (sowriteable(so)) { - events |= SCTP_EVENT_WRITE; - } - if (so->so_error) { - events |= SCTP_EVENT_ERROR; - } - SOCK_UNLOCK(so); - - return events; -} - -int -usrsctp_set_upcall(struct socket *so, void (*upcall)(struct socket *, void *, int), void *arg) -{ - if (so == NULL) { - errno = EBADF; - return (-1); - } - - SOCK_LOCK(so); - so->so_upcall = upcall; - so->so_upcallarg = arg; - so->so_snd.sb_flags |= SB_UPCALL; - so->so_rcv.sb_flags |= SB_UPCALL; - SOCK_UNLOCK(so); - - return (0); -} - -#define USRSCTP_TUNABLE_SET_DEF(__field, __prefix) \ -int usrsctp_tunable_set_ ## __field(uint32_t value) \ -{ \ - if ((value < __prefix##_MIN) || \ - (value > __prefix##_MAX)) { \ - errno = EINVAL; \ - return (-1); \ - } else { \ - SCTP_BASE_SYSCTL(__field) = value; \ - return (0); \ - } \ -} - -USRSCTP_TUNABLE_SET_DEF(sctp_hashtblsize, SCTPCTL_TCBHASHSIZE) -USRSCTP_TUNABLE_SET_DEF(sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE) -USRSCTP_TUNABLE_SET_DEF(sctp_chunkscale, SCTPCTL_CHUNKSCALE) - -#define USRSCTP_SYSCTL_SET_DEF(__field, __prefix) \ -int usrsctp_sysctl_set_ ## __field(uint32_t value) \ -{ \ - if ((value < __prefix##_MIN) || \ - (value > __prefix##_MAX)) { \ - errno = EINVAL; \ - return (-1); \ - } else { \ - SCTP_BASE_SYSCTL(__field) = value; \ - return (0); \ - } \ -} - -#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" -#endif -USRSCTP_SYSCTL_SET_DEF(sctp_sendspace, SCTPCTL_MAXDGRAM) -USRSCTP_SYSCTL_SET_DEF(sctp_recvspace, SCTPCTL_RECVSPACE) -USRSCTP_SYSCTL_SET_DEF(sctp_auto_asconf, SCTPCTL_AUTOASCONF) -USRSCTP_SYSCTL_SET_DEF(sctp_ecn_enable, SCTPCTL_ECN_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_pr_enable, SCTPCTL_PR_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_auth_enable, SCTPCTL_AUTH_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_asconf_enable, SCTPCTL_ASCONF_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_reconfig_enable, SCTPCTL_RECONFIG_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_nrsack_enable, SCTPCTL_NRSACK_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_pktdrop_enable, SCTPCTL_PKTDROP_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM) -USRSCTP_SYSCTL_SET_DEF(sctp_peer_chunk_oh, SCTPCTL_PEER_CHKOH) -USRSCTP_SYSCTL_SET_DEF(sctp_max_burst_default, SCTPCTL_MAXBURST) -USRSCTP_SYSCTL_SET_DEF(sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS) -USRSCTP_SYSCTL_SET_DEF(sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT) -USRSCTP_SYSCTL_SET_DEF(sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME) -USRSCTP_SYSCTL_SET_DEF(sctp_sack_freq_default, SCTPCTL_SACK_FREQ) -USRSCTP_SYSCTL_SET_DEF(sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE) -USRSCTP_SYSCTL_SET_DEF(sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE) -USRSCTP_SYSCTL_SET_DEF(sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL) -USRSCTP_SYSCTL_SET_DEF(sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME) -USRSCTP_SYSCTL_SET_DEF(sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME) -USRSCTP_SYSCTL_SET_DEF(sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME) -USRSCTP_SYSCTL_SET_DEF(sctp_rto_max_default, SCTPCTL_RTO_MAX) -USRSCTP_SYSCTL_SET_DEF(sctp_rto_min_default, SCTPCTL_RTO_MIN) -USRSCTP_SYSCTL_SET_DEF(sctp_rto_initial_default, SCTPCTL_RTO_INITIAL) -USRSCTP_SYSCTL_SET_DEF(sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX) -USRSCTP_SYSCTL_SET_DEF(sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE) -USRSCTP_SYSCTL_SET_DEF(sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX) -USRSCTP_SYSCTL_SET_DEF(sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX) -USRSCTP_SYSCTL_SET_DEF(sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX) -USRSCTP_SYSCTL_SET_DEF(sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT) -USRSCTP_SYSCTL_SET_DEF(sctp_nr_incoming_streams_default, SCTPCTL_INCOMING_STREAMS) -USRSCTP_SYSCTL_SET_DEF(sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS) -USRSCTP_SYSCTL_SET_DEF(sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF) -USRSCTP_SYSCTL_SET_DEF(sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC) -USRSCTP_SYSCTL_SET_DEF(sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST) -USRSCTP_SYSCTL_SET_DEF(sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY) -USRSCTP_SYSCTL_SET_DEF(sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR) -USRSCTP_SYSCTL_SET_DEF(sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS) -USRSCTP_SYSCTL_SET_DEF(sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN) -USRSCTP_SYSCTL_SET_DEF(sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST) -USRSCTP_SYSCTL_SET_DEF(sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT) -USRSCTP_SYSCTL_SET_DEF(sctp_min_residual, SCTPCTL_MIN_RESIDUAL) -USRSCTP_SYSCTL_SET_DEF(sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK) -USRSCTP_SYSCTL_SET_DEF(sctp_logging_level, SCTPCTL_LOGGING_LEVEL) -USRSCTP_SYSCTL_SET_DEF(sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE) -USRSCTP_SYSCTL_SET_DEF(sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE) -USRSCTP_SYSCTL_SET_DEF(sctp_mobility_base, SCTPCTL_MOBILITY_BASE) -USRSCTP_SYSCTL_SET_DEF(sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF) -USRSCTP_SYSCTL_SET_DEF(sctp_inits_include_nat_friendly, SCTPCTL_NAT_FRIENDLY_INITS) -USRSCTP_SYSCTL_SET_DEF(sctp_udp_tunneling_port, SCTPCTL_UDP_TUNNELING_PORT) -USRSCTP_SYSCTL_SET_DEF(sctp_enable_sack_immediately, SCTPCTL_SACK_IMMEDIATELY_ENABLE) -USRSCTP_SYSCTL_SET_DEF(sctp_vtag_time_wait, SCTPCTL_TIME_WAIT) -USRSCTP_SYSCTL_SET_DEF(sctp_blackhole, SCTPCTL_BLACKHOLE) -USRSCTP_SYSCTL_SET_DEF(sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE) -USRSCTP_SYSCTL_SET_DEF(sctp_fr_max_burst_default, SCTPCTL_FRMAXBURST) -USRSCTP_SYSCTL_SET_DEF(sctp_path_pf_threshold, SCTPCTL_PATH_PF_THRESHOLD) -USRSCTP_SYSCTL_SET_DEF(sctp_default_ss_module, SCTPCTL_DEFAULT_SS_MODULE) -USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_bw, SCTPCTL_RTTVAR_BW) -USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_rtt, SCTPCTL_RTTVAR_RTT) -USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_eqret, SCTPCTL_RTTVAR_EQRET) -USRSCTP_SYSCTL_SET_DEF(sctp_steady_step, SCTPCTL_RTTVAR_STEADYS) -USRSCTP_SYSCTL_SET_DEF(sctp_use_dccc_ecn, SCTPCTL_RTTVAR_DCCCECN) -USRSCTP_SYSCTL_SET_DEF(sctp_buffer_splitting, SCTPCTL_BUFFER_SPLITTING) -USRSCTP_SYSCTL_SET_DEF(sctp_initial_cwnd, SCTPCTL_INITIAL_CWND) -#ifdef SCTP_DEBUG -USRSCTP_SYSCTL_SET_DEF(sctp_debug_on, SCTPCTL_DEBUG) -#endif -#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#define USRSCTP_SYSCTL_GET_DEF(__field) \ -uint32_t usrsctp_sysctl_get_ ## __field(void) { \ - return SCTP_BASE_SYSCTL(__field); \ -} - -USRSCTP_SYSCTL_GET_DEF(sctp_sendspace) -USRSCTP_SYSCTL_GET_DEF(sctp_recvspace) -USRSCTP_SYSCTL_GET_DEF(sctp_auto_asconf) -USRSCTP_SYSCTL_GET_DEF(sctp_multiple_asconfs) -USRSCTP_SYSCTL_GET_DEF(sctp_ecn_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_pr_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_auth_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_asconf_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_reconfig_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_nrsack_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_pktdrop_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_no_csum_on_loopback) -USRSCTP_SYSCTL_GET_DEF(sctp_peer_chunk_oh) -USRSCTP_SYSCTL_GET_DEF(sctp_max_burst_default) -USRSCTP_SYSCTL_GET_DEF(sctp_max_chunks_on_queue) -USRSCTP_SYSCTL_GET_DEF(sctp_hashtblsize) -USRSCTP_SYSCTL_GET_DEF(sctp_pcbtblsize) -USRSCTP_SYSCTL_GET_DEF(sctp_min_split_point) -USRSCTP_SYSCTL_GET_DEF(sctp_chunkscale) -USRSCTP_SYSCTL_GET_DEF(sctp_delayed_sack_time_default) -USRSCTP_SYSCTL_GET_DEF(sctp_sack_freq_default) -USRSCTP_SYSCTL_GET_DEF(sctp_system_free_resc_limit) -USRSCTP_SYSCTL_GET_DEF(sctp_asoc_free_resc_limit) -USRSCTP_SYSCTL_GET_DEF(sctp_heartbeat_interval_default) -USRSCTP_SYSCTL_GET_DEF(sctp_pmtu_raise_time_default) -USRSCTP_SYSCTL_GET_DEF(sctp_shutdown_guard_time_default) -USRSCTP_SYSCTL_GET_DEF(sctp_secret_lifetime_default) -USRSCTP_SYSCTL_GET_DEF(sctp_rto_max_default) -USRSCTP_SYSCTL_GET_DEF(sctp_rto_min_default) -USRSCTP_SYSCTL_GET_DEF(sctp_rto_initial_default) -USRSCTP_SYSCTL_GET_DEF(sctp_init_rto_max_default) -USRSCTP_SYSCTL_GET_DEF(sctp_valid_cookie_life_default) -USRSCTP_SYSCTL_GET_DEF(sctp_init_rtx_max_default) -USRSCTP_SYSCTL_GET_DEF(sctp_assoc_rtx_max_default) -USRSCTP_SYSCTL_GET_DEF(sctp_path_rtx_max_default) -USRSCTP_SYSCTL_GET_DEF(sctp_add_more_threshold) -USRSCTP_SYSCTL_GET_DEF(sctp_nr_incoming_streams_default) -USRSCTP_SYSCTL_GET_DEF(sctp_nr_outgoing_streams_default) -USRSCTP_SYSCTL_GET_DEF(sctp_cmt_on_off) -USRSCTP_SYSCTL_GET_DEF(sctp_cmt_use_dac) -USRSCTP_SYSCTL_GET_DEF(sctp_use_cwnd_based_maxburst) -USRSCTP_SYSCTL_GET_DEF(sctp_nat_friendly) -USRSCTP_SYSCTL_GET_DEF(sctp_L2_abc_variable) -USRSCTP_SYSCTL_GET_DEF(sctp_mbuf_threshold_count) -USRSCTP_SYSCTL_GET_DEF(sctp_do_drain) -USRSCTP_SYSCTL_GET_DEF(sctp_hb_maxburst) -USRSCTP_SYSCTL_GET_DEF(sctp_abort_if_one_2_one_hits_limit) -USRSCTP_SYSCTL_GET_DEF(sctp_min_residual) -USRSCTP_SYSCTL_GET_DEF(sctp_max_retran_chunk) -USRSCTP_SYSCTL_GET_DEF(sctp_logging_level) -USRSCTP_SYSCTL_GET_DEF(sctp_default_cc_module) -USRSCTP_SYSCTL_GET_DEF(sctp_default_frag_interleave) -USRSCTP_SYSCTL_GET_DEF(sctp_mobility_base) -USRSCTP_SYSCTL_GET_DEF(sctp_mobility_fasthandoff) -USRSCTP_SYSCTL_GET_DEF(sctp_inits_include_nat_friendly) -USRSCTP_SYSCTL_GET_DEF(sctp_udp_tunneling_port) -USRSCTP_SYSCTL_GET_DEF(sctp_enable_sack_immediately) -USRSCTP_SYSCTL_GET_DEF(sctp_vtag_time_wait) -USRSCTP_SYSCTL_GET_DEF(sctp_blackhole) -USRSCTP_SYSCTL_GET_DEF(sctp_diag_info_code) -USRSCTP_SYSCTL_GET_DEF(sctp_fr_max_burst_default) -USRSCTP_SYSCTL_GET_DEF(sctp_path_pf_threshold) -USRSCTP_SYSCTL_GET_DEF(sctp_default_ss_module) -USRSCTP_SYSCTL_GET_DEF(sctp_rttvar_bw) -USRSCTP_SYSCTL_GET_DEF(sctp_rttvar_rtt) -USRSCTP_SYSCTL_GET_DEF(sctp_rttvar_eqret) -USRSCTP_SYSCTL_GET_DEF(sctp_steady_step) -USRSCTP_SYSCTL_GET_DEF(sctp_use_dccc_ecn) -USRSCTP_SYSCTL_GET_DEF(sctp_buffer_splitting) -USRSCTP_SYSCTL_GET_DEF(sctp_initial_cwnd) -#ifdef SCTP_DEBUG -USRSCTP_SYSCTL_GET_DEF(sctp_debug_on) -#endif - -void usrsctp_get_stat(struct sctpstat *stat) -{ - *stat = SCTP_BASE_STATS; -} diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socketvar.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socketvar.h deleted file mode 100644 index e8eccc7f..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_socketvar.h +++ /dev/null @@ -1,527 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* __Userspace__ version of goes here.*/ - -#ifndef _USER_SOCKETVAR_H_ -#define _USER_SOCKETVAR_H_ - -#if defined(__APPLE__) -#include -#include -#endif - -/* #include */ /*__Userspace__ alternative?*/ /* for struct selinfo */ -/* #include was 0 byte file */ -/* #include was 0 byte file */ -/* #include */ /*__Userspace__ alternative?*/ -#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(_WIN32) && !defined(__native_client__) -#include -#endif -#define SOCK_MAXADDRLEN 255 -#if !defined(MSG_NOTIFICATION) -#define MSG_NOTIFICATION 0x2000 /* SCTP notification */ -#endif -#define SCTP_SO_LINGER 0x0001 -#define SCTP_SO_ACCEPTCONN 0x0002 -#define SS_CANTRCVMORE 0x020 -#define SS_CANTSENDMORE 0x010 - -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(_WIN32) || defined(__native_client__) -#define UIO_MAXIOV 1024 -#define ERESTART (-1) -#endif - -#if !defined(__APPLE__) && !defined(__NetBSD__) && !defined(__OpenBSD__) -enum uio_rw { UIO_READ, UIO_WRITE }; -#endif - -#if !defined(__NetBSD__) && !defined(__OpenBSD__) -/* Segment flag values. */ -enum uio_seg { - UIO_USERSPACE, /* from user data space */ - UIO_SYSSPACE /* from system space */ -}; -#endif - -struct proc { - int stub; /* struct proc is a dummy for __Userspace__ */ -}; - -MALLOC_DECLARE(M_ACCF); -MALLOC_DECLARE(M_PCB); -MALLOC_DECLARE(M_SONAME); - -/* __Userspace__ Are these all the fields we need? - * Removing struct thread *uio_td; owner field -*/ -struct uio { - struct iovec *uio_iov; /* scatter/gather list */ - int uio_iovcnt; /* length of scatter/gather list */ - off_t uio_offset; /* offset in target object */ - ssize_t uio_resid; /* remaining bytes to process */ - enum uio_seg uio_segflg; /* address space */ - enum uio_rw uio_rw; /* operation */ -}; - - -/* __Userspace__ */ - -/* - * Kernel structure per socket. - * Contains send and receive buffer queues, - * handle on protocol and pointer to protocol - * private data and error information. - */ -#if defined(_WIN32) -#define AF_ROUTE 17 -#if !defined(__MINGW32__) -typedef __int32 pid_t; -#endif -typedef unsigned __int32 uid_t; -enum sigType { - SIGNAL = 0, - BROADCAST = 1, - MAX_EVENTS = 2 -}; -#endif - -/*- - * Locking key to struct socket: - * (a) constant after allocation, no locking required. - * (b) locked by SOCK_LOCK(so). - * (c) locked by SOCKBUF_LOCK(&so->so_rcv). - * (d) locked by SOCKBUF_LOCK(&so->so_snd). - * (e) locked by ACCEPT_LOCK(). - * (f) not locked since integer reads/writes are atomic. - * (g) used only as a sleep/wakeup address, no value. - * (h) locked by global mutex so_global_mtx. - */ -struct socket { - int so_count; /* (b) reference count */ - short so_type; /* (a) generic type, see socket.h */ - short so_options; /* from socket call, see socket.h */ - short so_linger; /* time to linger while closing */ - short so_state; /* (b) internal state flags SS_* */ - int so_qstate; /* (e) internal state flags SQ_* */ - void *so_pcb; /* protocol control block */ - int so_dom; -/* - * Variables for connection queuing. - * Socket where accepts occur is so_head in all subsidiary sockets. - * If so_head is 0, socket is not related to an accept. - * For head socket so_incomp queues partially completed connections, - * while so_comp is a queue of connections ready to be accepted. - * If a connection is aborted and it has so_head set, then - * it has to be pulled out of either so_incomp or so_comp. - * We allow connections to queue up based on current queue lengths - * and limit on number of queued connections for this socket. - */ - struct socket *so_head; /* (e) back pointer to listen socket */ - TAILQ_HEAD(, socket) so_incomp; /* (e) queue of partial unaccepted connections */ - TAILQ_HEAD(, socket) so_comp; /* (e) queue of complete unaccepted connections */ - TAILQ_ENTRY(socket) so_list; /* (e) list of unaccepted connections */ - u_short so_qlen; /* (e) number of unaccepted connections */ - u_short so_incqlen; /* (e) number of unaccepted incomplete - connections */ - u_short so_qlimit; /* (e) max number queued connections */ - short so_timeo; /* (g) connection timeout */ - userland_cond_t timeo_cond; /* timeo_cond condition variable being used in wakeup */ - - u_short so_error; /* (f) error affecting connection */ - struct sigio *so_sigio; /* [sg] information for async I/O or - out of band data (SIGURG) */ - u_long so_oobmark; /* (c) chars to oob mark */ - TAILQ_HEAD(, aiocblist) so_aiojobq; /* AIO ops waiting on socket */ -/* - * Variables for socket buffering. - */ - struct sockbuf { - /* __Userspace__ Many of these fields may - * not be required for the sctp stack. - * Commenting out the following. - * Including pthread mutex and condition variable to be - * used by sbwait, sorwakeup and sowwakeup. - */ - /* struct selinfo sb_sel;*/ /* process selecting read/write */ - /* struct mtx sb_mtx;*/ /* sockbuf lock */ - /* struct sx sb_sx;*/ /* prevent I/O interlacing */ - userland_cond_t sb_cond; /* sockbuf condition variable */ - userland_mutex_t sb_mtx; /* sockbuf lock associated with sb_cond */ - short sb_state; /* (c/d) socket state on sockbuf */ -#define sb_startzero sb_mb - struct mbuf *sb_mb; /* (c/d) the mbuf chain */ - struct mbuf *sb_mbtail; /* (c/d) the last mbuf in the chain */ - struct mbuf *sb_lastrecord; /* (c/d) first mbuf of last - * record in socket buffer */ - struct mbuf *sb_sndptr; /* (c/d) pointer into mbuf chain */ - u_int sb_sndptroff; /* (c/d) byte offset of ptr into chain */ - u_int sb_cc; /* (c/d) actual chars in buffer */ - u_int sb_hiwat; /* (c/d) max actual char count */ - u_int sb_mbcnt; /* (c/d) chars of mbufs used */ - u_int sb_mbmax; /* (c/d) max chars of mbufs to use */ - u_int sb_ctl; /* (c/d) non-data chars in buffer */ - int sb_lowat; /* (c/d) low water mark */ - int sb_timeo; /* (c/d) timeout for read/write */ - short sb_flags; /* (c/d) flags, see below */ - } so_rcv, so_snd; -/* - * Constants for sb_flags field of struct sockbuf. - */ -#define SB_MAX (256*1024) /* default for max chars in sockbuf */ -#define SB_RAW (64*1024*2) /*Aligning so->so_rcv.sb_hiwat with the receive buffer size of raw socket*/ -/* - * Constants for sb_flags field of struct sockbuf. - */ -#define SB_WAIT 0x04 /* someone is waiting for data/space */ -#define SB_SEL 0x08 /* someone is selecting */ -#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ -#define SB_UPCALL 0x20 /* someone wants an upcall */ -#define SB_NOINTR 0x40 /* operations not interruptible */ -#define SB_AIO 0x80 /* AIO operations queued */ -#define SB_KNOTE 0x100 /* kernel note attached */ -#define SB_AUTOSIZE 0x800 /* automatically size socket buffer */ - - void (*so_upcall)(struct socket *, void *, int); - void *so_upcallarg; - struct ucred *so_cred; /* (a) user credentials */ - struct label *so_label; /* (b) MAC label for socket */ - struct label *so_peerlabel; /* (b) cached MAC label for peer */ - /* NB: generation count must not be first. */ - uint32_t so_gencnt; /* (h) generation count */ - void *so_emuldata; /* (b) private data for emulators */ - struct so_accf { - struct accept_filter *so_accept_filter; - void *so_accept_filter_arg; /* saved filter args */ - char *so_accept_filter_str; /* saved user args */ - } *so_accf; -}; - -#define SB_EMPTY_FIXUP(sb) do { \ - if ((sb)->sb_mb == NULL) { \ - (sb)->sb_mbtail = NULL; \ - (sb)->sb_lastrecord = NULL; \ - } \ -} while (/*CONSTCOND*/0) - -/* - * Global accept mutex to serialize access to accept queues and - * fields associated with multiple sockets. This allows us to - * avoid defining a lock order between listen and accept sockets - * until such time as it proves to be a good idea. - */ -#if defined(_WIN32) -extern userland_mutex_t accept_mtx; -extern userland_cond_t accept_cond; -#define ACCEPT_LOCK_ASSERT() -#define ACCEPT_LOCK() do { \ - EnterCriticalSection(&accept_mtx); \ -} while (0) -#define ACCEPT_UNLOCK() do { \ - LeaveCriticalSection(&accept_mtx); \ -} while (0) -#define ACCEPT_UNLOCK_ASSERT() -#else -extern userland_mutex_t accept_mtx; - -extern userland_cond_t accept_cond; -#ifdef INVARIANTS -#define ACCEPT_LOCK() KASSERT(pthread_mutex_lock(&accept_mtx) == 0, ("%s: accept_mtx already locked", __func__)) -#define ACCEPT_UNLOCK() KASSERT(pthread_mutex_unlock(&accept_mtx) == 0, ("%s: accept_mtx not locked", __func__)) -#else -#define ACCEPT_LOCK() (void)pthread_mutex_lock(&accept_mtx) -#define ACCEPT_UNLOCK() (void)pthread_mutex_unlock(&accept_mtx) -#endif -#define ACCEPT_LOCK_ASSERT() \ - KASSERT(pthread_mutex_trylock(&accept_mtx) == EBUSY, ("%s: accept_mtx not locked", __func__)) -#define ACCEPT_UNLOCK_ASSERT() do { \ - KASSERT(pthread_mutex_trylock(&accept_mtx) == 0, ("%s: accept_mtx locked", __func__)); \ - (void)pthread_mutex_unlock(&accept_mtx); \ - } while (0) -#endif - -/* - * Per-socket buffer mutex used to protect most fields in the socket - * buffer. - */ -#define SOCKBUF_MTX(_sb) (&(_sb)->sb_mtx) -#if defined(_WIN32) -#define SOCKBUF_LOCK_INIT(_sb, _name) \ - InitializeCriticalSection(SOCKBUF_MTX(_sb)) -#define SOCKBUF_LOCK_DESTROY(_sb) DeleteCriticalSection(SOCKBUF_MTX(_sb)) -#define SOCKBUF_COND_INIT(_sb) InitializeConditionVariable((&(_sb)->sb_cond)) -#define SOCKBUF_COND_DESTROY(_sb) DeleteConditionVariable((&(_sb)->sb_cond)) -#define SOCK_COND_INIT(_so) InitializeConditionVariable((&(_so)->timeo_cond)) -#define SOCK_COND_DESTROY(_so) DeleteConditionVariable((&(_so)->timeo_cond)) -#define SOCK_COND(_so) (&(_so)->timeo_cond) -#else -#ifdef INVARIANTS -#define SOCKBUF_LOCK_INIT(_sb, _name) do { \ - pthread_mutexattr_t mutex_attr; \ - \ - pthread_mutexattr_init(&mutex_attr); \ - pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK); \ - pthread_mutex_init(SOCKBUF_MTX(_sb), &mutex_attr); \ - pthread_mutexattr_destroy(&mutex_attr); \ -} while (0) -#else -#define SOCKBUF_LOCK_INIT(_sb, _name) \ - pthread_mutex_init(SOCKBUF_MTX(_sb), NULL) -#endif -#define SOCKBUF_LOCK_DESTROY(_sb) pthread_mutex_destroy(SOCKBUF_MTX(_sb)) -#define SOCKBUF_COND_INIT(_sb) pthread_cond_init((&(_sb)->sb_cond), NULL) -#define SOCKBUF_COND_DESTROY(_sb) pthread_cond_destroy((&(_sb)->sb_cond)) -#define SOCK_COND_INIT(_so) pthread_cond_init((&(_so)->timeo_cond), NULL) -#define SOCK_COND_DESTROY(_so) pthread_cond_destroy((&(_so)->timeo_cond)) -#define SOCK_COND(_so) (&(_so)->timeo_cond) -#endif -/*__Userspace__ SOCKBUF_LOCK(_sb) is now defined in netinet/sctp_process_lock.h */ - -/* #define SOCKBUF_OWNED(_sb) mtx_owned(SOCKBUF_MTX(_sb)) unused */ -/*__Userspace__ SOCKBUF_UNLOCK(_sb) is now defined in netinet/sctp_process_lock.h */ - -/*__Userspace__ SOCKBUF_LOCK_ASSERT(_sb) is now defined in netinet/sctp_process_lock.h */ - -/* #define SOCKBUF_UNLOCK_ASSERT(_sb) mtx_assert(SOCKBUF_MTX(_sb), MA_NOTOWNED) unused */ - -/* - * Per-socket mutex: we reuse the receive socket buffer mutex for space - * efficiency. This decision should probably be revisited as we optimize - * locking for the socket code. - */ -#define SOCK_MTX(_so) SOCKBUF_MTX(&(_so)->so_rcv) -/*__Userspace__ SOCK_LOCK(_so) is now defined in netinet/sctp_process_lock.h */ - -/* #define SOCK_OWNED(_so) SOCKBUF_OWNED(&(_so)->so_rcv) unused */ -/*__Userspace__ SOCK_UNLOCK(_so) is now defined in netinet/sctp_process_lock.h */ - -#define SOCK_LOCK_ASSERT(_so) SOCKBUF_LOCK_ASSERT(&(_so)->so_rcv) - -/* - * Socket state bits. - * - * Historically, this bits were all kept in the so_state field. For - * locking reasons, they are now in multiple fields, as they are - * locked differently. so_state maintains basic socket state protected - * by the socket lock. so_qstate holds information about the socket - * accept queues. Each socket buffer also has a state field holding - * information relevant to that socket buffer (can't send, rcv). Many - * fields will be read without locks to improve performance and avoid - * lock order issues. However, this approach must be used with caution. - */ -#define SS_NOFDREF 0x0001 /* no file table ref any more */ -#define SS_ISCONNECTED 0x0002 /* socket connected to a peer */ -#define SS_ISCONNECTING 0x0004 /* in process of connecting to peer */ -#define SS_ISDISCONNECTING 0x0008 /* in process of disconnecting */ -#define SS_NBIO 0x0100 /* non-blocking ops */ -#define SS_ASYNC 0x0200 /* async i/o notify */ -#define SS_ISCONFIRMING 0x0400 /* deciding to accept connection req */ -#define SS_ISDISCONNECTED 0x2000 /* socket disconnected from peer */ -/* - * Protocols can mark a socket as SS_PROTOREF to indicate that, following - * pru_detach, they still want the socket to persist, and will free it - * themselves when they are done. Protocols should only ever call sofree() - * following setting this flag in pru_detach(), and never otherwise, as - * sofree() bypasses socket reference counting. - */ -#define SS_PROTOREF 0x4000 /* strong protocol reference */ - -/* - * Socket state bits now stored in the socket buffer state field. - */ -#define SBS_CANTSENDMORE 0x0010 /* can't send more data to peer */ -#define SBS_CANTRCVMORE 0x0020 /* can't receive more data from peer */ -#define SBS_RCVATMARK 0x0040 /* at mark on input */ - -/* - * Socket state bits stored in so_qstate. - */ -#define SQ_INCOMP 0x0800 /* unaccepted, incomplete connection */ -#define SQ_COMP 0x1000 /* unaccepted, complete connection */ - -/* - * Socket event flags - */ -#define SCTP_EVENT_READ 0x0001 /* socket is readable */ -#define SCTP_EVENT_WRITE 0x0002 /* socket is writeable */ -#define SCTP_EVENT_ERROR 0x0004 /* socket has an error state */ - - -/*-------------------------------------------------------------*/ -/*-------------------------------------------------------------*/ -/* __Userspace__ */ -/*-------------------------------------------------------------*/ -/*-------------------------------------------------------------*/ -/* this new __Userspace__ section is to copy portions of the _KERNEL block - * above into, avoiding having to port the entire thing at once... - * For function prototypes, the full bodies are in user_socket.c . - */ - -/* ---------------------------------------------------------- */ -/* --- function prototypes (implemented in user_socket.c) --- */ -/* ---------------------------------------------------------- */ -void soisconnecting(struct socket *so); -void soisdisconnecting(struct socket *so); -void soisconnected(struct socket *so); -struct socket * sonewconn(struct socket *head, int connstatus); -void socantrcvmore(struct socket *so); -void socantsendmore(struct socket *so); -void sofree(struct socket *so); - - - -/* -------------- */ -/* --- macros --- */ -/* -------------- */ - -#define soref(so) do { \ - SOCK_LOCK_ASSERT(so); \ - ++(so)->so_count; \ -} while (0) - -#define sorele(so) do { \ - ACCEPT_LOCK_ASSERT(); \ - SOCK_LOCK_ASSERT(so); \ - KASSERT((so)->so_count > 0, ("sorele")); \ - if (--(so)->so_count == 0) \ - sofree(so); \ - else { \ - SOCK_UNLOCK(so); \ - ACCEPT_UNLOCK(); \ - } \ -} while (0) - - -/* replacing imin with min (user_environment.h) */ -#define sbspace(sb) \ - ((long) min((int)((sb)->sb_hiwat - (sb)->sb_cc), \ - (int)((sb)->sb_mbmax - (sb)->sb_mbcnt))) - -/* do we have to send all at once on a socket? */ -#define sosendallatonce(so) \ - ((so)->so_proto->pr_flags & PR_ATOMIC) - -/* can we read something from so? */ -#define soreadable(so) \ - ((int)((so)->so_rcv.sb_cc) >= (so)->so_rcv.sb_lowat || \ - ((so)->so_rcv.sb_state & SBS_CANTRCVMORE) || \ - !TAILQ_EMPTY(&(so)->so_comp) || (so)->so_error) - -#if 0 /* original */ -#define PR_CONNREQUIRED 0x04 /* from sys/protosw.h "needed" for sowriteable */ -#define sowriteable(so) \ - ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat && \ - (((so)->so_state&SS_ISCONNECTED) || \ - ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0)) || \ - ((so)->so_snd.sb_state & SBS_CANTSENDMORE) || \ - (so)->so_error) -#else /* line with PR_CONNREQUIRED removed */ -/* can we write something to so? */ -#define sowriteable(so) \ - ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat && \ - (((so)->so_state&SS_ISCONNECTED))) || \ - ((so)->so_snd.sb_state & SBS_CANTSENDMORE) || \ - (so)->so_error) -#endif - -extern void solisten_proto(struct socket *so, int backlog); -extern int solisten_proto_check(struct socket *so); -extern int sctp_listen(struct socket *so, int backlog, struct proc *p); -extern void socantrcvmore_locked(struct socket *so); -extern int sctp_bind(struct socket *so, struct sockaddr *addr); -extern int sctp6_bind(struct socket *so, struct sockaddr *addr, void *proc); -extern int sctpconn_bind(struct socket *so, struct sockaddr *addr); -extern int sctp_accept(struct socket *so, struct sockaddr **addr); -extern int sctp_attach(struct socket *so, int proto, uint32_t vrf_id); -extern int sctp6_attach(struct socket *so, int proto, uint32_t vrf_id); -extern int sctp_abort(struct socket *so); -extern int sctp6_abort(struct socket *so); -extern void sctp_close(struct socket *so); -extern int soaccept(struct socket *so, struct sockaddr **nam); -extern int solisten(struct socket *so, int backlog); -extern int soreserve(struct socket *so, u_long sndcc, u_long rcvcc); -extern void sowakeup(struct socket *so, struct sockbuf *sb); -extern void wakeup(void *ident, struct socket *so); /*__Userspace__ */ -extern int uiomove(void *cp, int n, struct uio *uio); -extern int sbwait(struct sockbuf *sb); -extern int sodisconnect(struct socket *so); -extern int soconnect(struct socket *so, struct sockaddr *nam); -extern int sctp_disconnect(struct socket *so); -extern int sctp_connect(struct socket *so, struct sockaddr *addr); -extern int sctp6_connect(struct socket *so, struct sockaddr *addr); -extern int sctpconn_connect(struct socket *so, struct sockaddr *addr); -extern void sctp_finish(void); - -/* ------------------------------------------------ */ -/* ----- macros copied from above ---- */ -/* ------------------------------------------------ */ - -/* - * Do we need to notify the other side when I/O is possible? - */ -#define sb_notify(sb) (((sb)->sb_flags & (SB_WAIT | SB_SEL | SB_ASYNC | \ - SB_UPCALL | SB_AIO | SB_KNOTE)) != 0) - - -/* - * In sorwakeup() and sowwakeup(), acquire the socket buffer lock to - * avoid a non-atomic test-and-wakeup. However, sowakeup is - * responsible for releasing the lock if it is called. We unlock only - * if we don't call into sowakeup. If any code is introduced that - * directly invokes the underlying sowakeup() primitives, it must - * maintain the same semantics. - */ -#define sorwakeup_locked(so) do { \ - SOCKBUF_LOCK_ASSERT(&(so)->so_rcv); \ - if (sb_notify(&(so)->so_rcv)) \ - sowakeup((so), &(so)->so_rcv); \ - else \ - SOCKBUF_UNLOCK(&(so)->so_rcv); \ -} while (0) - -#define sorwakeup(so) do { \ - SOCKBUF_LOCK(&(so)->so_rcv); \ - sorwakeup_locked(so); \ -} while (0) - -#define sowwakeup_locked(so) do { \ - SOCKBUF_LOCK_ASSERT(&(so)->so_snd); \ - if (sb_notify(&(so)->so_snd)) \ - sowakeup((so), &(so)->so_snd); \ - else \ - SOCKBUF_UNLOCK(&(so)->so_snd); \ -} while (0) - -#define sowwakeup(so) do { \ - SOCKBUF_LOCK(&(so)->so_snd); \ - sowwakeup_locked(so); \ -} while (0) - -#endif /* !_SYS_SOCKETVAR_H_ */ diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_uma.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_uma.h deleted file mode 100644 index 59d71fff..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_uma.h +++ /dev/null @@ -1,96 +0,0 @@ -/*- - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USER_UMA_H_ -#define _USER_UMA_H_ - -#define UMA_ZFLAG_FULL 0x40000000 /* Reached uz_maxpages */ -#define UMA_ALIGN_PTR (sizeof(void *) - 1) /* Alignment fit for ptr */ - -/* __Userspace__ All these definitions will change for -userspace Universal Memory Allocator (UMA). These are included -for reference purposes and to avoid compile errors for the time being. -*/ -typedef int (*uma_ctor)(void *mem, int size, void *arg, int flags); -typedef void (*uma_dtor)(void *mem, int size, void *arg); -typedef int (*uma_init)(void *mem, int size, int flags); -typedef void (*uma_fini)(void *mem, int size); -typedef struct uma_zone * uma_zone_t; -typedef struct uma_keg * uma_keg_t; - -struct uma_cache { - int stub; /* TODO __Userspace__ */ -}; - -struct uma_keg { - int stub; /* TODO __Userspace__ */ -}; - -struct uma_zone { - char *uz_name; /* Text name of the zone */ - struct mtx *uz_lock; /* Lock for the zone (keg's lock) */ - uma_keg_t uz_keg; /* Our underlying Keg */ - - LIST_ENTRY(uma_zone) uz_link; /* List of all zones in keg */ - LIST_HEAD(,uma_bucket) uz_full_bucket; /* full buckets */ - LIST_HEAD(,uma_bucket) uz_free_bucket; /* Buckets for frees */ - - uma_ctor uz_ctor; /* Constructor for each allocation */ - uma_dtor uz_dtor; /* Destructor */ - uma_init uz_init; /* Initializer for each item */ - uma_fini uz_fini; /* Discards memory */ - - u_int64_t uz_allocs; /* Total number of allocations */ - u_int64_t uz_frees; /* Total number of frees */ - u_int64_t uz_fails; /* Total number of alloc failures */ - uint16_t uz_fills; /* Outstanding bucket fills */ - uint16_t uz_count; /* Highest value ub_ptr can have */ - - /* - * This HAS to be the last item because we adjust the zone size - * based on NCPU and then allocate the space for the zones. - */ - struct uma_cache uz_cpu[1]; /* Per cpu caches */ -}; - -/* Prototype */ -uma_zone_t -uma_zcreate(char *name, size_t size, uma_ctor ctor, uma_dtor dtor, - uma_init uminit, uma_fini fini, int align, uint32_t flags); - - -#define uma_zone_set_max(zone, number) /* stub TODO __Userspace__ */ - -uma_zone_t -uma_zcreate(char *name, size_t size, uma_ctor ctor, uma_dtor dtor, - uma_init uminit, uma_fini fini, int align, uint32_t flags) { - return NULL; /* stub TODO __Userspace__. Also place implementation in a separate .c file */ -} -#endif diff --git a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/usrsctp.h b/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/usrsctp.h deleted file mode 100644 index 93e89b38..00000000 --- a/godot/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/usrsctp.h +++ /dev/null @@ -1,1329 +0,0 @@ -/*- - * Copyright (c) 2009-2010 Brad Penoff - * Copyright (c) 2009-2010 Humaira Kamal - * Copyright (c) 2011-2012 Irene Ruengeler - * Copyright (c) 2011-2012 Michael Tuexen - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __USRSCTP_H__ -#define __USRSCTP_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#ifdef _WIN32 -#ifdef _MSC_VER -#pragma warning(disable: 4200) -#endif -#include -#include -#else -#include -#include -#endif - -#ifndef MSG_NOTIFICATION -/* This definition MUST be in sync with usrsctplib/user_socketvar.h */ -#define MSG_NOTIFICATION 0x2000 -#endif - -#ifndef IPPROTO_SCTP -/* This is the IANA assigned protocol number of SCTP. */ -#define IPPROTO_SCTP 132 -#endif - -#ifdef _WIN32 -#if defined(_MSC_VER) && _MSC_VER >= 1600 -#include -#elif defined(SCTP_STDINT_INCLUDE) -#include SCTP_STDINT_INCLUDE -#else -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -#endif - -#ifndef ssize_t -#ifdef _WIN64 -typedef __int64 ssize_t; -#elif defined _WIN32 -typedef int ssize_t; -#else -#error "Unknown platform!" -#endif -#endif - -#define MSG_EOR 0x8 -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif -#define SHUT_RD 1 -#define SHUT_WR 2 -#define SHUT_RDWR 3 -#endif - -typedef uint32_t sctp_assoc_t; - -#if defined(_WIN32) && defined(_MSC_VER) -#pragma pack (push, 1) -#define SCTP_PACKED -#else -#define SCTP_PACKED __attribute__((packed)) -#endif - -struct sctp_common_header { - uint16_t source_port; - uint16_t destination_port; - uint32_t verification_tag; - uint32_t crc32c; -} SCTP_PACKED; - -#if defined(_WIN32) && defined(_MSC_VER) -#pragma pack(pop) -#endif -#undef SCTP_PACKED - -#define AF_CONN 123 -/* The definition of struct sockaddr_conn MUST be in - * tune with other sockaddr_* structures. - */ -#if defined(__APPLE__) || defined(__Bitrig__) || defined(__DragonFly__) || \ - defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) -struct sockaddr_conn { - uint8_t sconn_len; - uint8_t sconn_family; - uint16_t sconn_port; - void *sconn_addr; -}; -#else -struct sockaddr_conn { - uint16_t sconn_family; - uint16_t sconn_port; - void *sconn_addr; -}; -#endif - -union sctp_sockstore { - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - struct sockaddr_conn sconn; - struct sockaddr sa; -}; - -#define SCTP_FUTURE_ASSOC 0 -#define SCTP_CURRENT_ASSOC 1 -#define SCTP_ALL_ASSOC 2 - -#define SCTP_EVENT_READ 0x0001 -#define SCTP_EVENT_WRITE 0x0002 -#define SCTP_EVENT_ERROR 0x0004 - -/*** Structures and definitions to use the socket API ***/ - -#define SCTP_ALIGN_RESV_PAD 92 -#define SCTP_ALIGN_RESV_PAD_SHORT 76 - -struct sctp_rcvinfo { - uint16_t rcv_sid; - uint16_t rcv_ssn; - uint16_t rcv_flags; - uint32_t rcv_ppid; - uint32_t rcv_tsn; - uint32_t rcv_cumtsn; - uint32_t rcv_context; - sctp_assoc_t rcv_assoc_id; -}; - -struct sctp_nxtinfo { - uint16_t nxt_sid; - uint16_t nxt_flags; - uint32_t nxt_ppid; - uint32_t nxt_length; - sctp_assoc_t nxt_assoc_id; -}; - -#define SCTP_NO_NEXT_MSG 0x0000 -#define SCTP_NEXT_MSG_AVAIL 0x0001 -#define SCTP_NEXT_MSG_ISCOMPLETE 0x0002 -#define SCTP_NEXT_MSG_IS_UNORDERED 0x0004 -#define SCTP_NEXT_MSG_IS_NOTIFICATION 0x0008 - -struct sctp_recvv_rn { - struct sctp_rcvinfo recvv_rcvinfo; - struct sctp_nxtinfo recvv_nxtinfo; -}; - -#define SCTP_RECVV_NOINFO 0 -#define SCTP_RECVV_RCVINFO 1 -#define SCTP_RECVV_NXTINFO 2 -#define SCTP_RECVV_RN 3 - -#define SCTP_SENDV_NOINFO 0 -#define SCTP_SENDV_SNDINFO 1 -#define SCTP_SENDV_PRINFO 2 -#define SCTP_SENDV_AUTHINFO 3 -#define SCTP_SENDV_SPA 4 - -#define SCTP_SEND_SNDINFO_VALID 0x00000001 -#define SCTP_SEND_PRINFO_VALID 0x00000002 -#define SCTP_SEND_AUTHINFO_VALID 0x00000004 - -struct sctp_snd_all_completes { - uint16_t sall_stream; - uint16_t sall_flags; - uint32_t sall_ppid; - uint32_t sall_context; - uint32_t sall_num_sent; - uint32_t sall_num_failed; -}; - -struct sctp_sndinfo { - uint16_t snd_sid; - uint16_t snd_flags; - uint32_t snd_ppid; - uint32_t snd_context; - sctp_assoc_t snd_assoc_id; -}; - -struct sctp_prinfo { - uint16_t pr_policy; - uint32_t pr_value; -}; - -struct sctp_authinfo { - uint16_t auth_keynumber; -}; - -struct sctp_sendv_spa { - uint32_t sendv_flags; - struct sctp_sndinfo sendv_sndinfo; - struct sctp_prinfo sendv_prinfo; - struct sctp_authinfo sendv_authinfo; -}; - -struct sctp_udpencaps { - struct sockaddr_storage sue_address; - uint32_t sue_assoc_id; - uint16_t sue_port; -}; - -/******** Notifications **************/ - -/* notification types */ -#define SCTP_ASSOC_CHANGE 0x0001 -#define SCTP_PEER_ADDR_CHANGE 0x0002 -#define SCTP_REMOTE_ERROR 0x0003 -#define SCTP_SEND_FAILED 0x0004 -#define SCTP_SHUTDOWN_EVENT 0x0005 -#define SCTP_ADAPTATION_INDICATION 0x0006 -#define SCTP_PARTIAL_DELIVERY_EVENT 0x0007 -#define SCTP_AUTHENTICATION_EVENT 0x0008 -#define SCTP_STREAM_RESET_EVENT 0x0009 -#define SCTP_SENDER_DRY_EVENT 0x000a -#define SCTP_NOTIFICATIONS_STOPPED_EVENT 0x000b -#define SCTP_ASSOC_RESET_EVENT 0x000c -#define SCTP_STREAM_CHANGE_EVENT 0x000d -#define SCTP_SEND_FAILED_EVENT 0x000e - -/* notification event structures */ - - -/* association change event */ -struct sctp_assoc_change { - uint16_t sac_type; - uint16_t sac_flags; - uint32_t sac_length; - uint16_t sac_state; - uint16_t sac_error; - uint16_t sac_outbound_streams; - uint16_t sac_inbound_streams; - sctp_assoc_t sac_assoc_id; - uint8_t sac_info[]; /* not available yet */ -}; - -/* sac_state values */ -#define SCTP_COMM_UP 0x0001 -#define SCTP_COMM_LOST 0x0002 -#define SCTP_RESTART 0x0003 -#define SCTP_SHUTDOWN_COMP 0x0004 -#define SCTP_CANT_STR_ASSOC 0x0005 - -/* sac_info values */ -#define SCTP_ASSOC_SUPPORTS_PR 0x01 -#define SCTP_ASSOC_SUPPORTS_AUTH 0x02 -#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03 -#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04 -#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05 -#define SCTP_ASSOC_SUPPORTS_INTERLEAVING 0x06 -#define SCTP_ASSOC_SUPPORTS_MAX 0x06 - -/* Address event */ -struct sctp_paddr_change { - uint16_t spc_type; - uint16_t spc_flags; - uint32_t spc_length; - struct sockaddr_storage spc_aaddr; - uint32_t spc_state; - uint32_t spc_error; - sctp_assoc_t spc_assoc_id; - uint8_t spc_padding[4]; -}; - -/* paddr state values */ -#define SCTP_ADDR_AVAILABLE 0x0001 -#define SCTP_ADDR_UNREACHABLE 0x0002 -#define SCTP_ADDR_REMOVED 0x0003 -#define SCTP_ADDR_ADDED 0x0004 -#define SCTP_ADDR_MADE_PRIM 0x0005 -#define SCTP_ADDR_CONFIRMED 0x0006 - -/* remote error events */ -struct sctp_remote_error { - uint16_t sre_type; - uint16_t sre_flags; - uint32_t sre_length; - uint16_t sre_error; - sctp_assoc_t sre_assoc_id; - uint8_t sre_data[]; -}; - -/* shutdown event */ -struct sctp_shutdown_event { - uint16_t sse_type; - uint16_t sse_flags; - uint32_t sse_length; - sctp_assoc_t sse_assoc_id; -}; - -/* Adaptation layer indication */ -struct sctp_adaptation_event { - uint16_t sai_type; - uint16_t sai_flags; - uint32_t sai_length; - uint32_t sai_adaptation_ind; - sctp_assoc_t sai_assoc_id; -}; - -/* Partial delivery event */ -struct sctp_pdapi_event { - uint16_t pdapi_type; - uint16_t pdapi_flags; - uint32_t pdapi_length; - uint32_t pdapi_indication; - uint32_t pdapi_stream; - uint32_t pdapi_seq; - sctp_assoc_t pdapi_assoc_id; -}; - -/* indication values */ -#define SCTP_PARTIAL_DELIVERY_ABORTED 0x0001 - -/* SCTP authentication event */ -struct sctp_authkey_event { - uint16_t auth_type; - uint16_t auth_flags; - uint32_t auth_length; - uint16_t auth_keynumber; - uint32_t auth_indication; - sctp_assoc_t auth_assoc_id; -}; - -/* indication values */ -#define SCTP_AUTH_NEW_KEY 0x0001 -#define SCTP_AUTH_NO_AUTH 0x0002 -#define SCTP_AUTH_FREE_KEY 0x0003 - -/* SCTP sender dry event */ -struct sctp_sender_dry_event { - uint16_t sender_dry_type; - uint16_t sender_dry_flags; - uint32_t sender_dry_length; - sctp_assoc_t sender_dry_assoc_id; -}; - - -/* Stream reset event - subscribe to SCTP_STREAM_RESET_EVENT */ -struct sctp_stream_reset_event { - uint16_t strreset_type; - uint16_t strreset_flags; - uint32_t strreset_length; - sctp_assoc_t strreset_assoc_id; - uint16_t strreset_stream_list[]; -}; - -/* flags in stream_reset_event (strreset_flags) */ -#define SCTP_STREAM_RESET_INCOMING_SSN 0x0001 -#define SCTP_STREAM_RESET_OUTGOING_SSN 0x0002 -#define SCTP_STREAM_RESET_DENIED 0x0004 /* SCTP_STRRESET_FAILED */ -#define SCTP_STREAM_RESET_FAILED 0x0008 /* SCTP_STRRESET_FAILED */ -#define SCTP_STREAM_CHANGED_DENIED 0x0010 - -#define SCTP_STREAM_RESET_INCOMING 0x00000001 -#define SCTP_STREAM_RESET_OUTGOING 0x00000002 - - -/* Assoc reset event - subscribe to SCTP_ASSOC_RESET_EVENT */ -struct sctp_assoc_reset_event { - uint16_t assocreset_type; - uint16_t assocreset_flags; - uint32_t assocreset_length; - sctp_assoc_t assocreset_assoc_id; - uint32_t assocreset_local_tsn; - uint32_t assocreset_remote_tsn; -}; - -#define SCTP_ASSOC_RESET_DENIED 0x0004 -#define SCTP_ASSOC_RESET_FAILED 0x0008 - - -/* Stream change event - subscribe to SCTP_STREAM_CHANGE_EVENT */ -struct sctp_stream_change_event { - uint16_t strchange_type; - uint16_t strchange_flags; - uint32_t strchange_length; - sctp_assoc_t strchange_assoc_id; - uint16_t strchange_instrms; - uint16_t strchange_outstrms; -}; - -#define SCTP_STREAM_CHANGE_DENIED 0x0004 -#define SCTP_STREAM_CHANGE_FAILED 0x0008 - - -/* SCTP send failed event */ -struct sctp_send_failed_event { - uint16_t ssfe_type; - uint16_t ssfe_flags; - uint32_t ssfe_length; - uint32_t ssfe_error; - struct sctp_sndinfo ssfe_info; - sctp_assoc_t ssfe_assoc_id; - uint8_t ssfe_data[]; -}; - -/* flag that indicates state of data */ -#define SCTP_DATA_UNSENT 0x0001 /* inqueue never on wire */ -#define SCTP_DATA_SENT 0x0002 /* on wire at failure */ - -/* SCTP event option */ -struct sctp_event { - sctp_assoc_t se_assoc_id; - uint16_t se_type; - uint8_t se_on; -}; - -union sctp_notification { - struct sctp_tlv { - uint16_t sn_type; - uint16_t sn_flags; - uint32_t sn_length; - } sn_header; - struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_paddr_change; - struct sctp_remote_error sn_remote_error; - struct sctp_shutdown_event sn_shutdown_event; - struct sctp_adaptation_event sn_adaptation_event; - struct sctp_pdapi_event sn_pdapi_event; - struct sctp_authkey_event sn_auth_event; - struct sctp_sender_dry_event sn_sender_dry_event; - struct sctp_send_failed_event sn_send_failed_event; - struct sctp_stream_reset_event sn_strreset_event; - struct sctp_assoc_reset_event sn_assocreset_event; - struct sctp_stream_change_event sn_strchange_event; -}; - -struct sctp_event_subscribe { - uint8_t sctp_data_io_event; - uint8_t sctp_association_event; - uint8_t sctp_address_event; - uint8_t sctp_send_failure_event; - uint8_t sctp_peer_error_event; - uint8_t sctp_shutdown_event; - uint8_t sctp_partial_delivery_event; - uint8_t sctp_adaptation_layer_event; - uint8_t sctp_authentication_event; - uint8_t sctp_sender_dry_event; - uint8_t sctp_stream_reset_event; -}; - - - -/* Flags that go into the sinfo->sinfo_flags field */ -#define SCTP_DATA_LAST_FRAG 0x0001 /* tail part of the message could not be sent */ -#define SCTP_DATA_NOT_FRAG 0x0003 /* complete message could not be sent */ -#define SCTP_NOTIFICATION 0x0010 /* next message is a notification */ -#define SCTP_COMPLETE 0x0020 /* next message is complete */ -#define SCTP_EOF 0x0100 /* Start shutdown procedures */ -#define SCTP_ABORT 0x0200 /* Send an ABORT to peer */ -#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */ -#define SCTP_ADDR_OVER 0x0800 /* Override the primary-address */ -#define SCTP_SENDALL 0x1000 /* Send this on all associations */ -#define SCTP_EOR 0x2000 /* end of message signal */ -#define SCTP_SACK_IMMEDIATELY 0x4000 /* Set I-Bit */ - -#define INVALID_SINFO_FLAG(x) (((x) & 0xfffffff0 \ - & ~(SCTP_EOF | SCTP_ABORT | SCTP_UNORDERED |\ - SCTP_ADDR_OVER | SCTP_SENDALL | SCTP_EOR |\ - SCTP_SACK_IMMEDIATELY)) != 0) -/* for the endpoint */ - -/* The lower byte is an enumeration of PR-SCTP policies */ -#define SCTP_PR_SCTP_NONE 0x0000 /* Reliable transfer */ -#define SCTP_PR_SCTP_TTL 0x0001 /* Time based PR-SCTP */ -#define SCTP_PR_SCTP_BUF 0x0002 /* Buffer based PR-SCTP */ -#define SCTP_PR_SCTP_RTX 0x0003 /* Number of retransmissions based PR-SCTP */ - -#define PR_SCTP_POLICY(x) ((x) & 0x0f) -#define PR_SCTP_ENABLED(x) (PR_SCTP_POLICY(x) != SCTP_PR_SCTP_NONE) -#define PR_SCTP_TTL_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_TTL) -#define PR_SCTP_BUF_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_BUF) -#define PR_SCTP_RTX_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_RTX) -#define PR_SCTP_INVALID_POLICY(x) (PR_SCTP_POLICY(x) > SCTP_PR_SCTP_RTX) - - -/* - * user socket options: socket API defined - */ -/* - * read-write options - */ -#define SCTP_RTOINFO 0x00000001 -#define SCTP_ASSOCINFO 0x00000002 -#define SCTP_INITMSG 0x00000003 -#define SCTP_NODELAY 0x00000004 -#define SCTP_AUTOCLOSE 0x00000005 -#define SCTP_PRIMARY_ADDR 0x00000007 -#define SCTP_ADAPTATION_LAYER 0x00000008 -#define SCTP_DISABLE_FRAGMENTS 0x00000009 -#define SCTP_PEER_ADDR_PARAMS 0x0000000a -/* ancillary data/notification interest options */ -/* Without this applied we will give V4 and V6 addresses on a V6 socket */ -#define SCTP_I_WANT_MAPPED_V4_ADDR 0x0000000d -#define SCTP_MAXSEG 0x0000000e -#define SCTP_DELAYED_SACK 0x0000000f -#define SCTP_FRAGMENT_INTERLEAVE 0x00000010 -#define SCTP_PARTIAL_DELIVERY_POINT 0x00000011 -/* authentication support */ -#define SCTP_HMAC_IDENT 0x00000014 -#define SCTP_AUTH_ACTIVE_KEY 0x00000015 -#define SCTP_AUTO_ASCONF 0x00000018 -#define SCTP_MAX_BURST 0x00000019 -/* assoc level context */ -#define SCTP_CONTEXT 0x0000001a -/* explicit EOR signalling */ -#define SCTP_EXPLICIT_EOR 0x0000001b -#define SCTP_REUSE_PORT 0x0000001c - -#define SCTP_EVENT 0x0000001e -#define SCTP_RECVRCVINFO 0x0000001f -#define SCTP_RECVNXTINFO 0x00000020 -#define SCTP_DEFAULT_SNDINFO 0x00000021 -#define SCTP_DEFAULT_PRINFO 0x00000022 -#define SCTP_REMOTE_UDP_ENCAPS_PORT 0x00000024 -#define SCTP_ECN_SUPPORTED 0x00000025 -#define SCTP_PR_SUPPORTED 0x00000026 -#define SCTP_AUTH_SUPPORTED 0x00000027 -#define SCTP_ASCONF_SUPPORTED 0x00000028 -#define SCTP_RECONFIG_SUPPORTED 0x00000029 -#define SCTP_NRSACK_SUPPORTED 0x00000030 -#define SCTP_PKTDROP_SUPPORTED 0x00000031 -#define SCTP_MAX_CWND 0x00000032 -#define SCTP_ACCEPT_ZERO_CHECKSUM 0x00000033 - -#define SCTP_ENABLE_STREAM_RESET 0x00000900 /* struct sctp_assoc_value */ - -/* Pluggable Stream Scheduling Socket option */ -#define SCTP_PLUGGABLE_SS 0x00001203 -#define SCTP_SS_VALUE 0x00001204 - -/* - * read-only options - */ -#define SCTP_STATUS 0x00000100 -#define SCTP_GET_PEER_ADDR_INFO 0x00000101 -/* authentication support */ -#define SCTP_PEER_AUTH_CHUNKS 0x00000102 -#define SCTP_LOCAL_AUTH_CHUNKS 0x00000103 -#define SCTP_GET_ASSOC_NUMBER 0x00000104 -#define SCTP_GET_ASSOC_ID_LIST 0x00000105 -#define SCTP_TIMEOUTS 0x00000106 -#define SCTP_PR_STREAM_STATUS 0x00000107 -#define SCTP_PR_ASSOC_STATUS 0x00000108 - -/* - * write-only options - */ -#define SCTP_SET_PEER_PRIMARY_ADDR 0x00000006 -#define SCTP_AUTH_CHUNK 0x00000012 -#define SCTP_AUTH_KEY 0x00000013 -#define SCTP_AUTH_DEACTIVATE_KEY 0x0000001d -#define SCTP_AUTH_DELETE_KEY 0x00000016 -#define SCTP_RESET_STREAMS 0x00000901 /* struct sctp_reset_streams */ -#define SCTP_RESET_ASSOC 0x00000902 /* sctp_assoc_t */ -#define SCTP_ADD_STREAMS 0x00000903 /* struct sctp_add_streams */ - -struct sctp_initmsg { - uint16_t sinit_num_ostreams; - uint16_t sinit_max_instreams; - uint16_t sinit_max_attempts; - uint16_t sinit_max_init_timeo; -}; - -struct sctp_rtoinfo { - sctp_assoc_t srto_assoc_id; - uint32_t srto_initial; - uint32_t srto_max; - uint32_t srto_min; -}; - -struct sctp_assocparams { - sctp_assoc_t sasoc_assoc_id; - uint32_t sasoc_peer_rwnd; - uint32_t sasoc_local_rwnd; - uint32_t sasoc_cookie_life; - uint16_t sasoc_asocmaxrxt; - uint16_t sasoc_number_peer_destinations; -}; - -struct sctp_setprim { - struct sockaddr_storage ssp_addr; - sctp_assoc_t ssp_assoc_id; - uint8_t ssp_padding[4]; -}; - -struct sctp_setadaptation { - uint32_t ssb_adaptation_ind; -}; - -struct sctp_paddrparams { - struct sockaddr_storage spp_address; - sctp_assoc_t spp_assoc_id; - uint32_t spp_hbinterval; - uint32_t spp_pathmtu; - uint32_t spp_flags; - uint32_t spp_ipv6_flowlabel; - uint16_t spp_pathmaxrxt; - uint8_t spp_dscp; -}; - -#define SPP_HB_ENABLE 0x00000001 -#define SPP_HB_DISABLE 0x00000002 -#define SPP_HB_DEMAND 0x00000004 -#define SPP_PMTUD_ENABLE 0x00000008 -#define SPP_PMTUD_DISABLE 0x00000010 -#define SPP_HB_TIME_IS_ZERO 0x00000080 -#define SPP_IPV6_FLOWLABEL 0x00000100 -#define SPP_DSCP 0x00000200 - -/* Used for SCTP_MAXSEG, SCTP_MAX_BURST, SCTP_ENABLE_STREAM_RESET, and SCTP_CONTEXT */ -struct sctp_assoc_value { - sctp_assoc_t assoc_id; - uint32_t assoc_value; -}; - -/* To enable stream reset */ -#define SCTP_ENABLE_RESET_STREAM_REQ 0x00000001 -#define SCTP_ENABLE_RESET_ASSOC_REQ 0x00000002 -#define SCTP_ENABLE_CHANGE_ASSOC_REQ 0x00000004 -#define SCTP_ENABLE_VALUE_MASK 0x00000007 - -struct sctp_reset_streams { - sctp_assoc_t srs_assoc_id; - uint16_t srs_flags; - uint16_t srs_number_streams; /* 0 == ALL */ - uint16_t srs_stream_list[]; /* list if strrst_num_streams is not 0 */ -}; - -struct sctp_add_streams { - sctp_assoc_t sas_assoc_id; - uint16_t sas_instrms; - uint16_t sas_outstrms; -}; - -struct sctp_hmacalgo { - uint32_t shmac_number_of_idents; - uint16_t shmac_idents[]; -}; - -/* AUTH hmac_id */ -#define SCTP_AUTH_HMAC_ID_RSVD 0x0000 -#define SCTP_AUTH_HMAC_ID_SHA1 0x0001 /* default, mandatory */ -#define SCTP_AUTH_HMAC_ID_SHA256 0x0003 -#define SCTP_AUTH_HMAC_ID_SHA224 0x0004 -#define SCTP_AUTH_HMAC_ID_SHA384 0x0005 -#define SCTP_AUTH_HMAC_ID_SHA512 0x0006 - - -struct sctp_sack_info { - sctp_assoc_t sack_assoc_id; - uint32_t sack_delay; - uint32_t sack_freq; -}; - -struct sctp_default_prinfo { - uint16_t pr_policy; - uint32_t pr_value; - sctp_assoc_t pr_assoc_id; -}; - -struct sctp_paddrinfo { - struct sockaddr_storage spinfo_address; - sctp_assoc_t spinfo_assoc_id; - int32_t spinfo_state; - uint32_t spinfo_cwnd; - uint32_t spinfo_srtt; - uint32_t spinfo_rto; - uint32_t spinfo_mtu; -}; - -struct sctp_status { - sctp_assoc_t sstat_assoc_id; - int32_t sstat_state; - uint32_t sstat_rwnd; - uint16_t sstat_unackdata; - uint16_t sstat_penddata; - uint16_t sstat_instrms; - uint16_t sstat_outstrms; - uint32_t sstat_fragmentation_point; - struct sctp_paddrinfo sstat_primary; -}; - -/* - * user state values - */ -#define SCTP_CLOSED 0x0000 -#define SCTP_BOUND 0x1000 -#define SCTP_LISTEN 0x2000 -#define SCTP_COOKIE_WAIT 0x0002 -#define SCTP_COOKIE_ECHOED 0x0004 -#define SCTP_ESTABLISHED 0x0008 -#define SCTP_SHUTDOWN_SENT 0x0010 -#define SCTP_SHUTDOWN_RECEIVED 0x0020 -#define SCTP_SHUTDOWN_ACK_SENT 0x0040 -#define SCTP_SHUTDOWN_PENDING 0x0080 - - -#define SCTP_ACTIVE 0x0001 /* SCTP_ADDR_REACHABLE */ -#define SCTP_INACTIVE 0x0002 /* neither SCTP_ADDR_REACHABLE - nor SCTP_ADDR_UNCONFIRMED */ -#define SCTP_UNCONFIRMED 0x0200 /* SCTP_ADDR_UNCONFIRMED */ - -struct sctp_authchunks { - sctp_assoc_t gauth_assoc_id; -/* uint32_t gauth_number_of_chunks; not available */ - uint8_t gauth_chunks[]; -}; - -struct sctp_assoc_ids { - uint32_t gaids_number_of_ids; - sctp_assoc_t gaids_assoc_id[]; -}; - -struct sctp_setpeerprim { - struct sockaddr_storage sspp_addr; - sctp_assoc_t sspp_assoc_id; - uint8_t sspp_padding[4]; -}; - -struct sctp_authchunk { - uint8_t sauth_chunk; -}; - - -struct sctp_get_nonce_values { - sctp_assoc_t gn_assoc_id; - uint32_t gn_peers_tag; - uint32_t gn_local_tag; -}; - -/* Values for SCTP_ACCEPT_ZERO_CHECKSUM */ -#define SCTP_EDMID_NONE 0 -#define SCTP_EDMID_LOWER_LAYER_DTLS 1 - - -/* - * Main SCTP chunk types - */ -/************0x00 series ***********/ -#define SCTP_DATA 0x00 -#define SCTP_INITIATION 0x01 -#define SCTP_INITIATION_ACK 0x02 -#define SCTP_SELECTIVE_ACK 0x03 -#define SCTP_HEARTBEAT_REQUEST 0x04 -#define SCTP_HEARTBEAT_ACK 0x05 -#define SCTP_ABORT_ASSOCIATION 0x06 -#define SCTP_SHUTDOWN 0x07 -#define SCTP_SHUTDOWN_ACK 0x08 -#define SCTP_OPERATION_ERROR 0x09 -#define SCTP_COOKIE_ECHO 0x0a -#define SCTP_COOKIE_ACK 0x0b -#define SCTP_ECN_ECHO 0x0c -#define SCTP_ECN_CWR 0x0d -#define SCTP_SHUTDOWN_COMPLETE 0x0e -/* RFC4895 */ -#define SCTP_AUTHENTICATION 0x0f -/* EY nr_sack chunk id*/ -#define SCTP_NR_SELECTIVE_ACK 0x10 -/************0x40 series ***********/ -/************0x80 series ***********/ -/* RFC5061 */ -#define SCTP_ASCONF_ACK 0x80 -/* draft-ietf-stewart-pktdrpsctp */ -#define SCTP_PACKET_DROPPED 0x81 -/* draft-ietf-stewart-strreset-xxx */ -#define SCTP_STREAM_RESET 0x82 - -/* RFC4820 */ -#define SCTP_PAD_CHUNK 0x84 -/************0xc0 series ***********/ -/* RFC3758 */ -#define SCTP_FORWARD_CUM_TSN 0xc0 -/* RFC5061 */ -#define SCTP_ASCONF 0xc1 - -struct sctp_authkey { - sctp_assoc_t sca_assoc_id; - uint16_t sca_keynumber; - uint16_t sca_keylength; - uint8_t sca_key[]; -}; - -struct sctp_authkeyid { - sctp_assoc_t scact_assoc_id; - uint16_t scact_keynumber; -}; - -struct sctp_cc_option { - int option; - struct sctp_assoc_value aid_value; -}; - -struct sctp_stream_value { - sctp_assoc_t assoc_id; - uint16_t stream_id; - uint16_t stream_value; -}; - -struct sctp_timeouts { - sctp_assoc_t stimo_assoc_id; - uint32_t stimo_init; - uint32_t stimo_data; - uint32_t stimo_sack; - uint32_t stimo_shutdown; - uint32_t stimo_heartbeat; - uint32_t stimo_cookie; - uint32_t stimo_shutdownack; -}; - -struct sctp_prstatus { - sctp_assoc_t sprstat_assoc_id; - uint16_t sprstat_sid; - uint16_t sprstat_policy; - uint64_t sprstat_abandoned_unsent; - uint64_t sprstat_abandoned_sent; -}; - -/* Standard TCP Congestion Control */ -#define SCTP_CC_RFC2581 0x00000000 -/* High Speed TCP Congestion Control (Floyd) */ -#define SCTP_CC_HSTCP 0x00000001 -/* HTCP Congestion Control */ -#define SCTP_CC_HTCP 0x00000002 -/* RTCC Congestion Control - RFC2581 plus */ -#define SCTP_CC_RTCC 0x00000003 - -#define SCTP_CC_OPT_RTCC_SETMODE 0x00002000 -#define SCTP_CC_OPT_USE_DCCC_EC 0x00002001 -#define SCTP_CC_OPT_STEADY_STEP 0x00002002 - -#define SCTP_CMT_OFF 0 -#define SCTP_CMT_BASE 1 -#define SCTP_CMT_RPV1 2 -#define SCTP_CMT_RPV2 3 -#define SCTP_CMT_MPTCP 4 -#define SCTP_CMT_MAX SCTP_CMT_MPTCP - -/* RS - Supported stream scheduling modules for pluggable - * stream scheduling - */ -/* Default simple round-robin */ -#define SCTP_SS_DEFAULT 0x00000000 -/* Real round-robin */ -#define SCTP_SS_ROUND_ROBIN 0x00000001 -/* Real round-robin per packet */ -#define SCTP_SS_ROUND_ROBIN_PACKET 0x00000002 -/* Priority */ -#define SCTP_SS_PRIORITY 0x00000003 -/* Fair Bandwidth */ -#define SCTP_SS_FAIR_BANDWITH 0x00000004 -/* First-come, first-serve */ -#define SCTP_SS_FIRST_COME 0x00000005 - -/******************** System calls *************/ - -struct socket; - -void -usrsctp_init(uint16_t, - int (*)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), - void (*)(const char *format, ...)); - -void -usrsctp_init_nothreads(uint16_t, - int (*)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), - void (*)(const char *format, ...)); - -struct socket * -usrsctp_socket(int domain, int type, int protocol, - int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data, - size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info), - int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info), - uint32_t sb_threshold, - void *ulp_info); - -int -usrsctp_setsockopt(struct socket *so, - int level, - int option_name, - const void *option_value, - socklen_t option_len); - -int -usrsctp_getsockopt(struct socket *so, - int level, - int option_name, - void *option_value, - socklen_t *option_len); - -int -usrsctp_opt_info(struct socket *so, - sctp_assoc_t id, - int opt, - void *arg, - socklen_t *size); - -int -usrsctp_getpaddrs(struct socket *so, - sctp_assoc_t id, - struct sockaddr **raddrs); - -void -usrsctp_freepaddrs(struct sockaddr *addrs); - -int -usrsctp_getladdrs(struct socket *so, - sctp_assoc_t id, - struct sockaddr **raddrs); - -void -usrsctp_freeladdrs(struct sockaddr *addrs); - -ssize_t -usrsctp_sendv(struct socket *so, - const void *data, - size_t len, - struct sockaddr *to, - int addrcnt, - void *info, - socklen_t infolen, - unsigned int infotype, - int flags); - -ssize_t -usrsctp_recvv(struct socket *so, - void *dbuf, - size_t len, - struct sockaddr *from, - socklen_t * fromlen, - void *info, - socklen_t *infolen, - unsigned int *infotype, - int *msg_flags); - -int -usrsctp_bind(struct socket *so, - struct sockaddr *name, - socklen_t namelen); - -#define SCTP_BINDX_ADD_ADDR 0x00008001 -#define SCTP_BINDX_REM_ADDR 0x00008002 - -int -usrsctp_bindx(struct socket *so, - struct sockaddr *addrs, - int addrcnt, - int flags); - -int -usrsctp_listen(struct socket *so, - int backlog); - -struct socket * -usrsctp_accept(struct socket *so, - struct sockaddr * aname, - socklen_t * anamelen); - -struct socket * -usrsctp_peeloff(struct socket *, sctp_assoc_t); - -int -usrsctp_connect(struct socket *so, - struct sockaddr *name, - socklen_t namelen); - -int -usrsctp_connectx(struct socket *so, - const struct sockaddr *addrs, int addrcnt, - sctp_assoc_t *id); - -void -usrsctp_close(struct socket *so); - -sctp_assoc_t -usrsctp_getassocid(struct socket *, struct sockaddr *); - -int -usrsctp_finish(void); - -int -usrsctp_shutdown(struct socket *so, int how); - -void -usrsctp_conninput(void *, const void *, size_t, uint8_t); - -int -usrsctp_set_non_blocking(struct socket *, int); - -int -usrsctp_get_non_blocking(struct socket *); - -void -usrsctp_register_address(void *); - -void -usrsctp_deregister_address(void *); - -int -usrsctp_set_ulpinfo(struct socket *, void *); - -int -usrsctp_get_ulpinfo(struct socket *, void **); - -int -usrsctp_set_upcall(struct socket *so, - void (*upcall)(struct socket *, void *, int), - void *arg); - -int -usrsctp_get_events(struct socket *so); - - -void -usrsctp_handle_timers(uint32_t elapsed_milliseconds); - -#define SCTP_DUMP_OUTBOUND 1 -#define SCTP_DUMP_INBOUND 0 - -char * -usrsctp_dumppacket(const void *, size_t, int); - -void -usrsctp_freedumpbuffer(char *); - -void -usrsctp_enable_crc32c_offload(void); - -void -usrsctp_disable_crc32c_offload(void); - -uint32_t -usrsctp_crc32c(void *, size_t); - -#define USRSCTP_TUNABLE_DECL(__field) \ -int usrsctp_tunable_set_ ## __field(uint32_t value);\ -uint32_t usrsctp_sysctl_get_ ## __field(void); - -USRSCTP_TUNABLE_DECL(sctp_hashtblsize) -USRSCTP_TUNABLE_DECL(sctp_pcbtblsize) -USRSCTP_TUNABLE_DECL(sctp_chunkscale) - -#define USRSCTP_SYSCTL_DECL(__field) \ -int usrsctp_sysctl_set_ ## __field(uint32_t value);\ -uint32_t usrsctp_sysctl_get_ ## __field(void); - -USRSCTP_SYSCTL_DECL(sctp_sendspace) -USRSCTP_SYSCTL_DECL(sctp_recvspace) -USRSCTP_SYSCTL_DECL(sctp_auto_asconf) -USRSCTP_SYSCTL_DECL(sctp_multiple_asconfs) -USRSCTP_SYSCTL_DECL(sctp_ecn_enable) -USRSCTP_SYSCTL_DECL(sctp_pr_enable) -USRSCTP_SYSCTL_DECL(sctp_auth_enable) -USRSCTP_SYSCTL_DECL(sctp_asconf_enable) -USRSCTP_SYSCTL_DECL(sctp_reconfig_enable) -USRSCTP_SYSCTL_DECL(sctp_nrsack_enable) -USRSCTP_SYSCTL_DECL(sctp_pktdrop_enable) -USRSCTP_SYSCTL_DECL(sctp_no_csum_on_loopback) -USRSCTP_SYSCTL_DECL(sctp_peer_chunk_oh) -USRSCTP_SYSCTL_DECL(sctp_max_burst_default) -USRSCTP_SYSCTL_DECL(sctp_max_chunks_on_queue) -USRSCTP_SYSCTL_DECL(sctp_min_split_point) -USRSCTP_SYSCTL_DECL(sctp_delayed_sack_time_default) -USRSCTP_SYSCTL_DECL(sctp_sack_freq_default) -USRSCTP_SYSCTL_DECL(sctp_system_free_resc_limit) -USRSCTP_SYSCTL_DECL(sctp_asoc_free_resc_limit) -USRSCTP_SYSCTL_DECL(sctp_heartbeat_interval_default) -USRSCTP_SYSCTL_DECL(sctp_pmtu_raise_time_default) -USRSCTP_SYSCTL_DECL(sctp_shutdown_guard_time_default) -USRSCTP_SYSCTL_DECL(sctp_secret_lifetime_default) -USRSCTP_SYSCTL_DECL(sctp_rto_max_default) -USRSCTP_SYSCTL_DECL(sctp_rto_min_default) -USRSCTP_SYSCTL_DECL(sctp_rto_initial_default) -USRSCTP_SYSCTL_DECL(sctp_init_rto_max_default) -USRSCTP_SYSCTL_DECL(sctp_valid_cookie_life_default) -USRSCTP_SYSCTL_DECL(sctp_init_rtx_max_default) -USRSCTP_SYSCTL_DECL(sctp_assoc_rtx_max_default) -USRSCTP_SYSCTL_DECL(sctp_path_rtx_max_default) -USRSCTP_SYSCTL_DECL(sctp_add_more_threshold) -USRSCTP_SYSCTL_DECL(sctp_nr_incoming_streams_default) -USRSCTP_SYSCTL_DECL(sctp_nr_outgoing_streams_default) -USRSCTP_SYSCTL_DECL(sctp_cmt_on_off) -USRSCTP_SYSCTL_DECL(sctp_cmt_use_dac) -USRSCTP_SYSCTL_DECL(sctp_use_cwnd_based_maxburst) -USRSCTP_SYSCTL_DECL(sctp_nat_friendly) -USRSCTP_SYSCTL_DECL(sctp_L2_abc_variable) -USRSCTP_SYSCTL_DECL(sctp_mbuf_threshold_count) -USRSCTP_SYSCTL_DECL(sctp_do_drain) -USRSCTP_SYSCTL_DECL(sctp_hb_maxburst) -USRSCTP_SYSCTL_DECL(sctp_abort_if_one_2_one_hits_limit) -USRSCTP_SYSCTL_DECL(sctp_min_residual) -USRSCTP_SYSCTL_DECL(sctp_max_retran_chunk) -USRSCTP_SYSCTL_DECL(sctp_logging_level) -USRSCTP_SYSCTL_DECL(sctp_default_cc_module) -USRSCTP_SYSCTL_DECL(sctp_default_frag_interleave) -USRSCTP_SYSCTL_DECL(sctp_mobility_base) -USRSCTP_SYSCTL_DECL(sctp_mobility_fasthandoff) -USRSCTP_SYSCTL_DECL(sctp_inits_include_nat_friendly) -USRSCTP_SYSCTL_DECL(sctp_udp_tunneling_port) -USRSCTP_SYSCTL_DECL(sctp_enable_sack_immediately) -USRSCTP_SYSCTL_DECL(sctp_vtag_time_wait) -USRSCTP_SYSCTL_DECL(sctp_blackhole) -USRSCTP_SYSCTL_DECL(sctp_sendall_limit) -USRSCTP_SYSCTL_DECL(sctp_diag_info_code) -USRSCTP_SYSCTL_DECL(sctp_fr_max_burst_default) -USRSCTP_SYSCTL_DECL(sctp_path_pf_threshold) -USRSCTP_SYSCTL_DECL(sctp_default_ss_module) -USRSCTP_SYSCTL_DECL(sctp_rttvar_bw) -USRSCTP_SYSCTL_DECL(sctp_rttvar_rtt) -USRSCTP_SYSCTL_DECL(sctp_rttvar_eqret) -USRSCTP_SYSCTL_DECL(sctp_steady_step) -USRSCTP_SYSCTL_DECL(sctp_use_dccc_ecn) -USRSCTP_SYSCTL_DECL(sctp_buffer_splitting) -USRSCTP_SYSCTL_DECL(sctp_initial_cwnd) -USRSCTP_SYSCTL_DECL(sctp_ootb_with_zero_cksum) -#ifdef SCTP_DEBUG -USRSCTP_SYSCTL_DECL(sctp_debug_on) -/* More specific values can be found in sctp_constants, but - * are not considered to be part of the API. - */ -#define SCTP_DEBUG_NONE 0x00000000 -#define SCTP_DEBUG_ALL 0xffffffff -#endif -#undef USRSCTP_SYSCTL_DECL -struct sctp_timeval { - uint32_t tv_sec; - uint32_t tv_usec; -}; - -struct sctpstat { - struct sctp_timeval sctps_discontinuitytime; /* sctpStats 18 (TimeStamp) */ - /* MIB according to RFC 3873 */ - uint32_t sctps_currestab; /* sctpStats 1 (Gauge32) */ - uint32_t sctps_activeestab; /* sctpStats 2 (Counter32) */ - uint32_t sctps_restartestab; - uint32_t sctps_collisionestab; - uint32_t sctps_passiveestab; /* sctpStats 3 (Counter32) */ - uint32_t sctps_aborted; /* sctpStats 4 (Counter32) */ - uint32_t sctps_shutdown; /* sctpStats 5 (Counter32) */ - uint32_t sctps_outoftheblue; /* sctpStats 6 (Counter32) */ - uint32_t sctps_checksumerrors; /* sctpStats 7 (Counter32) */ - uint32_t sctps_outcontrolchunks; /* sctpStats 8 (Counter64) */ - uint32_t sctps_outorderchunks; /* sctpStats 9 (Counter64) */ - uint32_t sctps_outunorderchunks; /* sctpStats 10 (Counter64) */ - uint32_t sctps_incontrolchunks; /* sctpStats 11 (Counter64) */ - uint32_t sctps_inorderchunks; /* sctpStats 12 (Counter64) */ - uint32_t sctps_inunorderchunks; /* sctpStats 13 (Counter64) */ - uint32_t sctps_fragusrmsgs; /* sctpStats 14 (Counter64) */ - uint32_t sctps_reasmusrmsgs; /* sctpStats 15 (Counter64) */ - uint32_t sctps_outpackets; /* sctpStats 16 (Counter64) */ - uint32_t sctps_inpackets; /* sctpStats 17 (Counter64) */ - - /* input statistics: */ - uint32_t sctps_recvpackets; /* total input packets */ - uint32_t sctps_recvdatagrams; /* total input datagrams */ - uint32_t sctps_recvpktwithdata; /* total packets that had data */ - uint32_t sctps_recvsacks; /* total input SACK chunks */ - uint32_t sctps_recvdata; /* total input DATA chunks */ - uint32_t sctps_recvdupdata; /* total input duplicate DATA chunks */ - uint32_t sctps_recvheartbeat; /* total input HB chunks */ - uint32_t sctps_recvheartbeatack; /* total input HB-ACK chunks */ - uint32_t sctps_recvecne; /* total input ECNE chunks */ - uint32_t sctps_recvauth; /* total input AUTH chunks */ - uint32_t sctps_recvauthmissing; /* total input chunks missing AUTH */ - uint32_t sctps_recvivalhmacid; /* total number of invalid HMAC ids received */ - uint32_t sctps_recvivalkeyid; /* total number of invalid secret ids received */ - uint32_t sctps_recvauthfailed; /* total number of auth failed */ - uint32_t sctps_recvexpress; /* total fast path receives all one chunk */ - uint32_t sctps_recvexpressm; /* total fast path multi-part data */ - uint32_t sctps_recv_spare; /* formerly sctps_recvnocrc */ - uint32_t sctps_recvswcrc; - uint32_t sctps_recvhwcrc; - - /* output statistics: */ - uint32_t sctps_sendpackets; /* total output packets */ - uint32_t sctps_sendsacks; /* total output SACKs */ - uint32_t sctps_senddata; /* total output DATA chunks */ - uint32_t sctps_sendretransdata; /* total output retransmitted DATA chunks */ - uint32_t sctps_sendfastretrans; /* total output fast retransmitted DATA chunks */ - uint32_t sctps_sendmultfastretrans; /* total FR's that happened more than once - * to same chunk (u-del multi-fr algo). - */ - uint32_t sctps_sendheartbeat; /* total output HB chunks */ - uint32_t sctps_sendecne; /* total output ECNE chunks */ - uint32_t sctps_sendauth; /* total output AUTH chunks FIXME */ - uint32_t sctps_senderrors; /* ip_output error counter */ - uint32_t sctps_send_spare; /* formerly sctps_sendnocrc */ - uint32_t sctps_sendswcrc; - uint32_t sctps_sendhwcrc; - /* PCKDROPREP statistics: */ - uint32_t sctps_pdrpfmbox; /* Packet drop from middle box */ - uint32_t sctps_pdrpfehos; /* P-drop from end host */ - uint32_t sctps_pdrpmbda; /* P-drops with data */ - uint32_t sctps_pdrpmbct; /* P-drops, non-data, non-endhost */ - uint32_t sctps_pdrpbwrpt; /* P-drop, non-endhost, bandwidth rep only */ - uint32_t sctps_pdrpcrupt; /* P-drop, not enough for chunk header */ - uint32_t sctps_pdrpnedat; /* P-drop, not enough data to confirm */ - uint32_t sctps_pdrppdbrk; /* P-drop, where process_chunk_drop said break */ - uint32_t sctps_pdrptsnnf; /* P-drop, could not find TSN */ - uint32_t sctps_pdrpdnfnd; /* P-drop, attempt reverse TSN lookup */ - uint32_t sctps_pdrpdiwnp; /* P-drop, e-host confirms zero-rwnd */ - uint32_t sctps_pdrpdizrw; /* P-drop, midbox confirms no space */ - uint32_t sctps_pdrpbadd; /* P-drop, data did not match TSN */ - uint32_t sctps_pdrpmark; /* P-drop, TSN's marked for Fast Retran */ - /* timeouts */ - uint32_t sctps_timoiterator; /* Number of iterator timers that fired */ - uint32_t sctps_timodata; /* Number of T3 data time outs */ - uint32_t sctps_timowindowprobe; /* Number of window probe (T3) timers that fired */ - uint32_t sctps_timoinit; /* Number of INIT timers that fired */ - uint32_t sctps_timosack; /* Number of sack timers that fired */ - uint32_t sctps_timoshutdown; /* Number of shutdown timers that fired */ - uint32_t sctps_timoheartbeat; /* Number of heartbeat timers that fired */ - uint32_t sctps_timocookie; /* Number of times a cookie timeout fired */ - uint32_t sctps_timosecret; /* Number of times an endpoint changed its cookie secret*/ - uint32_t sctps_timopathmtu; /* Number of PMTU timers that fired */ - uint32_t sctps_timoshutdownack; /* Number of shutdown ack timers that fired */ - uint32_t sctps_timoshutdownguard; /* Number of shutdown guard timers that fired */ - uint32_t sctps_timostrmrst; /* Number of stream reset timers that fired */ - uint32_t sctps_timoearlyfr; /* Number of early FR timers that fired */ - uint32_t sctps_timoasconf; /* Number of times an asconf timer fired */ - uint32_t sctps_timodelprim; /* Number of times a prim_deleted timer fired */ - uint32_t sctps_timoautoclose; /* Number of times auto close timer fired */ - uint32_t sctps_timoassockill; /* Number of asoc free timers expired */ - uint32_t sctps_timoinpkill; /* Number of inp free timers expired */ - /* former early FR counters */ - uint32_t sctps_spare[11]; - /* others */ - uint32_t sctps_hdrops; /* packet shorter than header */ - uint32_t sctps_badsum; /* checksum error */ - uint32_t sctps_noport; /* no endpoint for port */ - uint32_t sctps_badvtag; /* bad v-tag */ - uint32_t sctps_badsid; /* bad SID */ - uint32_t sctps_nomem; /* no memory */ - uint32_t sctps_fastretransinrtt; /* number of multiple FR in a RTT window */ - uint32_t sctps_markedretrans; - uint32_t sctps_naglesent; /* nagle allowed sending */ - uint32_t sctps_naglequeued; /* nagle doesn't allow sending */ - uint32_t sctps_maxburstqueued; /* max burst doesn't allow sending */ - uint32_t sctps_ifnomemqueued; /* look ahead tells us no memory in - * interface ring buffer OR we had a - * send error and are queuing one send. - */ - uint32_t sctps_windowprobed; /* total number of window probes sent */ - uint32_t sctps_lowlevelerr; /* total times an output error causes us - * to clamp down on next user send. - */ - uint32_t sctps_lowlevelerrusr; /* total times sctp_senderrors were caused from - * a user send from a user invoked send not - * a sack response - */ - uint32_t sctps_datadropchklmt; /* Number of in data drops due to chunk limit reached */ - uint32_t sctps_datadroprwnd; /* Number of in data drops due to rwnd limit reached */ - uint32_t sctps_ecnereducedcwnd; /* Number of times a ECN reduced the cwnd */ - uint32_t sctps_vtagexpress; /* Used express lookup via vtag */ - uint32_t sctps_vtagbogus; /* Collision in express lookup. */ - uint32_t sctps_primary_randry; /* Number of times the sender ran dry of user data on primary */ - uint32_t sctps_cmt_randry; /* Same for above */ - uint32_t sctps_slowpath_sack; /* Sacks the slow way */ - uint32_t sctps_wu_sacks_sent; /* Window Update only sacks sent */ - uint32_t sctps_sends_with_flags; /* number of sends with sinfo_flags !=0 */ - uint32_t sctps_sends_with_unord; /* number of unordered sends */ - uint32_t sctps_sends_with_eof; /* number of sends with EOF flag set */ - uint32_t sctps_sends_with_abort; /* number of sends with ABORT flag set */ - uint32_t sctps_protocol_drain_calls;/* number of times protocol drain called */ - uint32_t sctps_protocol_drains_done;/* number of times we did a protocol drain */ - uint32_t sctps_read_peeks; /* Number of times recv was called with peek */ - uint32_t sctps_cached_chk; /* Number of cached chunks used */ - uint32_t sctps_cached_strmoq; /* Number of cached stream oq's used */ - uint32_t sctps_left_abandon; /* Number of unread messages abandoned by close */ - uint32_t sctps_send_burst_avoid; /* Unused */ - uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already max burst inflight to net */ - uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via fwd-tsn's */ - uint32_t sctps_queue_upd_ecne; /* Number of times we queued or updated an ECN chunk on send queue */ - uint32_t sctps_recvzerocrc; /* Number of accepted packets with zero CRC */ - uint32_t sctps_sendzerocrc; /* Number of packets sent with zero CRC */ - uint32_t sctps_reserved[29]; /* Future ABI compat - remove int's from here when adding new */ -}; - -void -usrsctp_get_stat(struct sctpstat *); - -#ifdef _WIN32 -#ifdef _MSC_VER -#pragma warning(default: 4200) -#endif -#endif -#ifdef __cplusplus -} -#endif -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/aacrtppacketizer.hpp b/godot/thirdparty/libdatachannel/include/rtc/aacrtppacketizer.hpp deleted file mode 100644 index 7417f552..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/aacrtppacketizer.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_AAC_RTP_PACKETIZER_H -#define RTC_AAC_RTP_PACKETIZER_H - -#if RTC_ENABLE_MEDIA - -#include "mediachainablehandler.hpp" -#include "mediahandlerrootelement.hpp" -#include "rtppacketizer.hpp" - -namespace rtc { - -/// RTP packetizer for aac -class RTC_CPP_EXPORT AACRtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement { -public: - /// default clock rate used in aac RTP communication - inline static const uint32_t defaultClockRate = 48 * 1000; - - /// Constructs aac packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - AACRtpPacketizer(shared_ptr rtpConfig); - - /// Creates RTP packet for given payload based on `rtpConfig`. - /// @note This function increase sequence number after packetization. - /// @param payload RTP payload - /// @param setMark This needs to be `false` for all RTP packets with aac payload - binary_ptr packetize(binary_ptr payload, bool setMark) override; - - /// Creates RTP packet for given samples (all samples share same RTP timesamp) - /// @param messages aac samples - /// @param control RTCP - /// @returns RTP packets and unchanged `control` - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; -}; - -/// Handler for aac packetization -class RTC_CPP_EXPORT AACPacketizationHandler final : public MediaChainableHandler { - -public: - /// Construct handler for aac packetization. - /// @param packetizer RTP packetizer for aac - AACPacketizationHandler(shared_ptr packetizer) - : MediaChainableHandler(packetizer) {} -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_AAC_RTP_PACKETIZER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/av1packetizationhandler.hpp b/godot/thirdparty/libdatachannel/include/rtc/av1packetizationhandler.hpp deleted file mode 100644 index ed7941de..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/av1packetizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2023 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_AV1_PACKETIZATION_HANDLER_H -#define RTC_AV1_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "av1rtppacketizer.hpp" -#include "mediachainablehandler.hpp" -#include "nalunit.hpp" - -namespace rtc { - -/// Handler for AV1 packetization -class RTC_CPP_EXPORT AV1PacketizationHandler final : public MediaChainableHandler { -public: - /// Construct handler for AV1 packetization. - /// @param packetizer RTP packetizer for AV1 - AV1PacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_AV1_PACKETIZATION_HANDLER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/av1rtppacketizer.hpp b/godot/thirdparty/libdatachannel/include/rtc/av1rtppacketizer.hpp deleted file mode 100644 index 9e7432a0..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/av1rtppacketizer.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2023 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_AV1_RTP_PACKETIZER_H -#define RTC_AV1_RTP_PACKETIZER_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerrootelement.hpp" -#include "nalunit.hpp" -#include "rtppacketizer.hpp" - -namespace rtc { - -/// RTP packetization of AV1 payload -class RTC_CPP_EXPORT AV1RtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement { - shared_ptr splitMessage(binary_ptr message); - const uint16_t maximumFragmentSize; - -public: - /// Default clock rate for AV1 in RTP - inline static const uint32_t defaultClockRate = 90 * 1000; - - // Define how OBUs are seperated in a AV1 Sample - enum class Packetization { - Obu = RTC_OBU_PACKETIZED_OBU, - TemporalUnit = RTC_OBU_PACKETIZED_TEMPORAL_UNIT, - }; - - /// Constructs AV1 payload packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - AV1RtpPacketizer(Packetization packetization, shared_ptr rtpConfig, - uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); - - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; - -private: - const Packetization packetization; - std::shared_ptr sequenceHeader; - - std::vector> packetizeObu(binary_ptr message, uint16_t maximumFragmentSize); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_AV1_RTP_PACKETIZER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/candidate.hpp b/godot/thirdparty/libdatachannel/include/rtc/candidate.hpp deleted file mode 100644 index c243a829..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/candidate.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_CANDIDATE_H -#define RTC_CANDIDATE_H - -#include "common.hpp" - -#include - -namespace rtc { - -class RTC_CPP_EXPORT Candidate { -public: - enum class Family { Unresolved, Ipv4, Ipv6 }; - enum class Type { Unknown, Host, ServerReflexive, PeerReflexive, Relayed }; - enum class TransportType { Unknown, Udp, TcpActive, TcpPassive, TcpSo, TcpUnknown }; - - Candidate(); - static RTC_WRAPPED(Candidate) create(string candidate); - static RTC_WRAPPED(Candidate) create(string candidate, string mid); - - void hintMid(string mid); - RTC_WRAPPED(void) changeAddress(string addr); - RTC_WRAPPED(void) changeAddress(string addr, uint16_t port); - RTC_WRAPPED(void) changeAddress(string addr, string service); - - enum class ResolveMode { Simple, Lookup }; - bool resolve(ResolveMode mode = ResolveMode::Simple); - - Type type() const; - TransportType transportType() const; - uint32_t priority() const; - string candidate() const; - string mid() const; - operator string() const; - - bool operator==(const Candidate &other) const; - bool operator!=(const Candidate &other) const; - - bool isResolved() const; - Family family() const; - optional address() const; - optional port() const; - -private: - RTC_WRAPPED(void) parse(string candidate); - - string mFoundation; - uint32_t mComponent, mPriority; - string mTypeString, mTransportString; - Type mType; - TransportType mTransportType; - string mNode, mService; - string mTail; - - optional mMid; - - // Extracted on resolution - Family mFamily; - string mAddress; - uint16_t mPort; -}; - -} // namespace rtc - -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, - const rtc::Candidate::TransportType &transportType); - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/channel.hpp b/godot/thirdparty/libdatachannel/include/rtc/channel.hpp deleted file mode 100644 index 32e69d27..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/channel.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_CHANNEL_H -#define RTC_CHANNEL_H - -#include "common.hpp" - -#include -#include - -namespace rtc { - -namespace impl { -struct Channel; -} - -class RTC_CPP_EXPORT Channel : private CheshireCat { -public: - virtual ~Channel(); - - virtual void close() = 0; - virtual RTC_WRAPPED(bool) send(message_variant data) = 0; // returns false if buffered - virtual RTC_WRAPPED(bool) send(const byte *data, size_t size) = 0; - - virtual bool isOpen() const = 0; - virtual bool isClosed() const = 0; - virtual size_t maxMessageSize() const; // max message size in a call to send - virtual size_t bufferedAmount() const; // total size buffered to send - - void onOpen(std::function callback); - void onClosed(std::function callback); - void onError(std::function callback); - - void onMessage(std::function callback); - void onMessage(std::function binaryCallback, - std::function stringCallback); - - void onBufferedAmountLow(std::function callback); - void setBufferedAmountLowThreshold(size_t amount); - - void resetCallbacks(); - - // Extended API - optional receive(); // only if onMessage unset - optional peek(); // only if onMessage unset - size_t availableAmount() const; // total size available to receive - void onAvailable(std::function callback); - -protected: - Channel(impl_ptr impl); -}; - -} // namespace rtc - -#endif // RTC_CHANNEL_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/common.hpp b/godot/thirdparty/libdatachannel/include/rtc/common.hpp deleted file mode 100644 index d60634ac..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/common.hpp +++ /dev/null @@ -1,221 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_COMMON_H -#define RTC_COMMON_H - -#ifdef RTC_STATIC -#define RTC_CPP_EXPORT -#else // dynamic library -#ifdef _WIN32 -#ifdef RTC_EXPORTS -#define RTC_CPP_EXPORT __declspec(dllexport) // building the library -#else -#define RTC_CPP_EXPORT __declspec(dllimport) // using the library -#endif -#else // not WIN32 -#define RTC_CPP_EXPORT -#endif -#endif - -#ifdef _WIN32 -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0602 // Windows 8 -#endif -#ifdef _MSC_VER -#pragma warning(disable : 4251) // disable "X needs to have dll-interface..." -#endif -#endif - -#ifndef RTC_ENABLE_WEBSOCKET -#define RTC_ENABLE_WEBSOCKET 1 -#endif - -#ifndef RTC_ENABLE_MEDIA -#define RTC_ENABLE_MEDIA 1 -#endif - -#include "rtc.h" // for C API defines - -#include "utils.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rtc { - -#ifdef RTC_USE_CPP_EXCEPTIONS - -#define RTC_WHAT what -#define RTC_EXCEPTION std::exception -#define RTC_RUNTIME_ERROR std::runtime_error -#define RTC_LOGIC_ERROR std::logic_error -#define RTC_INVALID_ARGUMENT std::invalid_argument -#define RTC_OUT_OF_RANGE std::out_of_range - -#define RTC_THROW throw -#define RTC_THROW_WITHIN(exception) throw exception -#define RTC_BEGIN -#define RTC_TRY try -#define RTC_CATCH catch -#define RTC_WRAPPED(T) T -#define RTC_VOID -#define RTC_RET return - -#define RTC_UNWRAP_EXPR(func) (func) -#define RTC_CHECK_EXCEPTION -#define RTC_RETHROW throw - -#define RTC_UNWRAP_CATCH(func) (func) -#define RTC_UNWRAP_RETHROW(func) (func) -#define RTC_UNWRAP_CATCH_DECL(typ, var, func) typ var = (func) -#define RTC_UNWRAP_RETHROW_DECL(typ, var, func) typ var = (func) -#define RTC_UNWRAP_CATCH_VAR(var, func) var = (func) -#define RTC_UNWRAP_RETHROW_VAR(var, func) var = (func) -#define RTC_UNWRAP_CATCH_ARG(wrap, func) wrap((func)) -#define RTC_UNWRAP_RETHROW_ARG(wrap, func) wrap((func)) -#define RTC_COMMA , - -#else - - - - - - -#define RTC_WHAT c_str -#define RTC_EXCEPTION std::string -#define RTC_RUNTIME_ERROR std::string -#define RTC_LOGIC_ERROR std::string -#define RTC_INVALID_ARGUMENT std::string -#define RTC_OUT_OF_RANGE std::string - -#ifdef _MSC_VER -#pragma warning(error : 4715) -#pragma warning(error : 4716) -#pragma warning(error : 4834) -#endif - -class Void {}; - -class [[nodiscard]] ExceptionCast { - RTC_EXCEPTION &&rtc_exception; - -public: - ExceptionCast(RTC_EXCEPTION &&p_rtc_exception) : - rtc_exception(std::move(p_rtc_exception)) { - } - RTC_EXCEPTION &&exception() { - return std::move(rtc_exception); - } -}; -template -struct [[nodiscard]] WrappedResult { - using ExT = RTC_EXCEPTION; - T rtc_value; - ExT rtc_exception; - bool rtc_is_exception; - - WrappedResult(T &&value) : - rtc_value(std::move(value)), rtc_exception(ExT()), rtc_is_exception(false) { - } - WrappedResult(const T &value) : - rtc_value(value), rtc_exception(ExT()), rtc_is_exception(false) { - } - WrappedResult(ExceptionCast exception_cast) : - rtc_value(T()), rtc_exception(std::move(exception_cast.exception())), rtc_is_exception(true) { - } -}; - -template<> -struct [[nodiscard]] WrappedResult { - using ExT = RTC_EXCEPTION; - Void rtc_value; - ExT rtc_exception; - bool rtc_is_exception; - - WrappedResult() : - rtc_value(Void()), rtc_exception(ExT()), rtc_is_exception(false) { - } - WrappedResult(Void) : - rtc_value(Void()), rtc_exception(ExT()), rtc_is_exception(false) { - } - WrappedResult(ExceptionCast exception_cast) : - rtc_value(Void()), rtc_exception(std::move(exception_cast.exception())), rtc_is_exception(true) { - } -}; - -#define RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(clsname) friend struct WrappedResult -#define RTC_THROW return (::rtc::ExceptionCast) -#define RTC_TRY RTC_EXCEPTION e; bool rtcexc_was_thrown; -#define RTC_BEGIN RTC_EXCEPTION e; bool rtcexc_was_thrown -#define RTC_CATCH(extype) while (false) rtcexc_catch_label: -#define RTC_WRAPPED(T) ::rtc::WrappedResult -#define RTC_THROW_WITHIN(exception) while ((e = (exception)), (rtcexc_was_thrown = true)) goto rtcexc_catch_label -#define RTC_VOID ::rtc::WrappedResult() -#define RTC_RET return RTC_VOID - -#define RTC_UNWRAP_EXPR(func) ([&](){ \ - auto _rtcexc_tmp = (func); \ - e = _rtcexc_tmp.rtc_exception; \ - rtcexc_was_thrown = _rtcexc_tmp.rtc_is_exception || rtcexc_was_thrown; \ - return _rtcexc_tmp.rtc_value; \ -})() -#define RTC_CATCH_EXCEPTION while (rtcexc_was_thrown) goto rtcexc_catch_label -#define RTC_RETHROW while (rtcexc_was_thrown) return (::rtc::ExceptionCast)std::move(e) - -#define RTC_UNWRAP_CATCH(func) do { RTC_UNWRAP_EXPR(func); RTC_CATCH_EXCEPTION; } while (0) -#define RTC_UNWRAP_RETHROW(func) do { RTC_UNWRAP_EXPR(func); RTC_RETHROW; } while (0) -#define RTC_UNWRAP_CATCH_ARG(wrap, func) do { wrap(RTC_UNWRAP_EXPR(func)); RTC_CATCH_EXCEPTION; } while (0) -#define RTC_UNWRAP_RETHROW_ARG(wrap, func) do { wrap(RTC_UNWRAP_EXPR(func)); RTC_RETHROW; } while (0) -// Note: in a single-line if statement, this would fall out. -// This should only be used for variable declarations which cannot occur in a single line. -#define RTC_UNWRAP_CATCH_DECL(typ, var, func) typ var = RTC_UNWRAP_EXPR(func); RTC_CATCH_EXCEPTION; -#define RTC_UNWRAP_RETHROW_DECL(typ, var, func) typ var = RTC_UNWRAP_EXPR(func); RTC_RETHROW; -#define RTC_UNWRAP_CATCH_VAR(var, func) do { var = RTC_UNWRAP_EXPR(func); RTC_CATCH_EXCEPTION; } while (0) -#define RTC_UNWRAP_RETHROW_VAR(var, func) do { var = RTC_UNWRAP_EXPR(func); RTC_RETHROW; } while (0) -#define RTC_COMMA , - -#endif - -using std::byte; -using std::nullopt; -using std::optional; -using std::shared_ptr; -using std::string; -using std::string_view; -using std::unique_ptr; -using std::variant; -using std::weak_ptr; - -using binary = std::vector; -using binary_ptr = shared_ptr; -using message_variant = variant; - -using std::int16_t; -using std::int32_t; -using std::int64_t; -using std::int8_t; -using std::ptrdiff_t; -using std::size_t; -using std::uint16_t; -using std::uint32_t; -using std::uint64_t; -using std::uint8_t; - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/configuration.hpp b/godot/thirdparty/libdatachannel/include/rtc/configuration.hpp deleted file mode 100644 index feb34abb..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/configuration.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_ICE_CONFIGURATION_H -#define RTC_ICE_CONFIGURATION_H - -#include "common.hpp" - -#include - -namespace rtc { - -struct RTC_CPP_EXPORT IceServer { - enum class Type { Stun, Turn }; - enum class RelayType { TurnUdp, TurnTcp, TurnTls }; - - // Any type - IceServer(const string &url); - - // STUN - IceServer(string hostname_, uint16_t port_); - IceServer(string hostname_, string service_); - - // TURN - IceServer(string hostname_, uint16_t port, string username_, string password_, - RelayType relayType_ = RelayType::TurnUdp); - IceServer(string hostname_, string service_, string username_, string password_, - RelayType relayType_ = RelayType::TurnUdp); - - string hostname; - uint16_t port; - Type type; - string username; - string password; - RelayType relayType; -}; - -struct RTC_CPP_EXPORT ProxyServer { - enum class Type { Http, Socks5 }; - - ProxyServer(const string &url); - - ProxyServer(Type type_, string hostname_, uint16_t port_); - ProxyServer(Type type_, string hostname_, uint16_t port_, string username_, string password_); - - Type type; - string hostname; - uint16_t port; - optional username; - optional password; -}; - -enum class CertificateType { - Default = RTC_CERTIFICATE_DEFAULT, // ECDSA - Ecdsa = RTC_CERTIFICATE_ECDSA, - Rsa = RTC_CERTIFICATE_RSA -}; - -enum class TransportPolicy { All = RTC_TRANSPORT_POLICY_ALL, Relay = RTC_TRANSPORT_POLICY_RELAY }; - -struct RTC_CPP_EXPORT Configuration { - // ICE settings - std::vector iceServers; - optional proxyServer; // libnice only - optional bindAddress; // libjuice only, default any - - // Options - CertificateType certificateType = CertificateType::Default; - TransportPolicy iceTransportPolicy = TransportPolicy::All; - bool enableIceTcp = false; // libnice only - bool enableIceUdpMux = false; // libjuice only - bool disableAutoNegotiation = false; - bool forceMediaTransport = false; - - // Port range - uint16_t portRangeBegin = 1024; - uint16_t portRangeEnd = 65535; - - // Network MTU - optional mtu; - - // Local maximum message size for Data Channels - optional maxMessageSize; -}; - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/datachannel.hpp b/godot/thirdparty/libdatachannel/include/rtc/datachannel.hpp deleted file mode 100644 index ca7744d0..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/datachannel.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_DATA_CHANNEL_H -#define RTC_DATA_CHANNEL_H - -#include "channel.hpp" -#include "common.hpp" -#include "reliability.hpp" - -#include - -namespace rtc { - -namespace impl { - -struct DataChannel; -struct PeerConnection; - -} // namespace impl - -class RTC_CPP_EXPORT DataChannel final : private CheshireCat, public Channel { -public: - DataChannel(impl_ptr impl); - ~DataChannel() override; - - optional stream() const; - optional id() const; - string label() const; - string protocol() const; - Reliability reliability() const; - - bool isOpen(void) const override; - bool isClosed(void) const override; - size_t maxMessageSize() const override; - - void close(void) override; - RTC_WRAPPED(bool) send(message_variant data) override; - RTC_WRAPPED(bool) send(const byte *data, size_t size) override; - template RTC_WRAPPED(bool) sendBuffer(const Buffer &buf); - template RTC_WRAPPED(bool) sendBuffer(Iterator first, Iterator last); - -private: - using CheshireCat::impl; -}; - -template std::pair to_bytes(const Buffer &buf) { - using T = typename std::remove_pointer::type; - using E = typename std::conditional::value, byte, T>::type; - return std::make_pair(static_cast(static_cast(buf.data())), - buf.size() * sizeof(E)); -} - -template RTC_WRAPPED(bool) DataChannel::sendBuffer(const Buffer &buf) { - auto [bytes, size] = to_bytes(buf); - return send(bytes, size); -} - -template RTC_WRAPPED(bool) DataChannel::sendBuffer(Iterator first, Iterator last) { - size_t size = 0; - for (Iterator it = first; it != last; ++it) - size += it->size(); - - binary buffer(size); - byte *pos = buffer.data(); - for (Iterator it = first; it != last; ++it) { - auto [bytes, len] = to_bytes(*it); - pos = std::copy(bytes, bytes + len, pos); - } - return send(std::move(buffer)); -} - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/description.hpp b/godot/thirdparty/libdatachannel/include/rtc/description.hpp deleted file mode 100644 index ab8661b5..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/description.hpp +++ /dev/null @@ -1,324 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * Copyright (c) 2020 Staz Modrzynski - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_DESCRIPTION_H -#define RTC_DESCRIPTION_H - -#include "candidate.hpp" -#include "common.hpp" - -#include -#include -#include - -namespace rtc { - -const string DEFAULT_OPUS_AUDIO_PROFILE = - "minptime=10;maxaveragebitrate=96000;stereo=1;sprop-stereo=1;useinbandfec=1"; - -// Use Constrained Baseline profile Level 3.1 (necessary for Firefox) -// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#Supported_video_codecs -// TODO: Should be 42E0 but 42C0 appears to be more compatible. Investigate this. -const string DEFAULT_H264_VIDEO_PROFILE = - "profile-level-id=42e01f;packetization-mode=1;level-asymmetry-allowed=1"; - -class RTC_CPP_EXPORT Description { -public: - enum class Type { Unspec, Offer, Answer, Pranswer, Rollback }; - enum class Role { ActPass, Passive, Active }; - - enum class Direction { - SendOnly = RTC_DIRECTION_SENDONLY, - RecvOnly = RTC_DIRECTION_RECVONLY, - SendRecv = RTC_DIRECTION_SENDRECV, - Inactive = RTC_DIRECTION_INACTIVE, - Unknown = RTC_DIRECTION_UNKNOWN - }; - -private: - RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(Description); - Description(Type type = Type::Unspec, Role role = Role::ActPass); -public: - static RTC_WRAPPED(Description) create(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass); - static RTC_WRAPPED(Description) create(const string &sdp, string typeString); - - Type type() const; - string typeString() const; - Role role() const; - string bundleMid() const; - std::vector iceOptions() const; - optional iceUfrag() const; - optional icePwd() const; - optional fingerprint() const; - bool ended() const; - - void hintType(Type type); - RTC_WRAPPED(void) setFingerprint(string fingerprint); - void addIceOption(string option); - void removeIceOption(const string &option); - - std::vector attributes() const; - void addAttribute(string attr); - void removeAttribute(const string &attr); - - std::vector candidates() const; - std::vector extractCandidates(); - bool hasCandidate(const Candidate &candidate) const; - void addCandidate(Candidate candidate); - void addCandidates(std::vector candidates); - void endCandidates(); - - operator string() const; - string generateSdp(string_view eol = "\r\n") const; - string generateApplicationSdp(string_view eol = "\r\n") const; - - class RTC_CPP_EXPORT Entry { - public: - virtual ~Entry() = default; - - virtual string type() const; - virtual string description() const; - virtual string mid() const; - - Direction direction() const; - void setDirection(Direction dir); - - bool isRemoved() const; - void markRemoved(); - - std::vector attributes() const; - void addAttribute(string attr); - void removeAttribute(const string &attr); - void addRid(string rid); - - struct RTC_CPP_EXPORT ExtMap { - private: - RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(ExtMap); - ExtMap() {} - public: - static RTC_WRAPPED(int) parseId(string_view description); - - ExtMap(int id, string uri, Direction direction = Direction::Unknown); - static RTC_WRAPPED(ExtMap) create(string_view description); - - RTC_WRAPPED(void) setDescription(string_view description); - - int id; - string uri; - string attributes; - Direction direction = Direction::Unknown; - }; - - std::vector extIds(); - RTC_WRAPPED(ExtMap *) extMap(int id); - void addExtMap(ExtMap map); - void removeExtMap(int id); - - operator string() const; - string generateSdp(string_view eol = "\r\n", string_view addr = "0.0.0.0", - uint16_t port = 9) const; - - virtual RTC_WRAPPED(void) parseSdpLine(string_view line); - - protected: - Entry() {} - Entry(const string &mline, string mid, Direction dir = Direction::Unknown); - - virtual string generateSdpLines(string_view eol) const; - - std::vector mAttributes; - std::map mExtMaps; - - private: - string mType; - string mDescription; - string mMid; - std::vector mRids; - Direction mDirection; - bool mIsRemoved; - }; - - struct RTC_CPP_EXPORT Application : public Entry { - public: - Application(string mid = "data"); - Application(const string &mline, string mid); - virtual ~Application() = default; - - string description() const override; - Application reciprocate() const; - - void setSctpPort(uint16_t port); - void hintSctpPort(uint16_t port); - void setMaxMessageSize(size_t size); - - optional sctpPort() const; - optional maxMessageSize() const; - - virtual RTC_WRAPPED(void) parseSdpLine(string_view line) override; - - private: - virtual string generateSdpLines(string_view eol) const override; - - optional mSctpPort; - optional mMaxMessageSize; - }; - - // Media (non-data) - class RTC_CPP_EXPORT Media : public Entry { - RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(Media); - Media() {} - Media(const string &sdp); - public: - RTC_WRAPPED(Media) create(const string &sdp); - Media(const string &mline, string mid, Direction dir = Direction::SendOnly); - virtual ~Media() = default; - - string description() const override; - Media reciprocate() const; - - void addSSRC(uint32_t ssrc, optional name, optional msid = nullopt, - optional trackId = nullopt); - void removeSSRC(uint32_t ssrc); - void replaceSSRC(uint32_t old, uint32_t ssrc, optional name, - optional msid = nullopt, optional trackID = nullopt); - bool hasSSRC(uint32_t ssrc) const; - void clearSSRCs(); - std::vector getSSRCs() const; - optional getCNameForSsrc(uint32_t ssrc) const; - - int bitrate() const; - void setBitrate(int bitrate); - - struct RTC_CPP_EXPORT RtpMap { - private: - RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(RtpMap); - RtpMap() {} - public: - static RTC_WRAPPED(int) parsePayloadType(string_view description); - - explicit RtpMap(int payloadType); - static RTC_WRAPPED(RtpMap) create(string_view description); - - RTC_WRAPPED(void) setDescription(string_view description); - - void addFeedback(string fb); - void removeFeedback(const string &str); - void addParameter(string p); - void removeParameter(const string &str); - - int payloadType; - string format; - int clockRate; - string encParams; - - std::vector rtcpFbs; - std::vector fmtps; - }; - - bool hasPayloadType(int payloadType) const; - std::vector payloadTypes() const; - RTC_WRAPPED(RtpMap *) rtpMap(int payloadType); - void addRtpMap(RtpMap map); - void removeRtpMap(int payloadType); - void removeFormat(const string &format); - - RTC_WRAPPED(void) addRtxCodec(int payloadType, int origPayloadType, unsigned int clockRate); - - virtual RTC_WRAPPED(void) parseSdpLine(string_view line) override; - - private: - virtual string generateSdpLines(string_view eol) const override; - - int mBas = -1; - - std::map mRtpMaps; - std::vector mSsrcs; - std::map mCNameMap; - }; - - class RTC_CPP_EXPORT Audio : public Media { - public: - Audio(string mid = "audio", Direction dir = Direction::SendOnly); - - RTC_WRAPPED(void) addAudioCodec(int payloadType, string codec, optional profile = std::nullopt); - - RTC_WRAPPED(void) addOpusCodec(int payloadType, optional profile = DEFAULT_OPUS_AUDIO_PROFILE); - RTC_WRAPPED(void) addPCMACodec(int payloadType, optional profile = std::nullopt); - RTC_WRAPPED(void) addPCMUCodec(int payloadType, optional profile = std::nullopt); - RTC_WRAPPED(void) addAacCodec(int payloadType, optional profile = std::nullopt); - }; - - class RTC_CPP_EXPORT Video : public Media { - public: - Video(string mid = "video", Direction dir = Direction::SendOnly); - - RTC_WRAPPED(void) addVideoCodec(int payloadType, string codec, optional profile = std::nullopt); - - RTC_WRAPPED(void) addH264Codec(int payloadType, optional profile = DEFAULT_H264_VIDEO_PROFILE); - RTC_WRAPPED(void) addH265Codec(int payloadType, optional profile = std::nullopt); - RTC_WRAPPED(void) addVP8Codec(int payloadType, optional profile = std::nullopt); - RTC_WRAPPED(void) addVP9Codec(int payloadType, optional profile = std::nullopt); - RTC_WRAPPED(void) addAV1Codec(int payloadType, optional profile = std::nullopt); - }; - - bool hasApplication() const; - bool hasAudioOrVideo() const; - bool hasMid(string_view mid) const; - - int addMedia(Media media); - int addMedia(Application application); - int addApplication(string mid = "data"); - int addVideo(string mid = "video", Direction dir = Direction::SendOnly); - int addAudio(string mid = "audio", Direction dir = Direction::SendOnly); - void clearMedia(); - - RTC_WRAPPED(variant) media(unsigned int index); - RTC_WRAPPED(variant) media(unsigned int index) const; - - unsigned int mediaCount() const; - - const Application *application() const; - Application *application(); - - static Type stringToType(const string &typeString); - static string typeToString(Type type); - -private: - optional defaultCandidate() const; - shared_ptr createEntry(string mline, string mid, Direction dir); - void removeApplication(); - - Type mType; - - // Session-level attributes - Role mRole; - string mUsername; - string mSessionId; - std::vector mIceOptions; - optional mIceUfrag, mIcePwd; - optional mFingerprint; - std::vector mAttributes; // other attributes - - // Entries - std::vector> mEntries; - shared_ptr mApplication; - - // Candidates - std::vector mCandidates; - bool mEnded = false; -}; - -} // namespace rtc - -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Description &description); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Type type); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Role role); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Description::Direction &direction); - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/exception_wrapper_godot.hpp b/godot/thirdparty/libdatachannel/include/rtc/exception_wrapper_godot.hpp deleted file mode 100644 index b9202588..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/exception_wrapper_godot.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef EXCEPTION_WRAPPER_GODOT_HPP_ -#define EXCEPTION_WRAPPER_GODOT_HPP_ -#include "rtc/rtc.hpp" - -class LibDataChannelExceptionWrapper { -public: - static void close_data_channel(std::shared_ptr p_channel); - static void close_peer_connection(std::shared_ptr p_peer_connection); - static bool put_packet(std::shared_ptr p_channel, const uint8_t *p_buffer, int32_t p_len, bool p_is_text, std::string &r_error); - static std::shared_ptr create_data_channel(std::shared_ptr p_peer_connection, const char *p_label, rtc::DataChannelInit p_config, std::string &r_error); - static std::shared_ptr create_peer_connection(const rtc::Configuration &p_config, std::string &r_error); - static bool create_offer(std::shared_ptr p_peer_connection, std::string &r_error); - static bool set_remote_description(std::shared_ptr p_peer_connection, const char *p_type, const char *p_sdp, std::string &r_error); - static bool add_ice_candidate(std::shared_ptr p_peer_connection, const char *p_sdp_mid_name, const char *p_sdp_name, std::string &r_error); -}; - -#endif // EXCEPTION_WRAPPER_GODOT_H_ diff --git a/godot/thirdparty/libdatachannel/include/rtc/global.hpp b/godot/thirdparty/libdatachannel/include/rtc/global.hpp deleted file mode 100644 index b4910e09..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/global.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_GLOBAL_H -#define RTC_GLOBAL_H - -#include "common.hpp" - -#include -#include -#include - -namespace rtc { - -enum class LogLevel { // Don't change, it must match plog severity - None = 0, - Fatal = 1, - Error = 2, - Warning = 3, - Info = 4, - Debug = 5, - Verbose = 6 -}; - -typedef std::function LogCallback; - -RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr); - -RTC_CPP_EXPORT void Preload(); -RTC_CPP_EXPORT std::shared_future Cleanup(); - -struct SctpSettings { - // For the following settings, not set means optimized default - optional recvBufferSize; // in bytes - optional sendBufferSize; // in bytes - optional maxChunksOnQueue; // in chunks - optional initialCongestionWindow; // in MTUs - optional maxBurst; // in MTUs - optional congestionControlModule; // 0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC - optional delayedSackTime; - optional minRetransmitTimeout; - optional maxRetransmitTimeout; - optional initialRetransmitTimeout; - optional maxRetransmitAttempts; - optional heartbeatInterval; -}; - -RTC_CPP_EXPORT RTC_WRAPPED(void) SetSctpSettings(SctpSettings s); - -} // namespace rtc - -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level); - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/h264packetizationhandler.hpp b/godot/thirdparty/libdatachannel/include/rtc/h264packetizationhandler.hpp deleted file mode 100644 index fe4859be..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/h264packetizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H264_PACKETIZATION_HANDLER_H -#define RTC_H264_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "h264rtppacketizer.hpp" -#include "mediachainablehandler.hpp" -#include "nalunit.hpp" - -namespace rtc { - -/// Handler for H264 packetization -class RTC_CPP_EXPORT H264PacketizationHandler final : public MediaChainableHandler { -public: - /// Construct handler for H264 packetization. - /// @param packetizer RTP packetizer for h264 - H264PacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_H264_PACKETIZATION_HANDLER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/h264rtppacketizer.hpp b/godot/thirdparty/libdatachannel/include/rtc/h264rtppacketizer.hpp deleted file mode 100644 index 63f01e98..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/h264rtppacketizer.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H264_RTP_PACKETIZER_H -#define RTC_H264_RTP_PACKETIZER_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerrootelement.hpp" -#include "nalunit.hpp" -#include "rtppacketizer.hpp" - -namespace rtc { - -/// RTP packetization of h264 payload -class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, - public MediaHandlerRootElement { - shared_ptr splitMessage(binary_ptr message); - const uint16_t maximumFragmentSize; - -public: - using Separator = NalUnit::Separator; - - /// Default clock rate for H264 in RTP - inline static const uint32_t defaultClockRate = 90 * 1000; - - H264RtpPacketizer(Separator separator, shared_ptr rtpConfig, - uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); - - /// Constructs h264 payload packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - /// @param maximumFragmentSize maximum size of one NALU fragment - H264RtpPacketizer(shared_ptr rtpConfig, - uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); - - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; - -private: - const Separator separator; -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_H264_RTP_PACKETIZER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/h265nalunit.hpp b/godot/thirdparty/libdatachannel/include/rtc/h265nalunit.hpp deleted file mode 100644 index 5fec563f..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/h265nalunit.hpp +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Copyright (c) 2023 Zita Liao (Dolby) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H265_NAL_UNIT_H -#define RTC_H265_NAL_UNIT_H - -#if RTC_ENABLE_MEDIA - -#include "common.hpp" -#include "nalunit.hpp" - -#include - -namespace rtc { - -#pragma pack(push, 1) - -#define H265_FU_HEADER_SIZE 1 -/// Nalu header -struct RTC_CPP_EXPORT H265NalUnitHeader { - /* - * nal_unit_header( ) { - * forbidden_zero_bit f(1) - * nal_unit_type u(6) - * nuh_layer_id u(6) - * nuh_temporal_id_plus1 u(3) - } - */ - uint8_t _first = 0; // high byte of header - uint8_t _second = 0; // low byte of header - - bool forbiddenBit() const { return _first >> 7; } - uint8_t unitType() const { return (_first & 0b0111'1110) >> 1; } - uint8_t nuhLayerId() const { return ((_first & 0x1) << 5) | ((_second & 0b1111'1000) >> 3); } - uint8_t nuhTempIdPlus1() const { return _second & 0b111; } - - void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } - void setUnitType(uint8_t type) { _first = (_first & 0b1000'0001) | ((type & 0b11'1111) << 1); } - void setNuhLayerId(uint8_t nuhLayerId) { - _first = (_first & 0b1111'1110) | ((nuhLayerId & 0b10'0000) >> 5); - _second = (_second & 0b0000'0111) | ((nuhLayerId & 0b01'1111) << 3); - } - void setNuhTempIdPlus1(uint8_t nuhTempIdPlus1) { - _second = (_second & 0b1111'1000) | (nuhTempIdPlus1 & 0b111); - } -}; - -/// Nalu fragment header -struct RTC_CPP_EXPORT H265NalUnitFragmentHeader { - /* - * +---------------+ - * |0|1|2|3|4|5|6|7| - * +-+-+-+-+-+-+-+-+ - * |S|E| FuType | - * +---------------+ - */ - uint8_t _first = 0; - - bool isStart() const { return _first >> 7; } - bool isEnd() const { return (_first >> 6) & 0x01; } - uint8_t unitType() const { return _first & 0b11'1111; } - - void setStart(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } - void setEnd(bool isSet) { _first = (_first & 0b1011'1111) | (isSet << 6); } - void setUnitType(uint8_t type) { _first = (_first & 0b1100'0000) | (type & 0b11'1111); } -}; - -#pragma pack(pop) - -/// Nal unit -struct RTC_CPP_EXPORT H265NalUnit : NalUnit { - H265NalUnit(const H265NalUnit &unit) = default; - H265NalUnit(size_t size, bool includingHeader = true) - : NalUnit(size, includingHeader, NalUnit::Type::H265) {} - H265NalUnit(binary &&data) : NalUnit(std::move(data)) {} - H265NalUnit() : NalUnit(NalUnit::Type::H265) {} - - template - H265NalUnit(Iterator begin_, Iterator end_) : NalUnit(begin_, end_) {} - - bool forbiddenBit() const { return header()->forbiddenBit(); } - uint8_t unitType() const { return header()->unitType(); } - uint8_t nuhLayerId() const { return header()->nuhLayerId(); } - uint8_t nuhTempIdPlus1() const { return header()->nuhTempIdPlus1(); } - - binary payload() const { - assert(size() >= H265_NAL_HEADER_SIZE); - return {begin() + H265_NAL_HEADER_SIZE, end()}; - } - - void setForbiddenBit(bool isSet) { header()->setForbiddenBit(isSet); } - void setUnitType(uint8_t type) { header()->setUnitType(type); } - void setNuhLayerId(uint8_t nuhLayerId) { header()->setNuhLayerId(nuhLayerId); } - void setNuhTempIdPlus1(uint8_t nuhTempIdPlus1) { header()->setNuhTempIdPlus1(nuhTempIdPlus1); } - - void setPayload(binary payload) { - assert(size() >= H265_NAL_HEADER_SIZE); - erase(begin() + H265_NAL_HEADER_SIZE, end()); - insert(end(), payload.begin(), payload.end()); - } - -protected: - const H265NalUnitHeader *header() const { - assert(size() >= H265_NAL_HEADER_SIZE); - return reinterpret_cast(data()); - } - - H265NalUnitHeader *header() { - assert(size() >= H265_NAL_HEADER_SIZE); - return reinterpret_cast(data()); - } -}; - -/// Nal unit fragment A -struct RTC_CPP_EXPORT H265NalUnitFragment : H265NalUnit { - static std::vector> fragmentsFrom(shared_ptr nalu, - uint16_t maximumFragmentSize); - - enum class FragmentType { Start, Middle, End }; - - H265NalUnitFragment(FragmentType type, bool forbiddenBit, uint8_t nuhLayerId, - uint8_t nuhTempIdPlus1, uint8_t unitType, binary data); - - uint8_t unitType() const { return fragmentHeader()->unitType(); } - - binary payload() const { - assert(size() >= H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE); - return {begin() + H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE, end()}; - } - - FragmentType type() const { - if (fragmentHeader()->isStart()) { - return FragmentType::Start; - } else if (fragmentHeader()->isEnd()) { - return FragmentType::End; - } else { - return FragmentType::Middle; - } - } - - void setUnitType(uint8_t type) { fragmentHeader()->setUnitType(type); } - - void setPayload(binary payload) { - assert(size() >= H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE); - erase(begin() + H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE, end()); - insert(end(), payload.begin(), payload.end()); - } - - void setFragmentType(FragmentType type); - -protected: - const uint8_t nal_type_fu = 49; - - H265NalUnitHeader *fragmentIndicator() { return reinterpret_cast(data()); } - - const H265NalUnitHeader *fragmentIndicator() const { - return reinterpret_cast(data()); - } - - H265NalUnitFragmentHeader *fragmentHeader() { - return reinterpret_cast(fragmentIndicator() + - H265_NAL_HEADER_SIZE); - } - - const H265NalUnitFragmentHeader *fragmentHeader() const { - return reinterpret_cast(fragmentIndicator() + - H265_NAL_HEADER_SIZE); - } -}; - -class RTC_CPP_EXPORT H265NalUnits : public std::vector> { -public: - static const uint16_t defaultMaximumFragmentSize = - uint16_t(RTC_DEFAULT_MTU - 12 - 8 - 40); // SRTP/UDP/IPv6 - - std::vector> generateFragments(uint16_t maximumFragmentSize); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_NAL_UNIT_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/h265packetizationhandler.hpp b/godot/thirdparty/libdatachannel/include/rtc/h265packetizationhandler.hpp deleted file mode 100644 index 17fb25b8..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/h265packetizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2023 Zita Liao (Dolby) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H265_PACKETIZATION_HANDLER_H -#define RTC_H265_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "h265nalunit.hpp" -#include "h265rtppacketizer.hpp" -#include "mediachainablehandler.hpp" - -namespace rtc { - -/// Handler for H265 packetization -class RTC_CPP_EXPORT H265PacketizationHandler final : public MediaChainableHandler { -public: - /// Construct handler for H265 packetization. - /// @param packetizer RTP packetizer for h265 - H265PacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_H265_PACKETIZATION_HANDLER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/h265rtppacketizer.hpp b/godot/thirdparty/libdatachannel/include/rtc/h265rtppacketizer.hpp deleted file mode 100644 index 02e68692..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/h265rtppacketizer.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2023 Zita Liao (Dolby) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H265_RTP_PACKETIZER_H -#define RTC_H265_RTP_PACKETIZER_H - -#if RTC_ENABLE_MEDIA - -#include "h265nalunit.hpp" -#include "mediahandlerrootelement.hpp" -#include "rtppacketizer.hpp" - -namespace rtc { - -/// RTP packetization of h265 payload -class RTC_CPP_EXPORT H265RtpPacketizer final : public RtpPacketizer, - public MediaHandlerRootElement { - shared_ptr splitMessage(binary_ptr message); - const uint16_t maximumFragmentSize; - -public: - using Separator = NalUnit::Separator; - - /// Default clock rate for H265 in RTP - inline static const uint32_t defaultClockRate = 90 * 1000; - - H265RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, - uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); - - /// Constructs h265 payload packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - /// @param maximumFragmentSize maximum size of one NALU fragment - H265RtpPacketizer(shared_ptr rtpConfig, - uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); - - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; - -private: - const NalUnit::Separator separator; -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_H265_RTP_PACKETIZER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/mediachainablehandler.hpp b/godot/thirdparty/libdatachannel/include/rtc/mediachainablehandler.hpp deleted file mode 100644 index 05ca3ef2..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/mediachainablehandler.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_CHAINABLE_HANDLER_H -#define RTC_MEDIA_CHAINABLE_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandler.hpp" -#include "mediahandlerrootelement.hpp" - -namespace rtc { - -class RTC_CPP_EXPORT MediaChainableHandler : public MediaHandler { - const shared_ptr root; - shared_ptr leaf; - mutable std::mutex mutex; - - message_ptr handleIncomingBinary(message_ptr); - message_ptr handleIncomingControl(message_ptr); - message_ptr handleOutgoingBinary(message_ptr); - message_ptr handleOutgoingControl(message_ptr); - bool sendProduct(ChainedOutgoingProduct product); - shared_ptr getLeaf() const; - -public: - MediaChainableHandler(shared_ptr root); - ~MediaChainableHandler(); - message_ptr incoming(message_ptr ptr) override; - message_ptr outgoing(message_ptr ptr) override; - - bool send(message_ptr msg); - - /// Adds element to chain - /// @param chainable Chainable element - void addToChain(shared_ptr chainable); -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_MEDIA_CHAINABLE_HANDLER_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/mediahandler.hpp b/godot/thirdparty/libdatachannel/include/rtc/mediahandler.hpp deleted file mode 100644 index 24c602e1..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/mediahandler.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2020 Staz Modrzynski - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_HANDLER_H -#define RTC_MEDIA_HANDLER_H - -#include "common.hpp" -#include "message.hpp" - -namespace rtc { - -class RTC_CPP_EXPORT MediaHandler { -protected: - // Use this callback when trying to send custom data (such as RTCP) to the client. - synchronized_callback outgoingCallback; - -public: - virtual ~MediaHandler() = default; - - // Called when there is traffic coming from the peer - virtual message_ptr incoming(message_ptr ptr) = 0; - - // Called when there is traffic that needs to be sent to the peer - virtual message_ptr outgoing(message_ptr ptr) = 0; - - // This callback is used to send traffic back to the peer. - void onOutgoing(const std::function &cb) { - this->outgoingCallback = synchronized_callback(cb); - } - - virtual bool requestKeyframe() { return false; } -}; - -} // namespace rtc - -#endif // RTC_MEDIA_HANDLER_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp b/godot/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp deleted file mode 100644 index 600bf233..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_HANDLER_ELEMENT_H -#define RTC_MEDIA_HANDLER_ELEMENT_H - -#if RTC_ENABLE_MEDIA - -#include "common.hpp" -#include "message.hpp" -#include "rtp.hpp" - -namespace rtc { - -using ChainedMessagesProduct = shared_ptr>; - -RTC_CPP_EXPORT ChainedMessagesProduct make_chained_messages_product(); -RTC_CPP_EXPORT ChainedMessagesProduct make_chained_messages_product(message_ptr msg); - -/// Ougoing messages -struct RTC_CPP_EXPORT ChainedOutgoingProduct { - ChainedOutgoingProduct(ChainedMessagesProduct messages = nullptr, - message_ptr control = nullptr); - const ChainedMessagesProduct messages; - const message_ptr control; -}; - -/// Incoming messages with response -struct RTC_CPP_EXPORT ChainedIncomingProduct { - ChainedIncomingProduct(ChainedMessagesProduct incoming = nullptr, - ChainedMessagesProduct outgoing = nullptr); - const ChainedMessagesProduct incoming; - const ChainedOutgoingProduct outgoing; -}; - -/// Incoming control messages with response -struct RTC_CPP_EXPORT ChainedIncomingControlProduct { - ChainedIncomingControlProduct(message_ptr incoming, - optional outgoing = nullopt); - const message_ptr incoming; - const optional outgoing; -}; - -/// Chainable handler -class RTC_CPP_EXPORT MediaHandlerElement - : public std::enable_shared_from_this { - shared_ptr upstream = nullptr; - shared_ptr downstream = nullptr; - - void prepareAndSendResponse(optional outgoing, - std::function send); - - void removeFromChain(); - -public: - MediaHandlerElement(); - - virtual ~MediaHandlerElement() = default; - - /// Creates response to incoming message - /// @param messages Current repsonse - /// @returns New response - optional processOutgoingResponse(ChainedOutgoingProduct messages); - - // Process incoming and ougoing messages - message_ptr formIncomingControlMessage(message_ptr message, - std::function send); - ChainedMessagesProduct - formIncomingBinaryMessage(ChainedMessagesProduct messages, - std::function send); - message_ptr formOutgoingControlMessage(message_ptr message); - optional formOutgoingBinaryMessage(ChainedOutgoingProduct product); - - /// Process current control message - /// @param messages current message - /// @returns Modified message and response - virtual ChainedIncomingControlProduct processIncomingControlMessage(message_ptr messages); - - /// Process current control message - /// @param messages current message - /// @returns Modified message - virtual message_ptr processOutgoingControlMessage(message_ptr messages); - - /// Process current binary message - /// @param messages current message - /// @returns Modified message and response - virtual ChainedIncomingProduct processIncomingBinaryMessage(ChainedMessagesProduct messages); - - /// Process current binary message - /// @param messages current message - /// @param control current control message - /// @returns Modified binary message and control message - virtual ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control); - - /// Set given element as upstream to this - /// @param upstream Upstream element - /// @returns Upstream element - shared_ptr chainWith(shared_ptr upstream); - - /// Remove all downstream elements from chain - void recursiveRemoveChain(); -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_MEDIA_HANDLER_ELEMENT_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/mediahandlerrootelement.hpp b/godot/thirdparty/libdatachannel/include/rtc/mediahandlerrootelement.hpp deleted file mode 100644 index 74ee2839..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/mediahandlerrootelement.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_HANDLER_ROOT_ELEMENT_H -#define RTC_MEDIA_HANDLER_ROOT_ELEMENT_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerelement.hpp" - -namespace rtc { - -/// Chainable message handler -class RTC_CPP_EXPORT MediaHandlerRootElement : public MediaHandlerElement { -public: - MediaHandlerRootElement() {} - - /// Reduce multiple messages into one message - /// @param messages Messages to reduce - virtual message_ptr reduce(ChainedMessagesProduct messages); - - /// Splits message into multiple messages - /// @param message Message to split - virtual ChainedMessagesProduct split(message_ptr message); -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_MEDIA_HANDLER_ROOT_ELEMENT_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/message.hpp b/godot/thirdparty/libdatachannel/include/rtc/message.hpp deleted file mode 100644 index 9a064f23..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/message.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MESSAGE_H -#define RTC_MESSAGE_H - -#include "common.hpp" -#include "reliability.hpp" - -#include - -namespace rtc { - -struct RTC_CPP_EXPORT Message : binary { - enum Type { Binary, String, Control, Reset }; - - Message(const Message &message) = default; - Message(size_t size, Type type_ = Binary) : binary(size), type(type_) {} - - template - Message(Iterator begin_, Iterator end_, Type type_ = Binary) - : binary(begin_, end_), type(type_) {} - - Message(binary &&data, Type type_ = Binary) : binary(std::move(data)), type(type_) {} - - Type type; - unsigned int stream = 0; // Stream id (SCTP stream or SSRC) - unsigned int dscp = 0; // Differentiated Services Code Point - shared_ptr reliability; -}; - -using message_ptr = shared_ptr; -using message_callback = std::function; - -inline size_t message_size_func(const message_ptr &m) { - return m->type == Message::Binary || m->type == Message::String ? m->size() : 0; -} - -template -message_ptr make_message(Iterator begin, Iterator end, Message::Type type = Message::Binary, - unsigned int stream = 0, shared_ptr reliability = nullptr) { - auto message = std::make_shared(begin, end, type); - message->stream = stream; - message->reliability = reliability; - return message; -} - -RTC_CPP_EXPORT message_ptr make_message(size_t size, Message::Type type = Message::Binary, - unsigned int stream = 0, - shared_ptr reliability = nullptr); - -RTC_CPP_EXPORT message_ptr make_message(binary &&data, Message::Type type = Message::Binary, - unsigned int stream = 0, - shared_ptr reliability = nullptr); - -RTC_CPP_EXPORT message_ptr make_message(message_variant data); - -#if RTC_ENABLE_MEDIA - -// Reconstructs a message_ptr from an opaque rtcMessage pointer that -// was allocated by rtcCreateOpaqueMessage(). -message_ptr make_message_from_opaque_ptr(rtcMessage *&&message); - -#endif - -RTC_CPP_EXPORT message_variant to_variant(Message &&message); -RTC_CPP_EXPORT message_variant to_variant(const Message &message); - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/nalunit.hpp b/godot/thirdparty/libdatachannel/include/rtc/nalunit.hpp deleted file mode 100644 index b59c1bf7..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/nalunit.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_NAL_UNIT_H -#define RTC_NAL_UNIT_H - -#if RTC_ENABLE_MEDIA - -#include "common.hpp" - -#include - -namespace rtc { - -#pragma pack(push, 1) - -/// Nalu header -struct RTC_CPP_EXPORT NalUnitHeader { - uint8_t _first = 0; - - bool forbiddenBit() const { return _first >> 7; } - uint8_t nri() const { return _first >> 5 & 0x03; } - uint8_t unitType() const { return _first & 0x1F; } - - void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } - void setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); } - void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); } -}; - -/// Nalu fragment header -struct RTC_CPP_EXPORT NalUnitFragmentHeader { - uint8_t _first = 0; - - bool isStart() const { return _first >> 7; } - bool reservedBit6() const { return (_first >> 5) & 0x01; } - bool isEnd() const { return (_first >> 6) & 0x01; } - uint8_t unitType() const { return _first & 0x1F; } - - void setStart(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } - void setEnd(bool isSet) { _first = (_first & 0xBF) | (isSet << 6); } - void setReservedBit6(bool isSet) { _first = (_first & 0xDF) | (isSet << 5); } - void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); } -}; - -#pragma pack(pop) - -typedef enum { - NUSM_noMatch, - NUSM_firstZero, - NUSM_secondZero, - NUSM_thirdZero, - NUSM_shortMatch, - NUSM_longMatch -} NalUnitStartSequenceMatch; - -static const size_t H264_NAL_HEADER_SIZE = 1; -static const size_t H265_NAL_HEADER_SIZE = 2; -/// Nal unit -struct RTC_CPP_EXPORT NalUnit : binary { - typedef enum { H264, H265 } Type; - - NalUnit(const NalUnit &unit) = default; - NalUnit(size_t size, bool includingHeader = true, Type type = H264) - : binary(size + (includingHeader - ? 0 - : (type == H264 ? H264_NAL_HEADER_SIZE : H265_NAL_HEADER_SIZE))) {} - NalUnit(binary &&data) : binary(std::move(data)) {} - NalUnit(Type type = H264) - : binary(type == H264 ? H264_NAL_HEADER_SIZE : H265_NAL_HEADER_SIZE) {} - template NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {} - - bool forbiddenBit() const { return header()->forbiddenBit(); } - uint8_t nri() const { return header()->nri(); } - uint8_t unitType() const { return header()->unitType(); } - - binary payload() const { - assert(size() >= 1); - return {begin() + 1, end()}; - } - - void setForbiddenBit(bool isSet) { header()->setForbiddenBit(isSet); } - void setNRI(uint8_t nri) { header()->setNRI(nri); } - void setUnitType(uint8_t type) { header()->setUnitType(type); } - - void setPayload(binary payload) { - assert(size() >= 1); - erase(begin() + 1, end()); - insert(end(), payload.begin(), payload.end()); - } - - /// NAL unit separator - enum class Separator { - Length = RTC_NAL_SEPARATOR_LENGTH, // first 4 bytes are NAL unit length - LongStartSequence = RTC_NAL_SEPARATOR_LONG_START_SEQUENCE, // 0x00, 0x00, 0x00, 0x01 - ShortStartSequence = RTC_NAL_SEPARATOR_SHORT_START_SEQUENCE, // 0x00, 0x00, 0x01 - StartSequence = RTC_NAL_SEPARATOR_START_SEQUENCE, // LongStartSequence or ShortStartSequence - }; - - static NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, - std::byte _byte, Separator separator) { - assert(separator != Separator::Length); - auto byte = (uint8_t)_byte; - auto detectShort = - separator == Separator::ShortStartSequence || separator == Separator::StartSequence; - auto detectLong = - separator == Separator::LongStartSequence || separator == Separator::StartSequence; - switch (match) { - case NUSM_noMatch: - if (byte == 0x00) { - return NUSM_firstZero; - } - break; - case NUSM_firstZero: - if (byte == 0x00) { - return NUSM_secondZero; - } - break; - case NUSM_secondZero: - if (byte == 0x00 && detectLong) { - return NUSM_thirdZero; - } else if (byte == 0x00 && detectShort) { - return NUSM_secondZero; - } else if (byte == 0x01 && detectShort) { - return NUSM_shortMatch; - } - break; - case NUSM_thirdZero: - if (byte == 0x00 && detectLong) { - return NUSM_thirdZero; - } else if (byte == 0x01 && detectLong) { - return NUSM_longMatch; - } - break; - case NUSM_shortMatch: - return NUSM_shortMatch; - case NUSM_longMatch: - return NUSM_longMatch; - } - return NUSM_noMatch; - } - -protected: - const NalUnitHeader *header() const { - assert(size() >= 1); - return reinterpret_cast(data()); - } - - NalUnitHeader *header() { - assert(size() >= 1); - return reinterpret_cast(data()); - } -}; - -/// Nal unit fragment A -struct RTC_CPP_EXPORT NalUnitFragmentA : NalUnit { - static std::vector> fragmentsFrom(shared_ptr nalu, - uint16_t maximumFragmentSize); - - enum class FragmentType { Start, Middle, End }; - - NalUnitFragmentA(FragmentType type, bool forbiddenBit, uint8_t nri, uint8_t unitType, - binary data); - - uint8_t unitType() const { return fragmentHeader()->unitType(); } - - binary payload() const { - assert(size() >= 2); - return {begin() + 2, end()}; - } - - FragmentType type() const { - if (fragmentHeader()->isStart()) { - return FragmentType::Start; - } else if (fragmentHeader()->isEnd()) { - return FragmentType::End; - } else { - return FragmentType::Middle; - } - } - - void setUnitType(uint8_t type) { fragmentHeader()->setUnitType(type); } - - void setPayload(binary payload) { - assert(size() >= 2); - erase(begin() + 2, end()); - insert(end(), payload.begin(), payload.end()); - } - - void setFragmentType(FragmentType type); - -protected: - const uint8_t nal_type_fu_A = 28; - - NalUnitHeader *fragmentIndicator() { return reinterpret_cast(data()); } - - const NalUnitHeader *fragmentIndicator() const { - return reinterpret_cast(data()); - } - - NalUnitFragmentHeader *fragmentHeader() { - return reinterpret_cast(fragmentIndicator() + 1); - } - - const NalUnitFragmentHeader *fragmentHeader() const { - return reinterpret_cast(fragmentIndicator() + 1); - } -}; - -class RTC_CPP_EXPORT NalUnits : public std::vector> { -public: - static const uint16_t defaultMaximumFragmentSize = - uint16_t(RTC_DEFAULT_MTU - 12 - 8 - 40); // SRTP/UDP/IPv6 - - std::vector> generateFragments(uint16_t maximumFragmentSize); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_NAL_UNIT_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/opuspacketizationhandler.hpp b/godot/thirdparty/libdatachannel/include/rtc/opuspacketizationhandler.hpp deleted file mode 100644 index 624058d1..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/opuspacketizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_OPUS_PACKETIZATION_HANDLER_H -#define RTC_OPUS_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "mediachainablehandler.hpp" -#include "opusrtppacketizer.hpp" - -namespace rtc { - -/// Handler for opus packetization -class RTC_CPP_EXPORT OpusPacketizationHandler final : public MediaChainableHandler { - -public: - /// Construct handler for opus packetization. - /// @param packetizer RTP packetizer for opus - OpusPacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_OPUS_PACKETIZATION_HANDLER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/opusrtppacketizer.hpp b/godot/thirdparty/libdatachannel/include/rtc/opusrtppacketizer.hpp deleted file mode 100644 index 2cddf469..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/opusrtppacketizer.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_OPUS_RTP_PACKETIZER_H -#define RTC_OPUS_RTP_PACKETIZER_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerrootelement.hpp" -#include "rtppacketizer.hpp" - -namespace rtc { - -/// RTP packetizer for opus -class RTC_CPP_EXPORT OpusRtpPacketizer final : public RtpPacketizer, - public MediaHandlerRootElement { -public: - /// default clock rate used in opus RTP communication - inline static const uint32_t defaultClockRate = 48 * 1000; - - /// Constructs opus packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - OpusRtpPacketizer(shared_ptr rtpConfig); - - /// Creates RTP packet for given payload based on `rtpConfig`. - /// @note This function increase sequence number after packetization. - /// @param payload RTP payload - /// @param setMark This needs to be `false` for all RTP packets with opus payload - binary_ptr packetize(binary_ptr payload, bool setMark) override; - - /// Creates RTP packet for given samples (all samples share same RTP timesamp) - /// @param messages opus samples - /// @param control RTCP - /// @returns RTP packets and unchanged `control` - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_OPUS_RTP_PACKETIZER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/peerconnection.hpp b/godot/thirdparty/libdatachannel/include/rtc/peerconnection.hpp deleted file mode 100644 index ebcd41f9..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/peerconnection.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_PEER_CONNECTION_H -#define RTC_PEER_CONNECTION_H - -#include "candidate.hpp" -#include "common.hpp" -#include "configuration.hpp" -#include "datachannel.hpp" -#include "description.hpp" -#include "reliability.hpp" -#include "track.hpp" - -#include -#include - -namespace rtc { - -namespace impl { - -struct PeerConnection; - -} - -struct RTC_CPP_EXPORT DataChannelInit { - Reliability reliability = {}; - bool negotiated = false; - optional id = nullopt; - string protocol = ""; -}; - -class RTC_CPP_EXPORT PeerConnection final : CheshireCat { -public: - enum class State : int { - New = RTC_NEW, - Connecting = RTC_CONNECTING, - Connected = RTC_CONNECTED, - Disconnected = RTC_DISCONNECTED, - Failed = RTC_FAILED, - Closed = RTC_CLOSED - }; - - enum class IceState : int { - New = RTC_ICE_NEW, - Checking = RTC_ICE_CHECKING, - Connected = RTC_ICE_CONNECTED, - Completed = RTC_ICE_COMPLETED, - Failed = RTC_ICE_FAILED, - Disconnected = RTC_ICE_DISCONNECTED, - Closed = RTC_ICE_CLOSED - }; - - enum class GatheringState : int { - New = RTC_GATHERING_NEW, - InProgress = RTC_GATHERING_INPROGRESS, - Complete = RTC_GATHERING_COMPLETE - }; - - enum class SignalingState : int { - Stable = RTC_SIGNALING_STABLE, - HaveLocalOffer = RTC_SIGNALING_HAVE_LOCAL_OFFER, - HaveRemoteOffer = RTC_SIGNALING_HAVE_REMOTE_OFFER, - HaveLocalPranswer = RTC_SIGNALING_HAVE_LOCAL_PRANSWER, - HaveRemotePranswer = RTC_SIGNALING_HAVE_REMOTE_PRANSWER, - }; - - PeerConnection(); - PeerConnection(Configuration config); - ~PeerConnection(); - - void close(); - - const Configuration *config() const; - State state() const; - IceState iceState() const; - GatheringState gatheringState() const; - SignalingState signalingState() const; - bool hasMedia() const; - optional localDescription() const; - optional remoteDescription() const; - optional localAddress() const; - optional remoteAddress() const; - uint16_t maxDataChannelId() const; - RTC_WRAPPED(bool) getSelectedCandidatePair(Candidate *local, Candidate *remote); - - RTC_WRAPPED(void) setLocalDescription(Description::Type type = Description::Type::Unspec); - RTC_WRAPPED(void) setRemoteDescription(Description description); - RTC_WRAPPED(void) addRemoteCandidate(Candidate candidate); - -#if RTC_ENABLE_MEDIA - void setMediaHandler(shared_ptr handler); - shared_ptr getMediaHandler(); -#endif - - [[nodiscard]] RTC_WRAPPED(shared_ptr) createDataChannel(string label, - DataChannelInit init = {}); - void onDataChannel(std::function dataChannel)> callback); - -#if RTC_ENABLE_MEDIA - [[nodiscard]] shared_ptr addTrack(Description::Media description); - void onTrack(std::function track)> callback); -#endif - - void onLocalDescription(std::function callback); - void onLocalCandidate(std::function callback); - void onStateChange(std::function callback); - void onIceStateChange(std::function callback); - void onGatheringStateChange(std::function callback); - void onSignalingStateChange(std::function callback); - - void resetCallbacks(); - - // Stats - void clearStats(); - size_t bytesSent(); - size_t bytesReceived(); - optional rtt(); -}; - -} // namespace rtc - -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::State state); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::IceState state); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, - rtc::PeerConnection::GatheringState state); -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, - rtc::PeerConnection::SignalingState state); - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/reliability.hpp b/godot/thirdparty/libdatachannel/include/rtc/reliability.hpp deleted file mode 100644 index 5a6296c3..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/reliability.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RELIABILITY_H -#define RTC_RELIABILITY_H - -#include "common.hpp" - -#include - -namespace rtc { - -struct Reliability { - enum class Type { Reliable = 0, Rexmit, Timed }; - - Type type = Type::Reliable; - bool unordered = false; - variant rexmit = 0; -}; - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtc.h b/godot/thirdparty/libdatachannel/include/rtc/rtc.h deleted file mode 100644 index 0210a0f2..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtc.h +++ /dev/null @@ -1,470 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_C_API -#define RTC_C_API - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef RTC_STATIC -#define RTC_C_EXPORT -#else // dynamic library -#ifdef _WIN32 -#ifdef RTC_EXPORTS -#define RTC_C_EXPORT __declspec(dllexport) // building the library -#else -#define RTC_C_EXPORT __declspec(dllimport) // using the library -#endif -#else // not WIN32 -#define RTC_C_EXPORT -#endif -#endif - -#ifdef _WIN32 -#ifdef CAPI_STDCALL -#define RTC_API __stdcall -#else -#define RTC_API -#endif -#else // not WIN32 -#define RTC_API -#endif - -#ifndef RTC_ENABLE_WEBSOCKET -#define RTC_ENABLE_WEBSOCKET 1 -#endif - -#ifndef RTC_ENABLE_MEDIA -#define RTC_ENABLE_MEDIA 1 -#endif - -#define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU - -#if RTC_ENABLE_MEDIA -#define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE \ - ((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6 -#define RTC_DEFAULT_MAXIMUM_PACKET_COUNT_FOR_NACK_CACHE ((unsigned)512) -#endif - -#include -#include - -// libdatachannel C API - -typedef enum { - RTC_NEW = 0, - RTC_CONNECTING = 1, - RTC_CONNECTED = 2, - RTC_DISCONNECTED = 3, - RTC_FAILED = 4, - RTC_CLOSED = 5 -} rtcState; - -typedef enum { - RTC_ICE_NEW = 0, - RTC_ICE_CHECKING = 1, - RTC_ICE_CONNECTED = 2, - RTC_ICE_COMPLETED = 3, - RTC_ICE_FAILED = 4, - RTC_ICE_DISCONNECTED = 5, - RTC_ICE_CLOSED = 6 -} rtcIceState; - -typedef enum { - RTC_GATHERING_NEW = 0, - RTC_GATHERING_INPROGRESS = 1, - RTC_GATHERING_COMPLETE = 2 -} rtcGatheringState; - -typedef enum { - RTC_SIGNALING_STABLE = 0, - RTC_SIGNALING_HAVE_LOCAL_OFFER = 1, - RTC_SIGNALING_HAVE_REMOTE_OFFER = 2, - RTC_SIGNALING_HAVE_LOCAL_PRANSWER = 3, - RTC_SIGNALING_HAVE_REMOTE_PRANSWER = 4, -} rtcSignalingState; - -typedef enum { // Don't change, it must match plog severity - RTC_LOG_NONE = 0, - RTC_LOG_FATAL = 1, - RTC_LOG_ERROR = 2, - RTC_LOG_WARNING = 3, - RTC_LOG_INFO = 4, - RTC_LOG_DEBUG = 5, - RTC_LOG_VERBOSE = 6 -} rtcLogLevel; - -typedef enum { - RTC_CERTIFICATE_DEFAULT = 0, // ECDSA - RTC_CERTIFICATE_ECDSA = 1, - RTC_CERTIFICATE_RSA = 2, -} rtcCertificateType; - -typedef enum { - // video - RTC_CODEC_H264 = 0, - RTC_CODEC_VP8 = 1, - RTC_CODEC_VP9 = 2, - RTC_CODEC_H265 = 3, - - // audio - RTC_CODEC_OPUS = 128, - RTC_CODEC_PCMU = 129, - RTC_CODEC_PCMA = 130, - RTC_CODEC_AAC = 131, -} rtcCodec; - -typedef enum { - RTC_DIRECTION_UNKNOWN = 0, - RTC_DIRECTION_SENDONLY = 1, - RTC_DIRECTION_RECVONLY = 2, - RTC_DIRECTION_SENDRECV = 3, - RTC_DIRECTION_INACTIVE = 4 -} rtcDirection; - -typedef enum { RTC_TRANSPORT_POLICY_ALL = 0, RTC_TRANSPORT_POLICY_RELAY = 1 } rtcTransportPolicy; - -#define RTC_ERR_SUCCESS 0 -#define RTC_ERR_INVALID -1 // invalid argument -#define RTC_ERR_FAILURE -2 // runtime error -#define RTC_ERR_NOT_AVAIL -3 // element not available -#define RTC_ERR_TOO_SMALL -4 // buffer too small - -typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message); -typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type, - void *ptr); -typedef void(RTC_API *rtcCandidateCallbackFunc)(int pc, const char *cand, const char *mid, - void *ptr); -typedef void(RTC_API *rtcStateChangeCallbackFunc)(int pc, rtcState state, void *ptr); -typedef void(RTC_API *rtcIceStateChangeCallbackFunc)(int pc, rtcIceState state, void *ptr); -typedef void(RTC_API *rtcGatheringStateCallbackFunc)(int pc, rtcGatheringState state, void *ptr); -typedef void(RTC_API *rtcSignalingStateCallbackFunc)(int pc, rtcSignalingState state, void *ptr); -typedef void(RTC_API *rtcDataChannelCallbackFunc)(int pc, int dc, void *ptr); -typedef void(RTC_API *rtcTrackCallbackFunc)(int pc, int tr, void *ptr); -typedef void(RTC_API *rtcOpenCallbackFunc)(int id, void *ptr); -typedef void(RTC_API *rtcClosedCallbackFunc)(int id, void *ptr); -typedef void(RTC_API *rtcErrorCallbackFunc)(int id, const char *error, void *ptr); -typedef void(RTC_API *rtcMessageCallbackFunc)(int id, const char *message, int size, void *ptr); -typedef void *(RTC_API *rtcInterceptorCallbackFunc)(int pc, const char *message, int size, - void *ptr); -typedef void(RTC_API *rtcBufferedAmountLowCallbackFunc)(int id, void *ptr); -typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr); - -// Log - -// NULL cb on the first call will log to stdout -RTC_C_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb); - -// User pointer -RTC_C_EXPORT void rtcSetUserPointer(int id, void *ptr); -RTC_C_EXPORT void *rtcGetUserPointer(int i); - -// PeerConnection - -typedef struct { - const char **iceServers; - int iceServersCount; - const char *proxyServer; // libnice only - const char *bindAddress; // libjuice only, NULL means any - rtcCertificateType certificateType; - rtcTransportPolicy iceTransportPolicy; - bool enableIceTcp; // libnice only - bool enableIceUdpMux; // libjuice only - bool disableAutoNegotiation; - bool forceMediaTransport; - uint16_t portRangeBegin; // 0 means automatic - uint16_t portRangeEnd; // 0 means automatic - int mtu; // <= 0 means automatic - int maxMessageSize; // <= 0 means default -} rtcConfiguration; - -RTC_C_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id -RTC_C_EXPORT int rtcClosePeerConnection(int pc); -RTC_C_EXPORT int rtcDeletePeerConnection(int pc); - -RTC_C_EXPORT int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb); -RTC_C_EXPORT int rtcSetLocalCandidateCallback(int pc, rtcCandidateCallbackFunc cb); -RTC_C_EXPORT int rtcSetStateChangeCallback(int pc, rtcStateChangeCallbackFunc cb); -RTC_C_EXPORT int rtcSetIceStateChangeCallback(int pc, rtcIceStateChangeCallbackFunc cb); -RTC_C_EXPORT int rtcSetGatheringStateChangeCallback(int pc, rtcGatheringStateCallbackFunc cb); -RTC_C_EXPORT int rtcSetSignalingStateChangeCallback(int pc, rtcSignalingStateCallbackFunc cb); - -RTC_C_EXPORT int rtcSetLocalDescription(int pc, const char *type); -RTC_C_EXPORT int rtcSetRemoteDescription(int pc, const char *sdp, const char *type); -RTC_C_EXPORT int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid); - -RTC_C_EXPORT int rtcGetLocalDescription(int pc, char *buffer, int size); -RTC_C_EXPORT int rtcGetRemoteDescription(int pc, char *buffer, int size); - -RTC_C_EXPORT int rtcGetLocalDescriptionType(int pc, char *buffer, int size); -RTC_C_EXPORT int rtcGetRemoteDescriptionType(int pc, char *buffer, int size); - -RTC_C_EXPORT int rtcGetLocalAddress(int pc, char *buffer, int size); -RTC_C_EXPORT int rtcGetRemoteAddress(int pc, char *buffer, int size); - -RTC_C_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, char *remote, - int remoteSize); - -RTC_C_EXPORT int rtcGetMaxDataChannelStream(int pc); - -// DataChannel, Track, and WebSocket common API - -RTC_C_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb); -RTC_C_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb); -RTC_C_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb); -RTC_C_EXPORT int rtcSetMessageCallback(int id, rtcMessageCallbackFunc cb); -RTC_C_EXPORT int rtcSendMessage(int id, const char *data, int size); -RTC_C_EXPORT int rtcClose(int id); -RTC_C_EXPORT int rtcDelete(int id); -RTC_C_EXPORT bool rtcIsOpen(int id); -RTC_C_EXPORT bool rtcIsClosed(int id); - -RTC_C_EXPORT int rtcGetBufferedAmount(int id); // total size buffered to send -RTC_C_EXPORT int rtcSetBufferedAmountLowThreshold(int id, int amount); -RTC_C_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb); - -// DataChannel, Track, and WebSocket common extended API - -RTC_C_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive -RTC_C_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb); -RTC_C_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size); - -// DataChannel - -typedef struct { - bool unordered; - bool unreliable; - int maxPacketLifeTime; // ignored if reliable - int maxRetransmits; // ignored if reliable -} rtcReliability; - -typedef struct { - rtcReliability reliability; - const char *protocol; // empty string if NULL - bool negotiated; - bool manualStream; - uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false -} rtcDataChannelInit; - -RTC_C_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb); -RTC_C_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id -RTC_C_EXPORT int rtcCreateDataChannelEx(int pc, const char *label, - const rtcDataChannelInit *init); // returns dc id -RTC_C_EXPORT int rtcDeleteDataChannel(int dc); - -RTC_C_EXPORT int rtcGetDataChannelStream(int dc); -RTC_C_EXPORT int rtcGetDataChannelLabel(int dc, char *buffer, int size); -RTC_C_EXPORT int rtcGetDataChannelProtocol(int dc, char *buffer, int size); -RTC_C_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability); - -// Track - -typedef struct { - rtcDirection direction; - rtcCodec codec; - int payloadType; - uint32_t ssrc; - const char *mid; - const char *name; // optional - const char *msid; // optional - const char *trackId; // optional, track ID used in MSID - const char *profile; // optional, codec profile -} rtcTrackInit; - -RTC_C_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb); -RTC_C_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id -RTC_C_EXPORT int rtcAddTrackEx(int pc, const rtcTrackInit *init); // returns tr id -RTC_C_EXPORT int rtcDeleteTrack(int tr); - -RTC_C_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size); -RTC_C_EXPORT int rtcGetTrackMid(int tr, char *buffer, int size); -RTC_C_EXPORT int rtcGetTrackDirection(int tr, rtcDirection *direction); - -#if RTC_ENABLE_MEDIA - -// Media - -// Define how OBUs are packetizied in a AV1 Sample -typedef enum { - RTC_OBU_PACKETIZED_OBU = 0, - RTC_OBU_PACKETIZED_TEMPORAL_UNIT = 1, -} rtcObuPacketization; - -// Define how NAL units are separated in a H264/H265 sample -typedef enum { - RTC_NAL_SEPARATOR_LENGTH = 0, // first 4 bytes are NAL unit length - RTC_NAL_SEPARATOR_LONG_START_SEQUENCE = 1, // 0x00, 0x00, 0x00, 0x01 - RTC_NAL_SEPARATOR_SHORT_START_SEQUENCE = 2, // 0x00, 0x00, 0x01 - RTC_NAL_SEPARATOR_START_SEQUENCE = 3, // long or short start sequence -} rtcNalUnitSeparator; - -typedef struct { - uint32_t ssrc; - const char *cname; - uint8_t payloadType; - uint32_t clockRate; - uint16_t sequenceNumber; - uint32_t timestamp; - - // H264/H265 - rtcNalUnitSeparator nalSeparator; // NAL unit separator - uint16_t maxFragmentSize; // Maximum NAL unit fragment size - -} rtcPacketizationHandlerInit; - -typedef struct { - uint32_t ssrc; - const char *name; // optional - const char *msid; // optional - const char *trackId; // optional, track ID used in MSID -} rtcSsrcForTypeInit; - -// Opaque message - -// Opaque type used (via rtcMessage*) to reference an rtc::Message -typedef void *rtcMessage; - -// Allocate a new opaque message. -// Must be explicitly freed by rtcDeleteOpaqueMessage() unless -// explicitly returned by a media interceptor callback; -RTC_C_EXPORT rtcMessage *rtcCreateOpaqueMessage(void *data, int size); -RTC_C_EXPORT void rtcDeleteOpaqueMessage(rtcMessage *msg); - -// Set MediaInterceptor for peer connection -RTC_C_EXPORT int rtcSetMediaInterceptorCallback(int id, rtcInterceptorCallbackFunc cb); - -// Set H264PacketizationHandler for track -RTC_C_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); - -// Set H265PacketizationHandler for track -RTC_C_EXPORT int rtcSetH265PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); - -// Set OpusPacketizationHandler for track -RTC_C_EXPORT int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); - -// Set AACPacketizationHandler for track -RTC_C_EXPORT int rtcSetAACPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); - -// Chain RtcpSrReporter to handler chain for given track -RTC_C_EXPORT int rtcChainRtcpSrReporter(int tr); - -// Chain RtcpNackResponder to handler chain for given track -RTC_C_EXPORT int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount); - -// Transform seconds to timestamp using track's clock rate, result is written to timestamp -RTC_C_EXPORT int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp); - -// Transform timestamp to seconds using track's clock rate, result is written to seconds -RTC_C_EXPORT int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds); - -// Get current timestamp, result is written to timestamp -RTC_C_EXPORT int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp); - -// Set RTP timestamp for track identified by given id -RTC_C_EXPORT int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp); - -// Get timestamp of last RTCP SR, result is written to timestamp -RTC_C_EXPORT int rtcGetLastTrackSenderReportTimestamp(int id, uint32_t *timestamp); - -// Set NeedsToReport flag in RtcpSrReporter handler identified by given track id -RTC_C_EXPORT int rtcSetNeedsToSendRtcpSr(int id); - -// Get all available payload types for given codec and stores them in buffer, does nothing if -// buffer is NULL -int rtcGetTrackPayloadTypesForCodec(int tr, const char *ccodec, int *buffer, int size); - -// Get all SSRCs for given track -int rtcGetSsrcsForTrack(int tr, uint32_t *buffer, int count); - -// Get CName for SSRC -int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char *cname, int cnameSize); - -// Get all SSRCs for given media type in given SDP -int rtcGetSsrcsForType(const char *mediaType, const char *sdp, uint32_t *buffer, int bufferSize); - -// Set SSRC for given media type in given SDP -int rtcSetSsrcForType(const char *mediaType, const char *sdp, char *buffer, const int bufferSize, - rtcSsrcForTypeInit *init); - -#endif // RTC_ENABLE_MEDIA - -#if RTC_ENABLE_WEBSOCKET - -// WebSocket - -typedef struct { - bool disableTlsVerification; // if true, don't verify the TLS certificate - const char *proxyServer; // only non-authenticated http supported for now - const char **protocols; - int protocolsCount; - int connectionTimeoutMs; // in milliseconds, 0 means default, < 0 means disabled - int pingIntervalMs; // in milliseconds, 0 means default, < 0 means disabled - int maxOutstandingPings; // 0 means default, < 0 means disabled -} rtcWsConfiguration; - -RTC_C_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id -RTC_C_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config); -RTC_C_EXPORT int rtcDeleteWebSocket(int ws); - -RTC_C_EXPORT int rtcGetWebSocketRemoteAddress(int ws, char *buffer, int size); -RTC_C_EXPORT int rtcGetWebSocketPath(int ws, char *buffer, int size); - -// WebSocketServer - -typedef void(RTC_API *rtcWebSocketClientCallbackFunc)(int wsserver, int ws, void *ptr); - -typedef struct { - uint16_t port; // 0 means automatic selection - bool enableTls; // if true, enable TLS (WSS) - const char *certificatePemFile; // NULL for autogenerated certificate - const char *keyPemFile; // NULL for autogenerated certificate - const char *keyPemPass; // NULL if no pass - const char *bindAddress; // NULL for IP_ANY_ADDR - int connectionTimeoutMs; // in milliseconds, 0 means default, < 0 means disabled -} rtcWsServerConfiguration; - -RTC_C_EXPORT int rtcCreateWebSocketServer(const rtcWsServerConfiguration *config, - rtcWebSocketClientCallbackFunc cb); // returns wsserver id -RTC_C_EXPORT int rtcDeleteWebSocketServer(int wsserver); - -RTC_C_EXPORT int rtcGetWebSocketServerPort(int wsserver); - -#endif - -// Optional global preload and cleanup - -RTC_C_EXPORT void rtcPreload(void); -RTC_C_EXPORT void rtcCleanup(void); - -// SCTP global settings - -typedef struct { - int recvBufferSize; // in bytes, <= 0 means optimized default - int sendBufferSize; // in bytes, <= 0 means optimized default - int maxChunksOnQueue; // in chunks, <= 0 means optimized default - int initialCongestionWindow; // in MTUs, <= 0 means optimized default - int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled - int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC - int delayedSackTimeMs; // in milliseconds, 0 means optimized default, < 0 means disabled - int minRetransmitTimeoutMs; // in milliseconds, <= 0 means optimized default - int maxRetransmitTimeoutMs; // in milliseconds, <= 0 means optimized default - int initialRetransmitTimeoutMs; // in milliseconds, <= 0 means optimized default - int maxRetransmitAttempts; // number of retransmissions, <= 0 means optimized default - int heartbeatIntervalMs; // in milliseconds, <= 0 means optimized default -} rtcSctpSettings; - -// Note: SCTP settings apply to newly-created PeerConnections only -RTC_C_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtc.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtc.hpp deleted file mode 100644 index 5fdb7fcd..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtc.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -// C API -#include "rtc.h" - -// C++ API -#include "common.hpp" -#include "global.hpp" -// -#include "datachannel.hpp" -#include "peerconnection.hpp" -#include "track.hpp" - -#if RTC_ENABLE_WEBSOCKET - -// WebSocket -#include "websocket.hpp" -#include "websocketserver.hpp" - -#endif // RTC_ENABLE_WEBSOCKET - -#if RTC_ENABLE_MEDIA - -// Media handling -#include "mediachainablehandler.hpp" -#include "rtcpnackresponder.hpp" -#include "rtcpreceivingsession.hpp" -#include "rtcpsrreporter.hpp" - -// Opus/AAC/h264/h265/AV1 streaming -#include "aacrtppacketizer.hpp" -#include "av1packetizationhandler.hpp" -#include "h264packetizationhandler.hpp" -#include "h265packetizationhandler.hpp" -#include "opuspacketizationhandler.hpp" - -#endif // RTC_ENABLE_MEDIA diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtcpnackresponder.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtcpnackresponder.hpp deleted file mode 100644 index 10f4cfee..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtcpnackresponder.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RTCP_NACK_RESPONDER_H -#define RTC_RTCP_NACK_RESPONDER_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerelement.hpp" - -#include -#include - -namespace rtc { - -class RTC_CPP_EXPORT RtcpNackResponder final : public MediaHandlerElement { - - /// Packet storage - class RTC_CPP_EXPORT Storage { - - /// Packet storage element - struct RTC_CPP_EXPORT Element { - Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr next = nullptr); - const binary_ptr packet; - const uint16_t sequenceNumber; - /// Pointer to newer element - shared_ptr next = nullptr; - }; - - private: - /// Oldest packet in storage - shared_ptr oldest = nullptr; - /// Newest packet in storage - shared_ptr newest = nullptr; - /// Inner storage - std::unordered_map> storage{}; - std::mutex mutex; - - /// Maximum storage size - const unsigned maximumSize; - - /// Returns current size - unsigned size(); - - public: - static const unsigned defaultMaximumSize = 512; - - Storage(unsigned _maximumSize); - - /// Returns packet with given sequence number - optional get(uint16_t sequenceNumber); - - /// Stores packet - /// @param packet Packet - void store(binary_ptr packet); - }; - - const shared_ptr storage; - -public: - RtcpNackResponder(unsigned maxStoredPacketCount = Storage::defaultMaximumSize); - - /// Checks for RTCP NACK and handles it, - /// @param message RTCP message - /// @returns unchanged RTCP message and requested RTP packets - ChainedIncomingControlProduct processIncomingControlMessage(message_ptr message) override; - - /// Stores RTP packets in internal storage - /// @param messages RTP packets - /// @param control RTCP - /// @returns Unchanged RTP and RTCP - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_RTCP_NACK_RESPONDER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtcpreceivingsession.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtcpreceivingsession.hpp deleted file mode 100644 index 0760495c..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtcpreceivingsession.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2020 Staz Modrzynski - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RTCP_RECEIVING_SESSION_H -#define RTC_RTCP_RECEIVING_SESSION_H - -#if RTC_ENABLE_MEDIA - -#include "common.hpp" -#include "mediahandler.hpp" -#include "message.hpp" -#include "rtp.hpp" - -namespace rtc { - -// An RtcpSession can be plugged into a Track to handle the whole RTCP session -class RTC_CPP_EXPORT RtcpReceivingSession : public MediaHandler { -public: - message_ptr incoming(message_ptr ptr) override; - message_ptr outgoing(message_ptr ptr) override; - bool send(message_ptr ptr); - - void requestBitrate(unsigned int newBitrate); - - bool requestKeyframe() override; - -protected: - void pushREMB(unsigned int bitrate); - void pushRR(unsigned int lastSR_delay); - - void pushPLI(); - - unsigned int mRequestedBitrate = 0; - SSRC mSsrc = 0; - uint32_t mGreatestSeqNo = 0; - uint64_t mSyncRTPTS, mSyncNTPTS; -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_RTCP_RECEIVING_SESSION_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtcpsrreporter.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtcpsrreporter.hpp deleted file mode 100644 index ddd2cf85..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtcpsrreporter.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RTCP_SENDER_REPORTABLE_H -#define RTC_RTCP_SENDER_REPORTABLE_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerelement.hpp" -#include "message.hpp" -#include "rtppacketizationconfig.hpp" - -namespace rtc { - -class RTC_CPP_EXPORT RtcpSrReporter final : public MediaHandlerElement { - void addToReport(RtpHeader *rtp, uint32_t rtpSize); - message_ptr getSenderReport(uint32_t timestamp); - -public: - /// RTP configuration - const shared_ptr rtpConfig; - - RtcpSrReporter(shared_ptr rtpConfig); - - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; - - uint32_t lastReportedTimestamp() const; - void setNeedsToReport(); - -private: - uint32_t mPacketCount = 0; - uint32_t mPayloadOctets = 0; - uint32_t mLastReportedTimestamp = 0; - bool mNeedsToReport = false; -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_RTCP_SENDER_REPORTABLE_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtp.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtp.hpp deleted file mode 100644 index ea6e230f..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtp.hpp +++ /dev/null @@ -1,379 +0,0 @@ -/** - * Copyright (c) 2020 Staz Modrzynski - * Copyright (c) 2020 Paul-Louis Ageneau - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RTP_HPP -#define RTC_RTP_HPP - -#include "common.hpp" - -#include - -namespace rtc { - -typedef uint32_t SSRC; - -RTC_CPP_EXPORT bool IsRtcp(const binary &data); - -#pragma pack(push, 1) - -struct RTC_CPP_EXPORT RtpExtensionHeader { - uint16_t _profileSpecificId; - uint16_t _headerLength; - - [[nodiscard]] uint16_t profileSpecificId() const; - [[nodiscard]] uint16_t headerLength() const; - - [[nodiscard]] size_t getSize() const; - [[nodiscard]] const char *getBody() const; - [[nodiscard]] char *getBody(); - - void setProfileSpecificId(uint16_t profileSpecificId); - void setHeaderLength(uint16_t headerLength); - - void clearBody(); - void writeCurrentVideoOrientation(size_t offset, uint8_t id, uint8_t value); - void writeOneByteHeader(size_t offset, uint8_t id, const byte *value, size_t size); -}; - -struct RTC_CPP_EXPORT RtpHeader { - uint8_t _first; - uint8_t _payloadType; - uint16_t _seqNumber; - uint32_t _timestamp; - SSRC _ssrc; - // The following field is SSRC _csrc[] - - [[nodiscard]] uint8_t version() const; - [[nodiscard]] bool padding() const; - [[nodiscard]] bool extension() const; - [[nodiscard]] uint8_t csrcCount() const; - [[nodiscard]] uint8_t marker() const; - [[nodiscard]] uint8_t payloadType() const; - [[nodiscard]] uint16_t seqNumber() const; - [[nodiscard]] uint32_t timestamp() const; - [[nodiscard]] uint32_t ssrc() const; - - [[nodiscard]] size_t getSize() const; - [[nodiscard]] size_t getExtensionHeaderSize() const; - [[nodiscard]] const RtpExtensionHeader *getExtensionHeader() const; - [[nodiscard]] RtpExtensionHeader *getExtensionHeader(); - [[nodiscard]] const char *getBody() const; - [[nodiscard]] char *getBody(); - - void log() const; - - void preparePacket(); - void setSeqNumber(uint16_t newSeqNo); - void setPayloadType(uint8_t newPayloadType); - void setSsrc(uint32_t in_ssrc); - void setMarker(bool marker); - void setTimestamp(uint32_t i); - void setExtension(bool extension); -}; - -struct RTC_CPP_EXPORT RtcpReportBlock { - SSRC _ssrc; - uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit - uint16_t _seqNoCycles; - uint16_t _highestSeqNo; - uint32_t _jitter; - uint32_t _lastReport; - uint32_t _delaySinceLastReport; - - [[nodiscard]] uint16_t seqNoCycles() const; - [[nodiscard]] uint16_t highestSeqNo() const; - [[nodiscard]] uint32_t jitter() const; - [[nodiscard]] uint32_t delaySinceSR() const; - - [[nodiscard]] SSRC getSSRC() const; - [[nodiscard]] uint32_t getNTPOfSR() const; - [[nodiscard]] unsigned int getLossPercentage() const; - [[nodiscard]] unsigned int getPacketLostCount() const; - - void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets, - uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter, - uint64_t lastSR_NTP, uint64_t lastSR_DELAY); - void setSSRC(SSRC in_ssrc); - void setPacketsLost(unsigned int packetsLost, unsigned int totalPackets); - void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles); - void setJitter(uint32_t jitter); - void setNTPOfSR(uint64_t ntp); - void setDelaySinceSR(uint32_t sr); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpHeader { - uint8_t _first; - uint8_t _payloadType; - uint16_t _length; - - [[nodiscard]] uint8_t version() const; - [[nodiscard]] bool padding() const; - [[nodiscard]] uint8_t reportCount() const; - [[nodiscard]] uint8_t payloadType() const; - [[nodiscard]] uint16_t length() const; - [[nodiscard]] size_t lengthInBytes() const; - - void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length); - void setPayloadType(uint8_t type); - void setReportCount(uint8_t count); - void setLength(uint16_t length); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpFbHeader { - RtcpHeader header; - - SSRC _packetSender; - SSRC _mediaSource; - - [[nodiscard]] SSRC packetSenderSSRC() const; - [[nodiscard]] SSRC mediaSourceSSRC() const; - - void setPacketSenderSSRC(SSRC ssrc); - void setMediaSourceSSRC(SSRC ssrc); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpSr { - RtcpHeader header; - - SSRC _senderSSRC; - uint64_t _ntpTimestamp; - uint32_t _rtpTimestamp; - uint32_t _packetCount; - uint32_t _octetCount; - - RtcpReportBlock _reportBlocks; - - [[nodiscard]] static unsigned int Size(unsigned int reportCount); - - [[nodiscard]] uint64_t ntpTimestamp() const; - [[nodiscard]] uint32_t rtpTimestamp() const; - [[nodiscard]] uint32_t packetCount() const; - [[nodiscard]] uint32_t octetCount() const; - [[nodiscard]] uint32_t senderSSRC() const; - - [[nodiscard]] const RtcpReportBlock *getReportBlock(int num) const; - [[nodiscard]] RtcpReportBlock *getReportBlock(int num); - [[nodiscard]] unsigned int size(unsigned int reportCount); - [[nodiscard]] size_t getSize() const; - - void preparePacket(SSRC senderSSRC, uint8_t reportCount); - void setNtpTimestamp(uint64_t ts); - void setRtpTimestamp(uint32_t ts); - void setOctetCount(uint32_t ts); - void setPacketCount(uint32_t ts); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpSdesItem { - uint8_t type; - - uint8_t _length; - char _text[1]; - - [[nodiscard]] static unsigned int Size(uint8_t textLength); - - [[nodiscard]] string text() const; - [[nodiscard]] uint8_t length() const; - - void setText(string text); -}; - -struct RTC_CPP_EXPORT RtcpSdesChunk { - SSRC _ssrc; - RtcpSdesItem _items; - - [[nodiscard]] static unsigned int Size(const std::vector textLengths); - - [[nodiscard]] SSRC ssrc() const; - - void setSSRC(SSRC ssrc); - - // Get item at given index - // All items with index < num must be valid, otherwise this function has undefined behaviour - // (use safelyCountChunkSize() to check if chunk is valid). - [[nodiscard]] const RtcpSdesItem *getItem(int num) const; - [[nodiscard]] RtcpSdesItem *getItem(int num); - - // Get size of chunk - // All items must be valid, otherwise this function has undefined behaviour (use - // safelyCountChunkSize() to check if chunk is valid) - [[nodiscard]] unsigned int getSize() const; - - long safelyCountChunkSize(size_t maxChunkSize) const; -}; - -struct RTC_CPP_EXPORT RtcpSdes { - RtcpHeader header; - RtcpSdesChunk _chunks; - - [[nodiscard]] static unsigned int Size(const std::vector> lengths); - - bool isValid() const; - - // Returns number of chunks in this packet - // Returns 0 if packet is invalid - unsigned int chunksCount() const; - - // Get chunk at given index - // All chunks (and their items) with index < `num` must be valid, otherwise this function has - // undefined behaviour (use `isValid` to check if chunk is valid). - const RtcpSdesChunk *getChunk(int num) const; - RtcpSdesChunk *getChunk(int num); - - void preparePacket(uint8_t chunkCount); -}; - -struct RTC_CPP_EXPORT RtcpRr { - RtcpHeader header; - - SSRC _senderSSRC; - RtcpReportBlock _reportBlocks; - - [[nodiscard]] static size_t SizeWithReportBlocks(uint8_t reportCount); - - SSRC senderSSRC() const; - bool isSenderReport(); - bool isReceiverReport(); - - [[nodiscard]] RtcpReportBlock *getReportBlock(int num); - [[nodiscard]] const RtcpReportBlock *getReportBlock(int num) const; - [[nodiscard]] size_t getSize() const; - - void preparePacket(SSRC senderSSRC, uint8_t reportCount); - void setSenderSSRC(SSRC ssrc); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpRemb { - RtcpFbHeader header; - - char _id[4]; // Unique identifier ('R' 'E' 'M' 'B') - uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask) - SSRC _ssrc[1]; - - [[nodiscard]] static size_t SizeWithSSRCs(int count); - - [[nodiscard]] unsigned int getSize() const; - - void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate); - void setBitrate(unsigned int numSSRC, unsigned int in_bitrate); - void setSsrc(int iterator, SSRC newSssrc); -}; - -struct RTC_CPP_EXPORT RtcpPli { - RtcpFbHeader header; - - [[nodiscard]] static unsigned int Size(); - - void preparePacket(SSRC messageSSRC); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpFirPart { - uint32_t ssrc; - uint8_t seqNo; - uint8_t dummy1; - uint16_t dummy2; -}; - -struct RTC_CPP_EXPORT RtcpFir { - RtcpFbHeader header; - RtcpFirPart parts[1]; - - static unsigned int Size(); - - void preparePacket(SSRC messageSSRC, uint8_t seqNo); - - void log() const; -}; - -struct RTC_CPP_EXPORT RtcpNackPart { - uint16_t _pid; - uint16_t _blp; - - uint16_t pid(); - uint16_t blp(); - - void setPid(uint16_t pid); - void setBlp(uint16_t blp); - - std::vector getSequenceNumbers(); -}; - -struct RTC_CPP_EXPORT RtcpNack { - RtcpFbHeader header; - RtcpNackPart parts[1]; - - [[nodiscard]] static unsigned int Size(unsigned int discreteSeqNoCount); - - [[nodiscard]] unsigned int getSeqNoCount(); - - void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount); - - /** - * Add a packet to the list of missing packets. - * @param fciCount The number of FCI fields that are present in this packet. - * Let the number start at zero and let this function grow the number. - * @param fciPID The seq no of the active FCI. It will be initialized automatically, and will - * change automatically. - * @param missingPacket The seq no of the missing packet. This will be added to the queue. - * @return true if the packet has grown, false otherwise. - */ - bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket); -}; - -struct RTC_CPP_EXPORT RtpRtx { - RtpHeader header; - - [[nodiscard]] const char *getBody() const; - [[nodiscard]] char *getBody(); - [[nodiscard]] size_t getBodySize(size_t totalSize) const; - [[nodiscard]] size_t getSize() const; - [[nodiscard]] uint16_t getOriginalSeqNo() const; - - // Returns the new size of the packet - size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType); - - size_t copyTo(RtpHeader *dest, size_t totalSize, uint8_t originalPayloadType); -}; - -// For backward compatibility, do not use -using RTP_ExtensionHeader = RtpExtensionHeader; -using RTP = RtpHeader; -using RTCP_ReportBlock = RtcpReportBlock; -using RTCP_HEADER = RtcpHeader; -using RTCP_FB_HEADER = RtcpFbHeader; -using RTCP_SR = RtcpSr; -using RTCP_SDES_ITEM = RtcpSdesItem; -using RTCP_SDES_CHUNK = RtcpSdesChunk; -using RTCP_SDES = RtcpSdes; -using RTCP_RR = RtcpRr; -using RTCP_REMB = RtcpRemb; -using RTCP_PLI = RtcpPli; -using RTCP_FIR_PART = RtcpFirPart; -using RTCP_FIR = RtcpFir; -using RTCP_NACK_PART = RtcpNackPart; -using RTCP_NACK = RtcpNack; -using RTP_RTX = RtpRtx; - -#pragma pack(pop) - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtppacketizationconfig.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtppacketizationconfig.hpp deleted file mode 100644 index ce0a180d..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtppacketizationconfig.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RTP_PACKETIZATION_CONFIG_H -#define RTC_RTP_PACKETIZATION_CONFIG_H - -#if RTC_ENABLE_MEDIA - -#include "rtp.hpp" - -namespace rtc { - -// RTP configuration used in packetization process -class RTC_CPP_EXPORT RtpPacketizationConfig { -public: - SSRC ssrc; - const std::string cname; - const uint8_t payloadType; - const uint32_t clockRate; - const uint8_t videoOrientationId; - - // current sequence number - uint16_t sequenceNumber; - - // current timestamp - uint32_t timestamp; - - // start timestamp - uint32_t startTimestamp; - - /// Current video orientation - /// - /// Bit# 7 6 5 4 3 2 1 0 - /// Definition 0 0 0 0 C F R1 R0 - /// - /// C - /// 0 - Front-facing camera (use this if unsure) - /// 1 - Back-facing camera - /// - /// F - /// 0 - No Flip - /// 1 - Horizontal flip - /// - /// R1 R0 - CW rotation that receiver must apply - /// 0 - 0 degrees - /// 1 - 90 degrees - /// 2 - 180 degrees - /// 3 - 270 degrees - uint8_t videoOrientation = 0; - - // MID Extension Header - uint8_t midId = 0; - optional mid; - - // RID Extension Header - uint8_t ridId = 0; - optional rid; - - /// Construct RTP configuration used in packetization process - /// @param ssrc SSRC of source - /// @param cname CNAME of source - /// @param payloadType Payload type of source - /// @param clockRate Clock rate of source used in timestamps - /// nullopt) - /// @param videoOrientationId Video orientation (see above) - RtpPacketizationConfig(SSRC ssrc, std::string cname, uint8_t payloadType, uint32_t clockRate, - uint8_t videoOrientationId = 0); - - RtpPacketizationConfig(const RtpPacketizationConfig &) = delete; - - /// Convert timestamp to seconds - /// @param timestamp Timestamp - /// @param clockRate Clock rate for timestamp calculation - static double getSecondsFromTimestamp(uint32_t timestamp, uint32_t clockRate); - - /// Convert timestamp to seconds - /// @param timestamp Timestamp - double timestampToSeconds(uint32_t timestamp); - - /// Convert seconds to timestamp - /// @param seconds Number of seconds - /// @param clockRate Clock rate for timestamp calculation - static uint32_t getTimestampFromSeconds(double seconds, uint32_t clockRate); - - /// Convert seconds to timestamp - /// @param seconds Number of seconds - uint32_t secondsToTimestamp(double seconds); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_RTP_PACKETIZATION_CONFIG_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp b/godot/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp deleted file mode 100644 index f28afd50..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_RTP_PACKETIZER_H -#define RTC_RTP_PACKETIZER_H - -#if RTC_ENABLE_MEDIA - -#include "message.hpp" -#include "rtppacketizationconfig.hpp" - -namespace rtc { - -/// Class responsible for RTP packetization -class RTC_CPP_EXPORT RtpPacketizer { - static const auto rtpHeaderSize = 12; - static const auto rtpExtHeaderCvoSize = 8; - -public: - virtual ~RtpPacketizer() = default; - - // RTP configuration - const shared_ptr rtpConfig; - - /// Constructs packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - RtpPacketizer(shared_ptr rtpConfig); - - /// Creates RTP packet for given payload based on `rtpConfig`. - /// @note This function increase sequence number after packetization. - /// @param payload RTP payload - /// @param setMark Set marker flag in RTP packet if true - virtual shared_ptr packetize(shared_ptr payload, bool setMark); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_RTP_PACKETIZER_H */ diff --git a/godot/thirdparty/libdatachannel/include/rtc/track.hpp b/godot/thirdparty/libdatachannel/include/rtc/track.hpp deleted file mode 100644 index 6f217b8d..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/track.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_TRACK_H -#define RTC_TRACK_H - -#include "channel.hpp" -#include "common.hpp" -#include "description.hpp" -#include "mediahandler.hpp" - -namespace rtc { - -namespace impl { - -class Track; - -} // namespace impl - -class RTC_CPP_EXPORT Track final : private CheshireCat, public Channel { -public: - Track(impl_ptr impl); - ~Track() override; - - string mid() const; - Description::Direction direction() const; - Description::Media description() const; - - void setDescription(Description::Media description); - - void close(void) override; - RTC_WRAPPED(bool) send(message_variant data) override; - RTC_WRAPPED(bool) send(const byte *data, size_t size) override; - - bool isOpen(void) const override; - bool isClosed(void) const override; - size_t maxMessageSize() const override; - - bool requestKeyframe(); - - void setMediaHandler(shared_ptr handler); - shared_ptr getMediaHandler(); - - // Deprecated, use setMediaHandler() and getMediaHandler() - inline void setRtcpHandler(shared_ptr handler) { setMediaHandler(handler); } - inline shared_ptr getRtcpHandler() { return getMediaHandler(); } - -private: - using CheshireCat::impl; -}; - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/utils.hpp b/godot/thirdparty/libdatachannel/include/rtc/utils.hpp deleted file mode 100644 index be277336..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/utils.hpp +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_UTILS_H -#define RTC_UTILS_H - -#include -#include -#include -#include -#include -#include - -namespace rtc { - -// overloaded helper -template struct overloaded : Ts... { using Ts::operator()...; }; -template overloaded(Ts...) -> overloaded; - -// weak_ptr bind helper -template auto weak_bind(F &&f, T *t, Args &&..._args) { - return [bound = std::bind(f, t, _args...), weak_this = t->weak_from_this()](auto &&...args) { - if (auto shared_this = weak_this.lock()) - return bound(args...); - else - return static_cast(false); - }; -} - -// scope_guard helper -class scope_guard final { -public: - scope_guard(std::function func) : function(std::move(func)) {} - scope_guard(scope_guard &&other) = delete; - scope_guard(const scope_guard &) = delete; - void operator=(const scope_guard &) = delete; - - ~scope_guard() { - if (function) - function(); - } - -private: - std::function function; -}; - -// callback with built-in synchronization -template class synchronized_callback { -public: - synchronized_callback() = default; - synchronized_callback(synchronized_callback &&cb) { *this = std::move(cb); } - synchronized_callback(const synchronized_callback &cb) { *this = cb; } - synchronized_callback(std::function func) { *this = std::move(func); } - virtual ~synchronized_callback() { *this = nullptr; } - - synchronized_callback &operator=(synchronized_callback &&cb) { - std::scoped_lock lock(mutex, cb.mutex); - set(std::exchange(cb.callback, nullptr)); - return *this; - } - - synchronized_callback &operator=(const synchronized_callback &cb) { - std::scoped_lock lock(mutex, cb.mutex); - set(cb.callback); - return *this; - } - - synchronized_callback &operator=(std::function func) { - std::lock_guard lock(mutex); - set(std::move(func)); - return *this; - } - - bool operator()(Args... args) const { - std::lock_guard lock(mutex); - return call(std::move(args)...); - } - - operator bool() const { - std::lock_guard lock(mutex); - return callback ? true : false; - } - -protected: - virtual void set(std::function func) { callback = std::move(func); } - virtual bool call(Args... args) const { - if (!callback) - return false; - - callback(std::move(args)...); - return true; - } - - std::function callback; - mutable std::recursive_mutex mutex; -}; - -// callback with built-in synchronization and replay of the last missed call -template -class synchronized_stored_callback final : public synchronized_callback { -public: - template - synchronized_stored_callback(CArgs &&...cargs) - : synchronized_callback(std::forward(cargs)...) {} - ~synchronized_stored_callback() {} - -private: - void set(std::function func) { - synchronized_callback::set(func); - if (func && stored) { - std::apply(func, std::move(*stored)); - stored.reset(); - } - } - - bool call(Args... args) const { - if (!synchronized_callback::call(args...)) - stored.emplace(std::move(args)...); - - return true; - } - - mutable std::optional> stored; -}; - -// pimpl base class -template using impl_ptr = std::shared_ptr; -template class CheshireCat { -public: - CheshireCat(impl_ptr impl) : mImpl(std::move(impl)) {} - template - CheshireCat(Args... args) : mImpl(std::make_shared(std::forward(args)...)) {} - CheshireCat(CheshireCat &&cc) { *this = std::move(cc); } - CheshireCat(const CheshireCat &) = delete; - - virtual ~CheshireCat() = default; - - CheshireCat &operator=(CheshireCat &&cc) { - mImpl = std::move(cc.mImpl); - return *this; - }; - CheshireCat &operator=(const CheshireCat &) = delete; - -protected: - impl_ptr impl() { return mImpl; } - impl_ptr impl() const { return mImpl; } - -private: - impl_ptr mImpl; -}; - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/include/rtc/websocket.hpp b/godot/thirdparty/libdatachannel/include/rtc/websocket.hpp deleted file mode 100644 index 154a04bc..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/websocket.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_WEBSOCKET_H -#define RTC_WEBSOCKET_H - -#if RTC_ENABLE_WEBSOCKET - -#include "channel.hpp" -#include "common.hpp" -#include "configuration.hpp" // for ProxyServer - -namespace rtc { - -namespace impl { - -struct WebSocket; - -} - -class RTC_CPP_EXPORT WebSocket final : private CheshireCat, public Channel { -public: - enum class State : int { - Connecting = 0, - Open = 1, - Closing = 2, - Closed = 3, - }; - - struct Configuration { - bool disableTlsVerification = false; // if true, don't verify the TLS certificate - optional proxyServer; // only non-authenticated http supported for now - std::vector protocols; - optional connectionTimeout; // zero to disable - optional pingInterval; // zero to disable - optional maxOutstandingPings; - }; - - WebSocket(); - WebSocket(Configuration config); - WebSocket(impl_ptr impl); - ~WebSocket() override; - - State readyState() const; - - bool isOpen() const override; - bool isClosed() const override; - size_t maxMessageSize() const override; - - void open(const string &url); - void close() override; - void forceClose(); - bool send(const message_variant data) override; - bool send(const byte *data, size_t size) override; - - optional remoteAddress() const; - optional path() const; - -private: - using CheshireCat::impl; -}; - -} // namespace rtc - -#endif - -#endif // RTC_WEBSOCKET_H diff --git a/godot/thirdparty/libdatachannel/include/rtc/websocketserver.hpp b/godot/thirdparty/libdatachannel/include/rtc/websocketserver.hpp deleted file mode 100644 index 449b5d4f..00000000 --- a/godot/thirdparty/libdatachannel/include/rtc/websocketserver.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_WEBSOCKETSERVER_H -#define RTC_WEBSOCKETSERVER_H - -#if RTC_ENABLE_WEBSOCKET - -#include "common.hpp" -#include "websocket.hpp" - -namespace rtc { - -namespace impl { - -struct WebSocketServer; - -} - -class RTC_CPP_EXPORT WebSocketServer final : private CheshireCat { -public: - struct Configuration { - uint16_t port = 8080; - bool enableTls = false; - optional certificatePemFile; - optional keyPemFile; - optional keyPemPass; - optional bindAddress; - optional connectionTimeout; - }; - - WebSocketServer(); - WebSocketServer(Configuration config); - ~WebSocketServer(); - - void stop(); - - uint16_t port() const; - - void onClient(std::function)> callback); - -private: - using CheshireCat::impl; -}; - -} // namespace rtc - -#endif - -#endif // RTC_WEBSOCKET_H diff --git a/godot/thirdparty/libdatachannel/patches/avoid_exceptions.patch b/godot/thirdparty/libdatachannel/patches/avoid_exceptions.patch deleted file mode 100644 index 69aa4aef..00000000 --- a/godot/thirdparty/libdatachannel/patches/avoid_exceptions.patch +++ /dev/null @@ -1,4948 +0,0 @@ -diff --git a/thirdparty/libdatachannel/include/rtc/candidate.hpp b/thirdparty/libdatachannel/include/rtc/candidate.hpp -index 88524851ab..c243a829c6 100644 ---- a/thirdparty/libdatachannel/include/rtc/candidate.hpp -+++ b/thirdparty/libdatachannel/include/rtc/candidate.hpp -@@ -22,13 +22,13 @@ public: - enum class TransportType { Unknown, Udp, TcpActive, TcpPassive, TcpSo, TcpUnknown }; - - Candidate(); -- Candidate(string candidate); -- Candidate(string candidate, string mid); -+ static RTC_WRAPPED(Candidate) create(string candidate); -+ static RTC_WRAPPED(Candidate) create(string candidate, string mid); - - void hintMid(string mid); -- void changeAddress(string addr); -- void changeAddress(string addr, uint16_t port); -- void changeAddress(string addr, string service); -+ RTC_WRAPPED(void) changeAddress(string addr); -+ RTC_WRAPPED(void) changeAddress(string addr, uint16_t port); -+ RTC_WRAPPED(void) changeAddress(string addr, string service); - - enum class ResolveMode { Simple, Lookup }; - bool resolve(ResolveMode mode = ResolveMode::Simple); -@@ -49,7 +49,7 @@ public: - optional port() const; - - private: -- void parse(string candidate); -+ RTC_WRAPPED(void) parse(string candidate); - - string mFoundation; - uint32_t mComponent, mPriority; -diff --git a/thirdparty/libdatachannel/include/rtc/channel.hpp b/thirdparty/libdatachannel/include/rtc/channel.hpp -index 384279d76a..32e69d27aa 100644 ---- a/thirdparty/libdatachannel/include/rtc/channel.hpp -+++ b/thirdparty/libdatachannel/include/rtc/channel.hpp -@@ -25,8 +25,8 @@ public: - virtual ~Channel(); - - virtual void close() = 0; -- virtual bool send(message_variant data) = 0; // returns false if buffered -- virtual bool send(const byte *data, size_t size) = 0; -+ virtual RTC_WRAPPED(bool) send(message_variant data) = 0; // returns false if buffered -+ virtual RTC_WRAPPED(bool) send(const byte *data, size_t size) = 0; - - virtual bool isOpen() const = 0; - virtual bool isClosed() const = 0; -diff --git a/thirdparty/libdatachannel/include/rtc/common.hpp b/thirdparty/libdatachannel/include/rtc/common.hpp -index 08f981cb8a..f94d6756de 100644 ---- a/thirdparty/libdatachannel/include/rtc/common.hpp -+++ b/thirdparty/libdatachannel/include/rtc/common.hpp -@@ -53,9 +53,139 @@ - #include - #include - #include -+#include - - namespace rtc { - -+#ifdef RTC_USE_CPP_EXCEPTIONS -+ -+#define RTC_WHAT what -+#define RTC_EXCEPTION std::exception -+#define RTC_RUNTIME_ERROR std::runtime_error -+#define RTC_LOGIC_ERROR std::logic_error -+#define RTC_INVALID_ARGUMENT std::invalid_argument -+#define RTC_OUT_OF_RANGE std::out_of_range -+ -+#define RTC_THROW throw -+#define RTC_THROW_WITHIN(exception) throw exception -+#define RTC_BEGIN -+#define RTC_TRY try -+#define RTC_CATCH catch -+#define RTC_WRAPPED(T) T -+#define RTC_VOID -+#define RTC_RET return -+ -+#define RTC_UNWRAP_EXPR(func) (func) -+#define RTC_CHECK_EXCEPTION -+#define RTC_RETHROW throw -+ -+#define RTC_UNWRAP_CATCH(func) (func) -+#define RTC_UNWRAP_RETHROW(func) (func) -+#define RTC_UNWRAP_CATCH_DECL(typ, var, func) typ var = (func) -+#define RTC_UNWRAP_RETHROW_DECL(typ, var, func) typ var = (func) -+#define RTC_UNWRAP_CATCH_VAR(var, func) var = (func) -+#define RTC_UNWRAP_RETHROW_VAR(var, func) var = (func) -+#define RTC_UNWRAP_CATCH_ARG(wrap, func) wrap((func)) -+#define RTC_UNWRAP_RETHROW_ARG(wrap, func) wrap((func)) -+#define RTC_COMMA , -+ -+#else -+ -+ -+ -+ -+ -+ -+#define RTC_WHAT c_str -+#define RTC_EXCEPTION std::string -+#define RTC_RUNTIME_ERROR std::string -+#define RTC_LOGIC_ERROR std::string -+#define RTC_INVALID_ARGUMENT std::string -+#define RTC_OUT_OF_RANGE std::string -+ -+#ifdef _MSC_VER -+#pragma warning(error : 4715) -+#pragma warning(error : 4716) -+#pragma warning(error : 4834) -+#endif -+ -+class Void {}; -+ -+class [[nodiscard]] ExceptionCast { -+ RTC_EXCEPTION &&rtc_exception; -+ -+public: -+ ExceptionCast(RTC_EXCEPTION &&rtc_exception) : -+ rtc_exception(std::move(rtc_exception)) { -+ } -+ RTC_EXCEPTION &&exception() { -+ return std::move(rtc_exception); -+ } -+}; -+template -+struct [[nodiscard]] WrappedResult { -+ using ExT = RTC_EXCEPTION; -+ T rtc_value; -+ ExT rtc_exception; -+ bool rtc_is_exception; -+ -+ WrappedResult(T &&value) : -+ rtc_value(std::move(value)), rtc_exception(ExT()), rtc_is_exception(false) { -+ } -+ WrappedResult(const T &value) : -+ rtc_value(value), rtc_exception(ExT()), rtc_is_exception(false) { -+ } -+ WrappedResult(ExceptionCast exception_cast) : -+ rtc_value(T()), rtc_exception(std::move(exception_cast.exception())), rtc_is_exception(true) { -+ } -+}; -+ -+template<> -+struct [[nodiscard]] WrappedResult { -+ using ExT = RTC_EXCEPTION; -+ Void rtc_value; -+ ExT rtc_exception; -+ bool rtc_is_exception; -+ -+ WrappedResult() : -+ rtc_value(Void()), rtc_exception(ExT()), rtc_is_exception(false) { -+ } -+ WrappedResult(Void) : -+ rtc_value(Void()), rtc_exception(ExT()), rtc_is_exception(false) { -+ } -+ WrappedResult(ExceptionCast exception_cast) : -+ rtc_value(Void()), rtc_exception(std::move(exception_cast.exception())), rtc_is_exception(true) { -+ } -+}; -+ -+#define RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(clsname) friend struct WrappedResult -+#define RTC_THROW return (::rtc::ExceptionCast) -+#define RTC_TRY RTC_EXCEPTION e; bool rtcexc_was_thrown; -+#define RTC_BEGIN RTC_EXCEPTION e; bool rtcexc_was_thrown -+#define RTC_CATCH(extype) while (false) rtcexc_catch_label: -+#define RTC_WRAPPED(T) ::rtc::WrappedResult -+#define RTC_THROW_WITHIN(exception) while ((e = (exception)), (rtcexc_was_thrown = true)) goto rtcexc_catch_label -+#define RTC_VOID ::rtc::WrappedResult() -+#define RTC_RET return RTC_VOID -+ -+#define RTC_UNWRAP_EXPR(func) ([&](){ auto [rtcexc_value, _rtcexc_e, _rtcexc_was_thrown] = (func); e = _rtcexc_e; rtcexc_was_thrown = rtcexc_was_thrown || _rtcexc_was_thrown; return rtcexc_value; })() -+#define RTC_CATCH_EXCEPTION while (rtcexc_was_thrown) goto rtcexc_catch_label -+#define RTC_RETHROW while (rtcexc_was_thrown) return e -+ -+#define RTC_UNWRAP_CATCH(func) do { RTC_UNWRAP_EXPR(func); RTC_CATCH_EXCEPTION; } while (0) -+#define RTC_UNWRAP_RETHROW(func) do { RTC_UNWRAP_EXPR(func); RTC_RETHROW; } while (0) -+#define RTC_UNWRAP_CATCH_ARG(wrap, func) do { wrap(RTC_UNWRAP_EXPR(func)); RTC_CATCH_EXCEPTION; } while (0) -+#define RTC_UNWRAP_RETHROW_ARG(wrap, func) do { wrap(RTC_UNWRAP_EXPR(func)); RTC_RETHROW; } while (0) -+// Note: in a single-line if statement, this would fall out. -+// This should only be used for variable declarations which cannot occur in a single line. -+#define RTC_UNWRAP_CATCH_DECL(typ, var, func) typ var = RTC_UNWRAP_EXPR(func); RTC_CATCH_EXCEPTION; -+#define RTC_UNWRAP_RETHROW_DECL(typ, var, func) typ var = RTC_UNWRAP_EXPR(func); RTC_RETHROW; -+#define RTC_UNWRAP_CATCH_VAR(var, func) do { var = RTC_UNWRAP_EXPR(func); RTC_CATCH_EXCEPTION; } while (0) -+#define RTC_UNWRAP_RETHROW_VAR(var, func) do { var = RTC_UNWRAP_EXPR(func); RTC_RETHROW; } while (0) -+#define RTC_COMMA , -+ -+#endif -+ - using std::byte; - using std::nullopt; - using std::optional; -diff --git a/thirdparty/libdatachannel/include/rtc/datachannel.hpp b/thirdparty/libdatachannel/include/rtc/datachannel.hpp -index 0e83a97900..b866d7e659 100644 ---- a/thirdparty/libdatachannel/include/rtc/datachannel.hpp -+++ b/thirdparty/libdatachannel/include/rtc/datachannel.hpp -@@ -40,8 +40,8 @@ public: - size_t maxMessageSize() const override; - - void close(void) override; -- bool send(message_variant data) override; -- bool send(const byte *data, size_t size) override; -+ RTC_WRAPPED(bool) send(message_variant data) override; -+ RTC_WRAPPED(bool) send(const byte *data, size_t size) override; - template bool sendBuffer(const Buffer &buf); - template bool sendBuffer(Iterator first, Iterator last); - -diff --git a/thirdparty/libdatachannel/include/rtc/description.hpp b/thirdparty/libdatachannel/include/rtc/description.hpp -index 22174a7824..ab8661b537 100644 ---- a/thirdparty/libdatachannel/include/rtc/description.hpp -+++ b/thirdparty/libdatachannel/include/rtc/description.hpp -@@ -41,8 +41,12 @@ public: - Unknown = RTC_DIRECTION_UNKNOWN - }; - -- Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass); -- Description(const string &sdp, string typeString); -+private: -+ RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(Description); -+ Description(Type type = Type::Unspec, Role role = Role::ActPass); -+public: -+ static RTC_WRAPPED(Description) create(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass); -+ static RTC_WRAPPED(Description) create(const string &sdp, string typeString); - - Type type() const; - string typeString() const; -@@ -55,7 +59,7 @@ public: - bool ended() const; - - void hintType(Type type); -- void setFingerprint(string fingerprint); -+ RTC_WRAPPED(void) setFingerprint(string fingerprint); - void addIceOption(string option); - void removeIceOption(const string &option); - -@@ -94,12 +98,16 @@ public: - void addRid(string rid); - - struct RTC_CPP_EXPORT ExtMap { -- static int parseId(string_view description); -+ private: -+ RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(ExtMap); -+ ExtMap() {} -+ public: -+ static RTC_WRAPPED(int) parseId(string_view description); - - ExtMap(int id, string uri, Direction direction = Direction::Unknown); -- ExtMap(string_view description); -+ static RTC_WRAPPED(ExtMap) create(string_view description); - -- void setDescription(string_view description); -+ RTC_WRAPPED(void) setDescription(string_view description); - - int id; - string uri; -@@ -108,7 +116,7 @@ public: - }; - - std::vector extIds(); -- ExtMap *extMap(int id); -+ RTC_WRAPPED(ExtMap *) extMap(int id); - void addExtMap(ExtMap map); - void removeExtMap(int id); - -@@ -116,9 +124,10 @@ public: - string generateSdp(string_view eol = "\r\n", string_view addr = "0.0.0.0", - uint16_t port = 9) const; - -- virtual void parseSdpLine(string_view line); -+ virtual RTC_WRAPPED(void) parseSdpLine(string_view line); - - protected: -+ Entry() {} - Entry(const string &mline, string mid, Direction dir = Direction::Unknown); - - virtual string generateSdpLines(string_view eol) const; -@@ -151,7 +160,7 @@ public: - optional sctpPort() const; - optional maxMessageSize() const; - -- virtual void parseSdpLine(string_view line) override; -+ virtual RTC_WRAPPED(void) parseSdpLine(string_view line) override; - - private: - virtual string generateSdpLines(string_view eol) const override; -@@ -162,8 +171,11 @@ public: - - // Media (non-data) - class RTC_CPP_EXPORT Media : public Entry { -- public: -+ RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(Media); -+ Media() {} - Media(const string &sdp); -+ public: -+ RTC_WRAPPED(Media) create(const string &sdp); - Media(const string &mline, string mid, Direction dir = Direction::SendOnly); - virtual ~Media() = default; - -@@ -184,12 +196,16 @@ public: - void setBitrate(int bitrate); - - struct RTC_CPP_EXPORT RtpMap { -- static int parsePayloadType(string_view description); -+ private: -+ RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(RtpMap); -+ RtpMap() {} -+ public: -+ static RTC_WRAPPED(int) parsePayloadType(string_view description); - - explicit RtpMap(int payloadType); -- RtpMap(string_view description); -+ static RTC_WRAPPED(RtpMap) create(string_view description); - -- void setDescription(string_view description); -+ RTC_WRAPPED(void) setDescription(string_view description); - - void addFeedback(string fb); - void removeFeedback(const string &str); -@@ -207,14 +223,14 @@ public: - - bool hasPayloadType(int payloadType) const; - std::vector payloadTypes() const; -- RtpMap *rtpMap(int payloadType); -+ RTC_WRAPPED(RtpMap *) rtpMap(int payloadType); - void addRtpMap(RtpMap map); - void removeRtpMap(int payloadType); - void removeFormat(const string &format); - -- void addRtxCodec(int payloadType, int origPayloadType, unsigned int clockRate); -+ RTC_WRAPPED(void) addRtxCodec(int payloadType, int origPayloadType, unsigned int clockRate); - -- virtual void parseSdpLine(string_view line) override; -+ virtual RTC_WRAPPED(void) parseSdpLine(string_view line) override; - - private: - virtual string generateSdpLines(string_view eol) const override; -@@ -230,25 +246,25 @@ public: - public: - Audio(string mid = "audio", Direction dir = Direction::SendOnly); - -- void addAudioCodec(int payloadType, string codec, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addAudioCodec(int payloadType, string codec, optional profile = std::nullopt); - -- void addOpusCodec(int payloadType, optional profile = DEFAULT_OPUS_AUDIO_PROFILE); -- void addPCMACodec(int payloadType, optional profile = std::nullopt); -- void addPCMUCodec(int payloadType, optional profile = std::nullopt); -- void addAacCodec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addOpusCodec(int payloadType, optional profile = DEFAULT_OPUS_AUDIO_PROFILE); -+ RTC_WRAPPED(void) addPCMACodec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addPCMUCodec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addAacCodec(int payloadType, optional profile = std::nullopt); - }; - - class RTC_CPP_EXPORT Video : public Media { - public: - Video(string mid = "video", Direction dir = Direction::SendOnly); - -- void addVideoCodec(int payloadType, string codec, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addVideoCodec(int payloadType, string codec, optional profile = std::nullopt); - -- void addH264Codec(int payloadType, optional profile = DEFAULT_H264_VIDEO_PROFILE); -- void addH265Codec(int payloadType, optional profile = std::nullopt); -- void addVP8Codec(int payloadType, optional profile = std::nullopt); -- void addVP9Codec(int payloadType, optional profile = std::nullopt); -- void addAV1Codec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addH264Codec(int payloadType, optional profile = DEFAULT_H264_VIDEO_PROFILE); -+ RTC_WRAPPED(void) addH265Codec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addVP8Codec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addVP9Codec(int payloadType, optional profile = std::nullopt); -+ RTC_WRAPPED(void) addAV1Codec(int payloadType, optional profile = std::nullopt); - }; - - bool hasApplication() const; -@@ -262,8 +278,9 @@ public: - int addAudio(string mid = "audio", Direction dir = Direction::SendOnly); - void clearMedia(); - -- variant media(unsigned int index); -- variant media(unsigned int index) const; -+ RTC_WRAPPED(variant) media(unsigned int index); -+ RTC_WRAPPED(variant) media(unsigned int index) const; -+ - unsigned int mediaCount() const; - - const Application *application() const; -diff --git a/thirdparty/libdatachannel/include/rtc/global.hpp b/thirdparty/libdatachannel/include/rtc/global.hpp -index a2038ed095..b4910e0994 100644 ---- a/thirdparty/libdatachannel/include/rtc/global.hpp -+++ b/thirdparty/libdatachannel/include/rtc/global.hpp -@@ -50,7 +50,7 @@ struct SctpSettings { - optional heartbeatInterval; - }; - --RTC_CPP_EXPORT void SetSctpSettings(SctpSettings s); -+RTC_CPP_EXPORT RTC_WRAPPED(void) SetSctpSettings(SctpSettings s); - - } // namespace rtc - -diff --git a/thirdparty/libdatachannel/include/rtc/peerconnection.hpp b/thirdparty/libdatachannel/include/rtc/peerconnection.hpp -index 512bed3c83..ebcd41f989 100644 ---- a/thirdparty/libdatachannel/include/rtc/peerconnection.hpp -+++ b/thirdparty/libdatachannel/include/rtc/peerconnection.hpp -@@ -87,18 +87,18 @@ public: - optional localAddress() const; - optional remoteAddress() const; - uint16_t maxDataChannelId() const; -- bool getSelectedCandidatePair(Candidate *local, Candidate *remote); -+ RTC_WRAPPED(bool) getSelectedCandidatePair(Candidate *local, Candidate *remote); - -- void setLocalDescription(Description::Type type = Description::Type::Unspec); -- void setRemoteDescription(Description description); -- void addRemoteCandidate(Candidate candidate); -+ RTC_WRAPPED(void) setLocalDescription(Description::Type type = Description::Type::Unspec); -+ RTC_WRAPPED(void) setRemoteDescription(Description description); -+ RTC_WRAPPED(void) addRemoteCandidate(Candidate candidate); - - #if RTC_ENABLE_MEDIA - void setMediaHandler(shared_ptr handler); - shared_ptr getMediaHandler(); - #endif - -- [[nodiscard]] shared_ptr createDataChannel(string label, -+ [[nodiscard]] RTC_WRAPPED(shared_ptr) createDataChannel(string label, - DataChannelInit init = {}); - void onDataChannel(std::function dataChannel)> callback); - -diff --git a/thirdparty/libdatachannel/include/rtc/track.hpp b/thirdparty/libdatachannel/include/rtc/track.hpp -index a47ba5ae65..6f217b8d03 100644 ---- a/thirdparty/libdatachannel/include/rtc/track.hpp -+++ b/thirdparty/libdatachannel/include/rtc/track.hpp -@@ -34,8 +34,8 @@ public: - void setDescription(Description::Media description); - - void close(void) override; -- bool send(message_variant data) override; -- bool send(const byte *data, size_t size) override; -+ RTC_WRAPPED(bool) send(message_variant data) override; -+ RTC_WRAPPED(bool) send(const byte *data, size_t size) override; - - bool isOpen(void) const override; - bool isClosed(void) const override; -diff --git a/thirdparty/libdatachannel/src/candidate.cpp b/thirdparty/libdatachannel/src/candidate.cpp -index cd88b0e108..d5ae9e69e4 100644 ---- a/thirdparty/libdatachannel/src/candidate.cpp -+++ b/thirdparty/libdatachannel/src/candidate.cpp -@@ -57,19 +57,27 @@ Candidate::Candidate() - mTransportString("unknown"), mType(Type::Unknown), mTransportType(TransportType::Unknown), - mNode("0.0.0.0"), mService("9"), mFamily(Family::Unresolved), mPort(0) {} - --Candidate::Candidate(string candidate) : Candidate() { -- if (!candidate.empty()) -- parse(std::move(candidate)); -+RTC_WRAPPED(Candidate) Candidate::create(string candidate) { -+ RTC_BEGIN; -+ Candidate ret; -+ if (!candidate.empty()) { -+ RTC_UNWRAP_RETHROW(ret.parse(std::move(candidate))); -+ } -+ return ret; - } - --Candidate::Candidate(string candidate, string mid) : Candidate() { -- if (!candidate.empty()) -- parse(std::move(candidate)); -+RTC_WRAPPED(Candidate) Candidate::create(string candidate, string mid) { -+ RTC_BEGIN; -+ Candidate ret; -+ if (!candidate.empty()) { -+ RTC_UNWRAP_RETHROW(ret.parse(std::move(candidate))); -+ } - if (!mid.empty()) -- mMid.emplace(std::move(mid)); -+ ret.mMid.emplace(std::move(mid)); -+ return ret; - } - --void Candidate::parse(string candidate) { -+RTC_WRAPPED(void) Candidate::parse(string candidate) { - using TypeMap_t = std::unordered_map; - using TcpTypeMap_t = std::unordered_map; - -@@ -93,8 +101,11 @@ void Candidate::parse(string candidate) { - std::istringstream iss(candidate); - string typ_; - if (!(iss >> mFoundation >> mComponent >> mTransportString >> mPriority && -- iss >> mNode >> mService >> typ_ >> mTypeString && typ_ == "typ")) -- throw std::invalid_argument("Invalid candidate format"); -+ iss >> mNode >> mService >> typ_ >> mTypeString && typ_ == "typ")) { -+ PLOG_ERROR << "Invalid candidate format"; -+ mType = Type::Unknown; -+ RTC_RET; -+ } - - std::getline(iss, mTail); - trim_begin(mTail); -@@ -123,6 +134,7 @@ void Candidate::parse(string candidate) { - } else { - mTransportType = TransportType::Unknown; - } -+ return RTC_VOID; - } - - void Candidate::hintMid(string mid) { -@@ -130,13 +142,19 @@ void Candidate::hintMid(string mid) { - mMid.emplace(std::move(mid)); - } - --void Candidate::changeAddress(string addr) { changeAddress(std::move(addr), mService); } -+RTC_WRAPPED(void) Candidate::changeAddress(string addr) { -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW(changeAddress(std::move(addr), mService)); -+ return RTC_VOID; -+} - --void Candidate::changeAddress(string addr, uint16_t port) { -- changeAddress(std::move(addr), std::to_string(port)); -+RTC_WRAPPED(void) Candidate::changeAddress(string addr, uint16_t port) { -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW(changeAddress(std::move(addr), std::to_string(port))); -+ return RTC_VOID; - } - --void Candidate::changeAddress(string addr, string service) { -+RTC_WRAPPED(void) Candidate::changeAddress(string addr, string service) { - mNode = std::move(addr); - mService = std::move(service); - -@@ -145,7 +163,8 @@ void Candidate::changeAddress(string addr, string service) { - mPort = 0; - - if (!resolve(ResolveMode::Simple)) -- throw std::invalid_argument("Invalid candidate address \"" + addr + ":" + service + "\""); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid candidate address \"" + addr + ":" + service + "\""); -+ RTC_RET; - } - - bool Candidate::resolve(ResolveMode mode) { -@@ -177,9 +196,9 @@ bool Candidate::resolve(ResolveMode mode) { - if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer, - MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN, - NI_NUMERICHOST | NI_NUMERICSERV) == 0) { -- try { -+ RTC_TRY { - mPort = uint16_t(std::stoul(servbuffer)); -- } catch (...) { -+ } RTC_CATCH (...) { - return false; - } - mAddress = nodebuffer; -diff --git a/thirdparty/libdatachannel/src/configuration.cpp b/thirdparty/libdatachannel/src/configuration.cpp -index fe28aef715..6b576bc146 100644 ---- a/thirdparty/libdatachannel/src/configuration.cpp -+++ b/thirdparty/libdatachannel/src/configuration.cpp -@@ -7,10 +7,13 @@ - */ - - #include "configuration.hpp" -+#include "rtp.hpp" - -+#include "impl/internals.hpp" - #include "impl/utils.hpp" - - #include -+#include - #include - - namespace { -@@ -42,8 +45,10 @@ namespace utils = impl::utils; - - IceServer::IceServer(const string &url) { - std::vector> opt; -- if (!parse_url(url, opt)) -- throw std::invalid_argument("Invalid ICE server URL: " + url); -+ if (!parse_url(url, opt)) { -+ PLOG_WARNING << "Invalid ICE server URL: " << url; -+ return; -+ } - - string scheme = opt[2].value_or("stun"); - relayType = RelayType::TurnUdp; -@@ -54,8 +59,10 @@ IceServer::IceServer(const string &url) { - else if (scheme == "turns" || scheme == "TURNS") { - type = Type::Turn; - relayType = RelayType::TurnTls; -- } else -- throw std::invalid_argument("Unknown ICE server protocol: " + scheme); -+ } else { -+ type = Type::Turn; -+ PLOG_WARNING << "Unknown ICE server protocol: " << scheme; -+ } - - if (auto &query = opt[15]) { - if (query->find("transport=udp") != string::npos) -@@ -79,10 +86,11 @@ IceServer::IceServer(const string &url) { - } - - string service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478"); -- try { -- port = uint16_t(std::stoul(service)); -- } catch (...) { -- throw std::invalid_argument("Invalid ICE server port in URL: " + service); -+ { -+ port = uint16_t(std::strtoul(service.c_str(), nullptr, 10)); -+ } -+ if (port == 0) { -+ PLOG_WARNING << "Invalid ICE server port in URL: " << service; - } - } - -@@ -91,10 +99,11 @@ IceServer::IceServer(string hostname_, uint16_t port_) - - IceServer::IceServer(string hostname_, string service_) - : hostname(std::move(hostname_)), type(Type::Stun) { -- try { -- port = uint16_t(std::stoul(service_)); -- } catch (...) { -- throw std::invalid_argument("Invalid ICE server port: " + service_); -+ { -+ port = uint16_t(std::strtoul(service_.c_str(), nullptr, 10)); -+ } -+ if (port == 0) { -+ PLOG_WARNING << "Invalid ICE server port: " << service_; - } - } - -@@ -107,25 +116,30 @@ IceServer::IceServer(string hostname_, string service_, string username_, string - RelayType relayType_) - : hostname(std::move(hostname_)), type(Type::Turn), username(std::move(username_)), - password(std::move(password_)), relayType(relayType_) { -- try { -- port = uint16_t(std::stoul(service_)); -- } catch (...) { -- throw std::invalid_argument("Invalid ICE server port: " + service_); -+ { -+ port = uint16_t(std::strtoul(service_.c_str(), nullptr, 10)); -+ } -+ if (port == 0) { -+ PLOG_WARNING << "Invalid ICE server port : " << service_; - } - } - - ProxyServer::ProxyServer(const string &url) { - std::vector> opt; -- if (!parse_url(url, opt)) -- throw std::invalid_argument("Invalid proxy server URL: " + url); -+ if (!parse_url(url, opt)) { -+ PLOG_WARNING << "Invalid proxy server URL: " << url; -+ return; -+ } - - string scheme = opt[2].value_or("http"); - if (scheme == "http" || scheme == "HTTP") - type = Type::Http; - else if (scheme == "socks5" || scheme == "SOCKS5") - type = Type::Socks5; -- else -- throw std::invalid_argument("Unknown proxy server protocol: " + scheme); -+ else { -+ type = Type::Http; -+ PLOG_WARNING << "Unknown proxy server protocol: " << scheme; -+ } - - username = opt[6]; - password = opt[8]; -@@ -137,10 +151,11 @@ ProxyServer::ProxyServer(const string &url) { - hostname.pop_back(); - - string service = opt[12].value_or(type == Type::Socks5 ? "1080" : "3128"); -- try { -- port = uint16_t(std::stoul(service)); -- } catch (...) { -- throw std::invalid_argument("Invalid proxy server port in URL: " + service); -+ { -+ port = uint16_t(std::strtoul(service.c_str(), nullptr, 10)); -+ } -+ if (port == 0) { -+ PLOG_WARNING << "Invalid proxy server port in URL: " << service; - } - } - -diff --git a/thirdparty/libdatachannel/src/datachannel.cpp b/thirdparty/libdatachannel/src/datachannel.cpp -index 80a151f33e..a80a5af175 100644 ---- a/thirdparty/libdatachannel/src/datachannel.cpp -+++ b/thirdparty/libdatachannel/src/datachannel.cpp -@@ -46,11 +46,11 @@ bool DataChannel::isClosed(void) const { return impl()->isClosed(); } - - size_t DataChannel::maxMessageSize() const { return impl()->maxMessageSize(); } - --bool DataChannel::send(message_variant data) { -+RTC_WRAPPED(bool) DataChannel::send(message_variant data) { - return impl()->outgoing(make_message(std::move(data))); - } - --bool DataChannel::send(const byte *data, size_t size) { -+RTC_WRAPPED(bool) DataChannel::send(const byte *data, size_t size) { - return impl()->outgoing(std::make_shared(data, data + size, Message::Binary)); - } - -diff --git a/thirdparty/libdatachannel/src/description.cpp b/thirdparty/libdatachannel/src/description.cpp -index f153e6f0e3..b276357ecd 100644 ---- a/thirdparty/libdatachannel/src/description.cpp -+++ b/thirdparty/libdatachannel/src/description.cpp -@@ -55,13 +55,14 @@ inline std::pair parse_pair(string_view attr) { - return std::make_pair(std::move(key), std::move(value)); - } - --template T to_integer(string_view s) { -+template RTC_WRAPPED(T) to_integer(string_view s) { - const string str(s); -- try { -- return std::is_signed::value ? T(std::stol(str)) : T(std::stoul(str)); -- } catch (...) { -- throw std::invalid_argument("Invalid integer \"" + str + "\" in description"); -+ char *p; -+ T ret = std::is_signed::value ? T(strtol(str.c_str(), &p, 10)) : T(strtoul(str.c_str(), &p, 10)); -+ if (*p == 0) { -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid integer \"" + str + "\" in description"); - } -+ return ret; - } - - inline bool is_sha256_fingerprint(string_view f) { -@@ -86,9 +87,13 @@ namespace rtc { - - namespace utils = impl::utils; - --Description::Description(const string &sdp, Type type, Role role) -+Description::Description(Type type, Role role) - : mType(Type::Unspec), mRole(role) { -- hintType(type); -+} -+RTC_WRAPPED(Description) Description::create(const string &sdp, Type type, Role role) { -+ RTC_BEGIN; -+ Description ret(type, role); -+ ret.hintType(type); - - int index = -1; - shared_ptr current; -@@ -101,11 +106,11 @@ Description::Description(const string &sdp, Type type, Role role) - continue; - - if (match_prefix(line, "m=")) { // Media description line (aka m-line) -- current = createEntry(line.substr(2), std::to_string(++index), Direction::Unknown); -+ current = ret.createEntry(line.substr(2), std::to_string(++index), Direction::Unknown); - - } else if (match_prefix(line, "o=")) { // Origin line - std::istringstream origin(line.substr(2)); -- origin >> mUsername >> mSessionId; -+ origin >> ret.mUsername >> ret.mSessionId; - - } else if (match_prefix(line, "a=")) { // Attribute line - string attr = line.substr(2); -@@ -113,53 +118,56 @@ Description::Description(const string &sdp, Type type, Role role) - - if (key == "setup") { - if (value == "active") -- mRole = Role::Active; -+ ret.mRole = Role::Active; - else if (value == "passive") -- mRole = Role::Passive; -+ ret.mRole = Role::Passive; - else -- mRole = Role::ActPass; -+ ret.mRole = Role::ActPass; - - } else if (key == "fingerprint") { - if (match_prefix(value, "sha-256 ") || match_prefix(value, "SHA-256 ")) { - string fingerprint{value.substr(8)}; - trim_begin(fingerprint); -- setFingerprint(std::move(fingerprint)); -+ RTC_UNWRAP_RETHROW(ret.setFingerprint(std::move(fingerprint))); - } else { - PLOG_WARNING << "Unknown SDP fingerprint format: " << value; - } - } else if (key == "ice-ufrag") { -- mIceUfrag = value; -+ ret.mIceUfrag = value; - } else if (key == "ice-pwd") { -- mIcePwd = value; -+ ret.mIcePwd = value; - } else if (key == "ice-options") { -- mIceOptions = utils::explode(string(value), ','); -+ ret.mIceOptions = utils::explode(string(value), ','); - } else if (key == "candidate") { -- addCandidate(Candidate(attr, bundleMid())); -+ RTC_UNWRAP_RETHROW_DECL(Candidate, tmp, Candidate::create(attr, ret.bundleMid())); -+ ret.addCandidate(tmp); - } else if (key == "end-of-candidates") { -- mEnded = true; -+ ret.mEnded = true; - } else if (current) { -- current->parseSdpLine(std::move(line)); -+ RTC_UNWRAP_RETHROW(current->parseSdpLine(std::move(line))); - } else { -- mAttributes.emplace_back(attr); -+ ret.mAttributes.emplace_back(attr); - } - - } else if (current) { -- current->parseSdpLine(std::move(line)); -+ RTC_UNWRAP_RETHROW(current->parseSdpLine(std::move(line))); - } - } - -- if (mUsername.empty()) -- mUsername = "rtc"; -+ if (ret.mUsername.empty()) -+ ret.mUsername = "rtc"; - -- if (mSessionId.empty()) { -+ if (ret.mSessionId.empty()) { - auto uniform = std::bind(std::uniform_int_distribution(), utils::random_engine()); -- mSessionId = std::to_string(uniform()); -+ ret.mSessionId = std::to_string(uniform()); - } -+ return ret; - } - --Description::Description(const string &sdp, string typeString) -- : Description(sdp, !typeString.empty() ? stringToType(typeString) : Type::Unspec, -- Role::ActPass) {} -+RTC_WRAPPED(Description) Description::create(const string &sdp, string typeString) { -+ return create(sdp, !typeString.empty() ? stringToType(typeString) : Type::Unspec, -+ Role::ActPass); -+} - - Description::Type Description::type() const { return mType; } - -@@ -191,13 +199,14 @@ void Description::hintType(Type type) { - mType = type; - } - --void Description::setFingerprint(string fingerprint) { -+RTC_WRAPPED(void) Description::setFingerprint(string fingerprint) { - if (!is_sha256_fingerprint(fingerprint)) -- throw std::invalid_argument("Invalid SHA256 fingerprint \"" + fingerprint + "\""); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid SHA256 fingerprint \"" + fingerprint + "\""); - - std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(), - [](char c) { return char(std::toupper(c)); }); - mFingerprint.emplace(std::move(fingerprint)); -+ RTC_RET; - } - - void Description::addIceOption(string option) { -@@ -459,44 +468,45 @@ void Description::clearMedia() { - mApplication.reset(); - } - --variant Description::media(unsigned int index) { -+RTC_WRAPPED(variant) -+Description::media(unsigned int index) { - if (index >= mEntries.size()) -- throw std::out_of_range("Media index out of range"); -+ RTC_THROW RTC_OUT_OF_RANGE("Media index out of range"); - - const auto &entry = mEntries[index]; - if (entry == mApplication) { - auto result = dynamic_cast(entry.get()); - if (!result) -- throw std::logic_error("Bad type of application in description"); -+ RTC_THROW RTC_LOGIC_ERROR("Bad type of application in description"); - - return result; - - } else { - auto result = dynamic_cast(entry.get()); - if (!result) -- throw std::logic_error("Bad type of media in description"); -+ RTC_THROW RTC_LOGIC_ERROR("Bad type of media in description"); - - return result; - } - } - --variant -+RTC_WRAPPED(variant) - Description::media(unsigned int index) const { - if (index >= mEntries.size()) -- throw std::out_of_range("Media index out of range"); -+ RTC_THROW RTC_OUT_OF_RANGE("Media index out of range"); - - const auto &entry = mEntries[index]; - if (entry == mApplication) { - auto result = dynamic_cast(entry.get()); - if (!result) -- throw std::logic_error("Bad type of application in description"); -+ RTC_THROW RTC_LOGIC_ERROR("Bad type of application in description"); - - return result; - - } else { - auto result = dynamic_cast(entry.get()); - if (!result) -- throw std::logic_error("Bad type of media in description"); -+ RTC_THROW RTC_LOGIC_ERROR("Bad type of media in description"); - - return result; - } -@@ -559,10 +569,10 @@ std::vector Description::Entry::extIds() { - return result; - } - --Description::Entry::ExtMap *Description::Entry::extMap(int id) { -+RTC_WRAPPED(Description::Entry::ExtMap *) Description::Entry::extMap(int id) { - auto it = mExtMaps.find(id); - if (it == mExtMaps.end()) -- throw std::invalid_argument("extmap not found"); -+ RTC_THROW RTC_INVALID_ARGUMENT("extmap not found"); - - return &it->second; - } -@@ -641,7 +651,8 @@ string Description::Entry::generateSdpLines(string_view eol) const { - return sdp.str(); - } - --void Description::Entry::parseSdpLine(string_view line) { -+RTC_WRAPPED(void) Description::Entry::parseSdpLine(string_view line) { -+ RTC_BEGIN; - if (match_prefix(line, "a=")) { - string_view attr = line.substr(2); - auto [key, value] = parse_pair(attr); -@@ -649,12 +660,13 @@ void Description::Entry::parseSdpLine(string_view line) { - if (key == "mid") { - mMid = value; - } else if (key == "extmap") { -- auto id = Description::Media::ExtMap::parseId(value); -+ RTC_UNWRAP_RETHROW_DECL(int, id, Description::Media::ExtMap::parseId(value)); - auto it = mExtMaps.find(id); -- if (it == mExtMaps.end()) -- it = mExtMaps.insert(std::make_pair(id, Description::Media::ExtMap(value))).first; -- else -- it->second.setDescription(value); -+ if (it == mExtMaps.end()) { -+ RTC_UNWRAP_RETHROW_DECL(auto, tmp, Description::Media::ExtMap::create(value)); -+ it = mExtMaps.insert(std::make_pair(id, tmp)).first; -+ } else -+ RTC_UNWRAP_RETHROW(it->second.setDescription(value)); - - } else if (attr == "sendonly") - mDirection = Direction::SendOnly; -@@ -673,9 +685,10 @@ void Description::Entry::parseSdpLine(string_view line) { - mAttributes.emplace_back(attr); - } - } -+ RTC_RET; - } - --int Description::Entry::ExtMap::parseId(string_view description) { -+RTC_WRAPPED(int) Description::Entry::ExtMap::parseId(string_view description) { - size_t p = description.find(' '); - return to_integer(description.substr(0, p)); - } -@@ -686,19 +699,26 @@ Description::Entry::ExtMap::ExtMap(int id, string uri, Direction direction) { - this->direction = direction; - } - --Description::Entry::ExtMap::ExtMap(string_view description) { setDescription(description); } -+RTC_WRAPPED(Description::Entry::ExtMap) Description::Entry::ExtMap::create(string_view description) { -+ Description::Entry::ExtMap ret; -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW(ret.setDescription(description)); -+ return ret; -+} - --void Description::Entry::ExtMap::setDescription(string_view description) { -+RTC_WRAPPED(void) -+Description::Entry::ExtMap::setDescription(string_view description) { -+ RTC_BEGIN; - const size_t uriStart = description.find(' '); - if (uriStart == string::npos) -- throw std::invalid_argument("Invalid description for extmap"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid description for extmap"); - - const string_view idAndDirection = description.substr(0, uriStart); - const size_t idSplit = idAndDirection.find('/'); -- if (idSplit == string::npos) { -- this->id = to_integer(idAndDirection); -- } else { -- this->id = to_integer(idAndDirection.substr(0, idSplit)); -+ if (idSplit == string::npos) -+ RTC_UNWRAP_RETHROW_VAR(this->id, to_integer(idAndDirection)); -+ else { -+ RTC_UNWRAP_RETHROW_VAR(this->id, (to_integer(idAndDirection.substr(0, idSplit)))); - - const string_view directionStr = idAndDirection.substr(idSplit + 1); - if (directionStr == "sendonly") -@@ -710,7 +730,7 @@ void Description::Entry::ExtMap::setDescription(string_view description) { - else if (directionStr == "inactive") - this->direction = Direction::Inactive; - else -- throw std::invalid_argument("Invalid direction for extmap"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid direction for extmap"); - } - - const string_view uriAndAttributes = description.substr(uriStart + 1); -@@ -722,6 +742,7 @@ void Description::Entry::ExtMap::setDescription(string_view description) { - this->uri = uriAndAttributes.substr(0, attributeSplit); - this->attributes = uriAndAttributes.substr(attributeSplit + 1); - } -+ RTC_RET; - } - - void Description::Media::addSSRC(uint32_t ssrc, optional name, optional msid, -@@ -825,24 +846,32 @@ string Description::Application::generateSdpLines(string_view eol) const { - return sdp.str(); - } - --void Description::Application::parseSdpLine(string_view line) { -+RTC_WRAPPED(void) Description::Application::parseSdpLine(string_view line) { -+ RTC_BEGIN; - if (match_prefix(line, "a=")) { - string_view attr = line.substr(2); - auto [key, value] = parse_pair(attr); - - if (key == "sctp-port") { -- mSctpPort = to_integer(value); -+ RTC_UNWRAP_RETHROW_VAR(mSctpPort, to_integer(value)); - } else if (key == "max-message-size") { -- mMaxMessageSize = to_integer(value); -+ RTC_UNWRAP_RETHROW_VAR(mMaxMessageSize, to_integer(value)); - } else { -- Entry::parseSdpLine(line); -+ RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } - } else { -- Entry::parseSdpLine(line); -+ RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } -+ RTC_RET; -+} -+ -+Description::Media::Media(const string& sdp) : -+ Entry(sdp, "", Direction::Unknown) { - } - --Description::Media::Media(const string &sdp) : Entry(sdp, "", Direction::Unknown) { -+RTC_WRAPPED(Description::Media) Description::Media::create(const string &sdp) { -+ RTC_BEGIN; -+ Media ret = sdp; - std::istringstream ss(sdp); - while (ss) { - string line; -@@ -851,11 +880,12 @@ Description::Media::Media(const string &sdp) : Entry(sdp, "", Direction::Unknown - if (line.empty()) - continue; - -- parseSdpLine(line); -+ RTC_UNWRAP_RETHROW(ret.parseSdpLine(line)); - } - -- if (mid().empty()) -- throw std::invalid_argument("Missing mid in media description"); -+ if (ret.mid().empty()) -+ PLOG_WARNING << "Missing mid in media description"; -+ return ret; - } - - Description::Media::Media(const string &mline, string mid, Direction dir) -@@ -929,10 +959,10 @@ std::vector Description::Media::payloadTypes() const { - return result; - } - --Description::Media::RtpMap *Description::Media::rtpMap(int payloadType) { -+RTC_WRAPPED(Description::Media::RtpMap *) Description::Media::rtpMap(int payloadType) { - auto it = mRtpMaps.find(payloadType); - if (it == mRtpMaps.end()) -- throw std::invalid_argument("rtpmap not found"); -+ RTC_THROW RTC_INVALID_ARGUMENT("rtpmap not found"); - - return &it->second; - } -@@ -968,10 +998,12 @@ void Description::Media::removeFormat(const string &format) { - removeRtpMap(pt); - } - --void Description::Media::addRtxCodec(int payloadType, int origPayloadType, unsigned int clockRate) { -- RtpMap rtp(std::to_string(payloadType) + " RTX/" + std::to_string(clockRate)); -+RTC_WRAPPED(void) Description::Media::addRtxCodec(int payloadType, int origPayloadType, unsigned int clockRate) { -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW_DECL(RtpMap, rtp, RtpMap::create(std::to_string(payloadType) + " RTX/" + std::to_string(clockRate))); - rtp.fmtps.emplace_back("apt=" + std::to_string(origPayloadType)); - addRtpMap(rtp); -+ RTC_RET; - } - - string Description::Media::generateSdpLines(string_view eol) const { -@@ -1002,22 +1034,24 @@ string Description::Media::generateSdpLines(string_view eol) const { - return sdp.str(); - } - --void Description::Media::parseSdpLine(string_view line) { -+RTC_WRAPPED(void) Description::Media::parseSdpLine(string_view line) { -+ RTC_BEGIN; - if (match_prefix(line, "a=")) { - string_view attr = line.substr(2); - auto [key, value] = parse_pair(attr); - - if (key == "rtpmap") { -- auto pt = Description::Media::RtpMap::parsePayloadType(value); -+ RTC_UNWRAP_RETHROW_DECL(auto, pt, Description::Media::RtpMap::parsePayloadType(value)); - auto it = mRtpMaps.find(pt); -- if (it == mRtpMaps.end()) -- it = mRtpMaps.insert(std::make_pair(pt, Description::Media::RtpMap(value))).first; -- else -- it->second.setDescription(value); -+ if (it == mRtpMaps.end()) { -+ RTC_UNWRAP_RETHROW_DECL(Description::Media::RtpMap, tmp, Description::Media::RtpMap::create(value)); -+ it = mRtpMaps.insert(std::make_pair(pt, tmp)).first; -+ } else -+ RTC_UNWRAP_RETHROW(it->second.setDescription(value)); - - } else if (key == "rtcp-fb") { - size_t p = value.find(' '); -- int pt = to_integer(value.substr(0, p)); -+ RTC_UNWRAP_RETHROW_DECL(int, pt, to_integer(value.substr(0, p))); - auto it = mRtpMaps.find(pt); - if (it == mRtpMaps.end()) - it = mRtpMaps.insert(std::make_pair(pt, Description::Media::RtpMap(pt))).first; -@@ -1026,7 +1060,7 @@ void Description::Media::parseSdpLine(string_view line) { - - } else if (key == "fmtp") { - size_t p = value.find(' '); -- int pt = to_integer(value.substr(0, p)); -+ RTC_UNWRAP_RETHROW_DECL(int, pt, to_integer(value.substr(0, p))); - auto it = mRtpMaps.find(pt); - if (it == mRtpMaps.end()) - it = mRtpMaps.insert(std::make_pair(pt, Description::Media::RtpMap(pt))).first; -@@ -1037,7 +1071,7 @@ void Description::Media::parseSdpLine(string_view line) { - // always added - - } else if (key == "ssrc") { -- auto ssrc = to_integer(value); -+ RTC_UNWRAP_RETHROW_DECL(auto, ssrc, to_integer(value)); - if (!hasSSRC(ssrc)) - mSsrcs.emplace_back(ssrc); - -@@ -1049,14 +1083,15 @@ void Description::Media::parseSdpLine(string_view line) { - mAttributes.emplace_back(attr); - - } else { -- Entry::parseSdpLine(line); -+ RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } - - } else if (match_prefix(line, "b=AS")) { -- mBas = to_integer(line.substr(line.find(':') + 1)); -+ RTC_UNWRAP_RETHROW_VAR(mBas, to_integer(line.substr(line.find(':') + 1))); - } else { -- Entry::parseSdpLine(line); -+ RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } -+ RTC_RET; - } - - Description::Media::RtpMap::RtpMap(int payloadType) { -@@ -1064,24 +1099,31 @@ Description::Media::RtpMap::RtpMap(int payloadType) { - this->clockRate = 0; - } - --int Description::Media::RtpMap::parsePayloadType(string_view mline) { -+RTC_WRAPPED(Description::Media::RtpMap) Description::Media::RtpMap::create(string_view description) { -+ RTC_BEGIN; -+ RtpMap ret = RtpMap(0); -+ RTC_UNWRAP_RETHROW(ret.setDescription(description)); -+ return ret; -+} -+ -+ -+RTC_WRAPPED(int) Description::Media::RtpMap::parsePayloadType(string_view mline) { - size_t p = mline.find(' '); - return to_integer(mline.substr(0, p)); - } - --Description::Media::RtpMap::RtpMap(string_view description) { setDescription(description); } -- --void Description::Media::RtpMap::setDescription(string_view description) { -+RTC_WRAPPED(void) Description::Media::RtpMap::setDescription(string_view description) { -+ RTC_BEGIN; - size_t p = description.find(' '); - if (p == string::npos) -- throw std::invalid_argument("Invalid format description for rtpmap"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid format description for rtpmap"); - -- this->payloadType = to_integer(description.substr(0, p)); -+ RTC_UNWRAP_RETHROW_VAR(this->payloadType, to_integer(description.substr(0, p))); - - string_view line = description.substr(p + 1); - size_t spl = line.find('/'); - if (spl == string::npos) -- throw std::invalid_argument("Invalid format description for rtpmap"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid format description for rtpmap"); - - this->format = line.substr(0, spl); - -@@ -1091,11 +1133,12 @@ void Description::Media::RtpMap::setDescription(string_view description) { - spl = line.find(' '); - } - if (spl == string::npos) -- this->clockRate = to_integer(line); -+ RTC_UNWRAP_RETHROW_VAR(this->clockRate, to_integer(line)); - else { -- this->clockRate = to_integer(line.substr(0, spl)); -+ RTC_UNWRAP_RETHROW_VAR(this->clockRate, (to_integer(line.substr(0, spl)))); - this->encParams = line.substr(spl + 1); - } -+ RTC_RET; - } - - void Description::Media::RtpMap::addFeedback(string fb) { -@@ -1127,7 +1170,8 @@ void Description::Media::RtpMap::removeParameter(const string &str) { - Description::Audio::Audio(string mid, Direction dir) - : Media("audio 9 UDP/TLS/RTP/SAVPF", std::move(mid), dir) {} - --void Description::Audio::addAudioCodec(int payloadType, string codec, optional profile) { -+RTC_WRAPPED(void) Description::Audio::addAudioCodec(int payloadType, string codec, optional profile) { -+ RTC_BEGIN; - if (codec.find('/') == string::npos) { - if (codec == "PCMA" || codec == "PCMU") - codec += "/8000/1"; -@@ -1135,42 +1179,44 @@ void Description::Audio::addAudioCodec(int payloadType, string codec, optional profile) { -- addAudioCodec(payloadType, "opus", profile); -+RTC_WRAPPED(void) Description::Audio::addOpusCodec(int payloadType, optional profile) { -+ return addAudioCodec(payloadType, "opus", profile); - } - --void Description::Audio::addPCMACodec(int payloadType, optional profile) { -- addAudioCodec(payloadType, "PCMA", profile); -+RTC_WRAPPED(void) Description::Audio::addPCMACodec(int payloadType, optional profile) { -+ return addAudioCodec(payloadType, "PCMA", profile); - } - --void Description::Audio::addPCMUCodec(int payloadType, optional profile) { -- addAudioCodec(payloadType, "PCMU", profile); -+RTC_WRAPPED(void) Description::Audio::addPCMUCodec(int payloadType, optional profile) { -+ return addAudioCodec(payloadType, "PCMU", profile); - } - --void Description::Audio::addAacCodec(int payloadType, optional profile) { -+RTC_WRAPPED(void) Description::Audio::addAacCodec(int payloadType, optional profile) { - if (profile) { -- addAudioCodec(payloadType, "MP4A-LATM", profile); -+ return addAudioCodec(payloadType, "MP4A-LATM", profile); - } else { -- addAudioCodec(payloadType, "MP4A-LATM", "cpresent=1"); -+ return addAudioCodec(payloadType, "MP4A-LATM", "cpresent=1"); - } - } - - Description::Video::Video(string mid, Direction dir) - : Media("video 9 UDP/TLS/RTP/SAVPF", std::move(mid), dir) {} - --void Description::Video::addVideoCodec(int payloadType, string codec, optional profile) { -+RTC_WRAPPED(void) Description::Video::addVideoCodec(int payloadType, string codec, optional profile) { -+ RTC_BEGIN; - if (codec.find('/') == string::npos) - codec += "/90000"; - -- RtpMap map(std::to_string(payloadType) + ' ' + codec); -+ RTC_UNWRAP_RETHROW_DECL(RtpMap, map, RtpMap::create(std::to_string(payloadType) + ' ' + codec)); - - map.addFeedback("nack"); - map.addFeedback("nack pli"); -@@ -1194,26 +1240,27 @@ void Description::Video::addVideoCodec(int payloadType, string codec, optional profile) { -- addVideoCodec(payloadType, "H264", profile); -+RTC_WRAPPED(void) Description::Video::addH264Codec(int payloadType, optional profile) { -+ return addVideoCodec(payloadType, "H264", profile); - } - --void Description::Video::addH265Codec(int payloadType, optional profile) { -- addVideoCodec(payloadType, "H265", profile); -+RTC_WRAPPED(void) Description::Video::addH265Codec(int payloadType, optional profile) { -+ return addVideoCodec(payloadType, "H265", profile); - } - --void Description::Video::addVP8Codec(int payloadType, optional profile) { -- addVideoCodec(payloadType, "VP8", profile); -+RTC_WRAPPED(void) Description::Video::addVP8Codec(int payloadType, optional profile) { -+ return addVideoCodec(payloadType, "VP8", profile); - } - --void Description::Video::addVP9Codec(int payloadType, optional profile) { -- addVideoCodec(payloadType, "VP9", profile); -+RTC_WRAPPED(void) Description::Video::addVP9Codec(int payloadType, optional profile) { -+ return addVideoCodec(payloadType, "VP9", profile); - } - --void Description::Video::addAV1Codec(int payloadType, optional profile) { -- addVideoCodec(payloadType, "AV1", profile); -+RTC_WRAPPED(void) Description::Video::addAV1Codec(int payloadType, optional profile) { -+ return addVideoCodec(payloadType, "AV1", profile); - } - - Description::Type Description::stringToType(const string &typeString) { -diff --git a/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp b/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp -index a9e6d0151e..1c8c366b36 100644 ---- a/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp -+++ b/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp -@@ -1,78 +1,95 @@ - #include "rtc/rtc.hpp" - #include "rtc/exception_wrapper_godot.hpp" - --void LibDataChannelExceptionWrapper::close_data_channel(std::shared_ptr p_channel) try { -- if (p_channel) { -- p_channel->close(); -+void LibDataChannelExceptionWrapper::close_data_channel(std::shared_ptr p_channel) { -+ RTC_TRY { -+ if (p_channel) { -+ p_channel->close(); -+ } -+ } RTC_CATCH (...) { - } --} catch (...) { - } - - --void LibDataChannelExceptionWrapper::close_peer_connection(std::shared_ptr p_peer_connection) try { -+void LibDataChannelExceptionWrapper::close_peer_connection(std::shared_ptr p_peer_connection) { -+RTC_TRY { - if (p_peer_connection) { - p_peer_connection->close(); - } --} catch (...) { -+} RTC_CATCH (...) { -+} - } - - --bool LibDataChannelExceptionWrapper::put_packet(std::shared_ptr p_channel, const uint8_t *p_buffer, int32_t p_len, bool p_is_text, std::string &r_error) try { -+bool LibDataChannelExceptionWrapper::put_packet(std::shared_ptr p_channel, const uint8_t *p_buffer, int32_t p_len, bool p_is_text, std::string &r_error) { -+RTC_TRY { - if (p_is_text) { - std::string str((const char *)p_buffer, (size_t)p_len); -- p_channel->send(str); -+ RTC_UNWRAP_CATCH(p_channel->send(str)); - } else { -- p_channel->send(reinterpret_cast(p_buffer), p_len); -+ RTC_UNWRAP_CATCH(p_channel->send(reinterpret_cast(p_buffer), p_len)); - } - return true; --} catch (const std::exception &e) { -- r_error = e.what(); -+} RTC_CATCH (const RTC_EXCEPTION &e) { -+ r_error = e.RTC_WHAT(); - return false; - } -+} - - --std::shared_ptr LibDataChannelExceptionWrapper::create_data_channel(std::shared_ptr p_peer_connection, const char *p_label, rtc::DataChannelInit p_config, std::string &r_error) try { -- return p_peer_connection->createDataChannel(p_label, p_config); --} catch (const std::exception &e) { -- r_error = e.what(); -+std::shared_ptr LibDataChannelExceptionWrapper::create_data_channel(std::shared_ptr p_peer_connection, const char *p_label, rtc::DataChannelInit p_config, std::string &r_error) { -+RTC_TRY { -+ RTC_UNWRAP_CATCH_DECL(std::shared_ptr, ret, p_peer_connection->createDataChannel(p_label, p_config)); -+ return ret; -+} RTC_CATCH (const RTC_EXCEPTION &e) { -+ r_error = e.RTC_WHAT(); - return std::shared_ptr(); - } -+} - --std::shared_ptr LibDataChannelExceptionWrapper::create_peer_connection(const rtc::Configuration &p_config, std::string &r_error) try { -+std::shared_ptr LibDataChannelExceptionWrapper::create_peer_connection(const rtc::Configuration &p_config, std::string &r_error) { -+RTC_TRY { - return std::make_shared(p_config); --} catch (const std::exception &e) { -- r_error = e.what(); -+} RTC_CATCH (const RTC_EXCEPTION &e) { -+ r_error = e.RTC_WHAT(); - return std::shared_ptr(); - } -+} - --bool LibDataChannelExceptionWrapper::create_offer(std::shared_ptr p_peer_connection, std::string &r_error) try { -- p_peer_connection->setLocalDescription(rtc::Description::Type::Offer); -+bool LibDataChannelExceptionWrapper::create_offer(std::shared_ptr p_peer_connection, std::string &r_error) { -+RTC_TRY { -+ RTC_UNWRAP_CATCH(p_peer_connection->setLocalDescription(rtc::Description::Type::Offer)); - return true; --} catch (const std::exception &e) { -- r_error = e.what(); -+} RTC_CATCH (const RTC_EXCEPTION &e) { -+ r_error = e.RTC_WHAT(); - return false; - } -+} - --bool LibDataChannelExceptionWrapper::set_remote_description(std::shared_ptr p_peer_connection, const char *p_type, const char *p_sdp, std::string &r_error) try { -+bool LibDataChannelExceptionWrapper::set_remote_description(std::shared_ptr p_peer_connection, const char *p_type, const char *p_sdp, std::string &r_error) { -+RTC_TRY { - std::string sdp(p_sdp); - std::string type(p_type); -- rtc::Description desc(sdp, type); -- p_peer_connection->setRemoteDescription(desc); -+ RTC_UNWRAP_CATCH_DECL(rtc::Description, desc, rtc::Description::create(sdp, type)); -+ RTC_UNWRAP_CATCH(p_peer_connection->setRemoteDescription(desc)); - // Automatically create the answer. - if (type == "offer") { -- p_peer_connection->setLocalDescription(rtc::Description::Type::Answer); -+ RTC_UNWRAP_CATCH(p_peer_connection->setLocalDescription(rtc::Description::Type::Answer)); - } - return true; --} catch (const std::exception &e) { -- r_error = e.what(); -+} RTC_CATCH (const RTC_EXCEPTION &e) { -+ r_error = e.RTC_WHAT(); - return false; - } -+} - --bool LibDataChannelExceptionWrapper::add_ice_candidate(std::shared_ptr p_peer_connection, const char *p_sdp_mid_name, const char *p_sdp_name, std::string &r_error) try { -- rtc::Candidate candidate(p_sdp_name, p_sdp_mid_name); -- p_peer_connection->addRemoteCandidate(candidate); -+bool LibDataChannelExceptionWrapper::add_ice_candidate(std::shared_ptr p_peer_connection, const char *p_sdp_mid_name, const char *p_sdp_name, std::string &r_error) { -+RTC_TRY { -+ RTC_UNWRAP_CATCH_DECL(rtc::Candidate, candidate, rtc::Candidate::create(p_sdp_name, p_sdp_mid_name)); -+ RTC_UNWRAP_CATCH(p_peer_connection->addRemoteCandidate(candidate)); - return true; --} catch (const std::exception &e) { -- r_error = e.what(); -+} RTC_CATCH (const RTC_EXCEPTION &e) { -+ r_error = e.RTC_WHAT(); - return false; - } -+} -diff --git a/thirdparty/libdatachannel/src/global.cpp b/thirdparty/libdatachannel/src/global.cpp -index 747dd217a2..18b129dde7 100644 ---- a/thirdparty/libdatachannel/src/global.cpp -+++ b/thirdparty/libdatachannel/src/global.cpp -@@ -97,7 +97,9 @@ void InitLogger(LogLevel level, LogCallback callback) { - void Preload() { impl::Init::Instance().preload(); } - std::shared_future Cleanup() { return impl::Init::Instance().cleanup(); } - --void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); } -+RTC_WRAPPED(void) SetSctpSettings(SctpSettings s) { -+ return impl::Init::Instance().setSctpSettings(std::move(s)); -+} - - } // namespace rtc - -diff --git a/thirdparty/libdatachannel/src/impl/certificate.cpp b/thirdparty/libdatachannel/src/impl/certificate.cpp -index eb4c419c86..cd8b715183 100644 ---- a/thirdparty/libdatachannel/src/impl/certificate.cpp -+++ b/thirdparty/libdatachannel/src/impl/certificate.cpp -@@ -48,7 +48,7 @@ Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_ - return Certificate(std::move(creds)); - } - --Certificate Certificate::Generate(CertificateType type, const string &commonName) { -+RTC_WRAPPED(Certificate) Certificate::Generate(CertificateType type, const string &commonName) { - PLOG_DEBUG << "Generating certificate (GnuTLS)"; - - using namespace gnutls; -@@ -75,7 +75,7 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - break; - } - default: -- throw std::invalid_argument("Unknown certificate type"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unknown certificate type"); - } - - using namespace std::chrono; -@@ -153,7 +153,7 @@ string make_fingerprint(mbedtls_x509_crt *crt) { - uint8_t buffer[size]; - std::stringstream fingerprint; - -- mbedtls::check( -+ (void)mbedtls::check( - mbedtls_sha256(crt->raw.p, crt->raw.len, reinterpret_cast(buffer), 0), - "Failed to generate certificate fingerprint"); - -@@ -170,40 +170,42 @@ string make_fingerprint(mbedtls_x509_crt *crt) { - Certificate::Certificate(shared_ptr crt, shared_ptr pk) - : mCrt(crt), mPk(pk), mFingerprint(make_fingerprint(crt.get())) {} - --Certificate Certificate::FromString(string crt_pem, string key_pem) { -+RTC_WRAPPED(Certificate) Certificate::FromString(string crt_pem, string key_pem) { -+ RTC_BEGIN; - PLOG_DEBUG << "Importing certificate from PEM string (MbedTLS)"; - - auto crt = mbedtls::new_x509_crt(); - auto pk = mbedtls::new_pk_context(); - -- mbedtls::check(mbedtls_x509_crt_parse(crt.get(), -+ RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_x509_crt_parse(crt.get(), - reinterpret_cast(crt_pem.c_str()), - crt_pem.length()), -- "Failed to parse certificate"); -- mbedtls::check(mbedtls_pk_parse_key(pk.get(), -+ "Failed to parse certificate")); -+ RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_pk_parse_key(pk.get(), - reinterpret_cast(key_pem.c_str()), - key_pem.size(), NULL, 0, NULL, 0), -- "Failed to parse key"); -+ "Failed to parse key")); - - return Certificate(std::move(crt), std::move(pk)); - } - --Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, -+RTC_WRAPPED(Certificate) Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass) { -+ RTC_BEGIN; - PLOG_DEBUG << "Importing certificate from PEM file (MbedTLS): " << crt_pem_file; - - auto crt = mbedtls::new_x509_crt(); - auto pk = mbedtls::new_pk_context(); - -- mbedtls::check(mbedtls_x509_crt_parse_file(crt.get(), crt_pem_file.c_str()), -- "Failed to parse certificate"); -- mbedtls::check(mbedtls_pk_parse_keyfile(pk.get(), key_pem_file.c_str(), pass.c_str(), 0, NULL), -- "Failed to parse key"); -+ RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_x509_crt_parse_file(crt.get(), crt_pem_file.c_str()), -+ "Failed to parse certificate")); -+ RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_pk_parse_keyfile(pk.get(), key_pem_file.c_str(), pass.c_str(), 0, NULL), -+ "Failed to parse key")); - - return Certificate(std::move(crt), std::move(pk)); - } - --Certificate Certificate::Generate(CertificateType type, const string &commonName) { -+RTC_WRAPPED(Certificate) Certificate::Generate(CertificateType type, const string &commonName) { - PLOG_DEBUG << "Generating certificate (MbedTLS)"; - - mbedtls_entropy_context entropy; -@@ -219,10 +221,10 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - mbedtls_x509write_crt_init(&wcrt); - mbedtls_mpi_init(&serial); - -- try { -- mbedtls::check(mbedtls_ctr_drbg_seed( -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ctr_drbg_seed( - &drbg, mbedtls_entropy_func, &entropy, -- reinterpret_cast(commonName.data()), commonName.size())); -+ reinterpret_cast(commonName.data()), commonName.size()))); - - switch (type) { - // RFC 8827 WebRTC Security Architecture 6.5. Communications Security -@@ -231,47 +233,47 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - case CertificateType::Default: - case CertificateType::Ecdsa: { -- mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))); -- mbedtls::check(mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk.get()), -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)))); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk.get()), - mbedtls_ctr_drbg_random, &drbg), -- "Unable to generate ECDSA P-256 key pair"); -+ "Unable to generate ECDSA P-256 key pair")); - break; - } - case CertificateType::Rsa: { - const unsigned int nbits = 2048; - const int exponent = 65537; - -- mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))); -- mbedtls::check(mbedtls_rsa_gen_key(mbedtls_pk_rsa(*pk.get()), mbedtls_ctr_drbg_random, -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)))); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_rsa_gen_key(mbedtls_pk_rsa(*pk.get()), mbedtls_ctr_drbg_random, - &drbg, nbits, exponent), -- "Unable to generate RSA key pair"); -+ "Unable to generate RSA key pair")); - break; - } - default: -- throw std::invalid_argument("Unknown certificate type"); -+ RTC_THROW_WITHIN(RTC_INVALID_ARGUMENT("Unknown certificate type")); - } - - auto now = std::chrono::system_clock::now(); -- string notBefore = mbedtls::format_time(now - std::chrono::hours(1)); -- string notAfter = mbedtls::format_time(now + std::chrono::hours(24 * 365)); -+ RTC_UNWRAP_CATCH_DECL(string, notBefore, mbedtls::format_time(now - std::chrono::hours(1))); -+ RTC_UNWRAP_CATCH_DECL(string, notAfter, mbedtls::format_time(now + std::chrono::hours(24 * 365))); - - const size_t serialBufferSize = 16; - unsigned char serialBuffer[serialBufferSize]; -- mbedtls::check(mbedtls_ctr_drbg_random(&drbg, serialBuffer, serialBufferSize), -- "Failed to generate certificate"); -- mbedtls::check(mbedtls_mpi_read_binary(&serial, serialBuffer, serialBufferSize), -- "Failed to generate certificate"); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ctr_drbg_random(&drbg, serialBuffer, serialBufferSize), -+ "Failed to generate certificate")); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_mpi_read_binary(&serial, serialBuffer, serialBufferSize), -+ "Failed to generate certificate")); - - std::string name = std::string("O=" + commonName + ",CN=" + commonName); -- mbedtls::check(mbedtls_x509write_crt_set_serial_raw(&wcrt, rand_serial, sizeof(rand_serial)), -- "Failed to generate certificate"); -- mbedtls::check(mbedtls_x509write_crt_set_subject_name(&wcrt, name.c_str()), -- "Failed to generate certificate"); -- mbedtls::check(mbedtls_x509write_crt_set_issuer_name(&wcrt, name.c_str()), -- "Failed to generate certificate"); -- mbedtls::check( -+ -+ uint8_t rand_serial[20]; -+ mbedtls_ctr_drbg_random(&ctr_drbg, rand_serial, sizeof(rand_serial)); -+ -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509write_crt_set_serial_raw(&wcrt, &serial), -+ "Failed to generate certificate")); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509write_crt_set_subject_name(&wcrt, name.c_str()), -+ "Failed to generate certificate")); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509write_crt_set_issuer_name(&wcrt, name.c_str()), -+ "Failed to generate certificate")); -+ RTC_UNWRAP_CATCH(mbedtls::check( - mbedtls_x509write_crt_set_validity(&wcrt, notBefore.c_str(), notAfter.c_str()), -- "Failed to generate certificate"); -+ "Failed to generate certificate")); - - mbedtls_x509write_crt_set_version(&wcrt, MBEDTLS_X509_CRT_VERSION_3); - mbedtls_x509write_crt_set_subject_key(&wcrt, pk.get()); -@@ -285,19 +287,19 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - auto certificateLen = mbedtls_x509write_crt_der( - &wcrt, certificateBuffer, certificateBufferSize, mbedtls_ctr_drbg_random, &drbg); - if (certificateLen <= 0) { -- throw std::runtime_error("Certificate generation failed"); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Certificate generation failed")); - } - -- mbedtls::check(mbedtls_x509_crt_parse_der( -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509_crt_parse_der( - crt.get(), (certificateBuffer + certificateBufferSize - certificateLen), - certificateLen), -- "Failed to generate certificate"); -- } catch (...) { -+ "Failed to generate certificate")); -+ } RTC_CATCH (...) { - mbedtls_entropy_free(&entropy); - mbedtls_ctr_drbg_free(&drbg); - mbedtls_x509write_crt_free(&wcrt); - mbedtls_mpi_free(&serial); -- throw; -+ RTC_RETHROW; - } - - mbedtls_entropy_free(&entropy); -@@ -328,7 +330,7 @@ int dummy_pass_cb(char *buf, int size, int /*rwflag*/, void *u) { - - } // namespace - --Certificate Certificate::FromString(string crt_pem, string key_pem) { -+RTC_WRAPPED(Certificate) Certificate::FromString(string crt_pem, string key_pem) { - PLOG_DEBUG << "Importing certificate from PEM string (OpenSSL)"; - - BIO *bio = BIO_new(BIO_s_mem()); -@@ -336,7 +338,7 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) { - auto x509 = shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free); - BIO_free(bio); - if (!x509) -- throw std::invalid_argument("Unable to import PEM certificate"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM certificate"); - - bio = BIO_new(BIO_s_mem()); - BIO_write(bio, key_pem.data(), int(key_pem.size())); -@@ -344,46 +346,46 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) { - EVP_PKEY_free); - BIO_free(bio); - if (!pkey) -- throw std::invalid_argument("Unable to import PEM key"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM key"); - - return Certificate(x509, pkey); - } - --Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, -+RTC_WRAPPED(Certificate) Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass) { - PLOG_DEBUG << "Importing certificate from PEM file (OpenSSL): " << crt_pem_file; - - BIO *bio = openssl::BIO_new_from_file(crt_pem_file); - if (!bio) -- throw std::invalid_argument("Unable to open PEM certificate file"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unable to open PEM certificate file"); - - auto x509 = shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free); - BIO_free(bio); - if (!x509) -- throw std::invalid_argument("Unable to import PEM certificate from file"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM certificate from file"); - - bio = openssl::BIO_new_from_file(key_pem_file); - if (!bio) -- throw std::invalid_argument("Unable to open PEM key file"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unable to open PEM key file"); - - auto pkey = shared_ptr( - PEM_read_bio_PrivateKey(bio, nullptr, dummy_pass_cb, const_cast(pass.c_str())), - EVP_PKEY_free); - BIO_free(bio); - if (!pkey) -- throw std::invalid_argument("Unable to import PEM key from file"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM key from file"); - - return Certificate(x509, pkey); - } - --Certificate Certificate::Generate(CertificateType type, const string &commonName) { -+RTC_WRAPPED(Certificate) Certificate::Generate(CertificateType type, const string &commonName) { - PLOG_DEBUG << "Generating certificate (OpenSSL)"; - - shared_ptr x509(X509_new(), X509_free); - unique_ptr serial_number(BN_new(), BN_free); - unique_ptr name(X509_NAME_new(), X509_NAME_free); - if (!x509 || !serial_number || !name) -- throw std::runtime_error("Unable to allocate structures for certificate generation"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to allocate structures for certificate generation"); - - shared_ptr pkey; - switch (type) { -@@ -401,7 +403,7 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - unique_ptr ecc( - EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), EC_KEY_free); - if (!pkey || !ecc) -- throw std::runtime_error("Unable to allocate structure for ECDSA P-256 key pair"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to allocate structure for ECDSA P-256 key pair"); - - EC_KEY_set_asn1_flag(ecc.get(), OPENSSL_EC_NAMED_CURVE); // Set ASN1 OID - if (!EC_KEY_generate_key(ecc.get()) || -@@ -409,7 +411,7 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - ecc.release())) // the key will be freed when pkey is freed - #endif - if (!pkey) -- throw std::runtime_error("Unable to generate ECDSA P-256 key pair"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to generate ECDSA P-256 key pair"); - - break; - } -@@ -423,7 +425,7 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - unique_ptr rsa(RSA_new(), RSA_free); - unique_ptr exponent(BN_new(), BN_free); - if (!pkey || !rsa || !exponent) -- throw std::runtime_error("Unable to allocate structures for RSA key pair"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to allocate structures for RSA key pair"); - - const unsigned int e = 65537; // 2^16 + 1 - if (!BN_set_word(exponent.get(), e) || -@@ -432,12 +434,12 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - rsa.release())) // the key will be freed when pkey is freed - #endif - if (!pkey) -- throw std::runtime_error("Unable to generate RSA key pair"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to generate RSA key pair"); - - break; - } - default: -- throw std::invalid_argument("Unknown certificate type"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Unknown certificate type"); - } - - const size_t serialSize = 16; -@@ -445,7 +447,7 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - reinterpret_cast(const_cast(commonName.c_str())); - - if (!X509_set_pubkey(x509.get(), pkey.get())) -- throw std::runtime_error("Unable to set certificate public key"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to set certificate public key"); - - if (!X509_gmtime_adj(X509_getm_notBefore(x509.get()), 3600 * -1) || - !X509_gmtime_adj(X509_getm_notAfter(x509.get()), 3600 * 24 * 365) || -@@ -455,10 +457,10 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName - -1, 0) || - !X509_set_subject_name(x509.get(), name.get()) || - !X509_set_issuer_name(x509.get(), name.get())) -- throw std::runtime_error("Unable to set certificate properties"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to set certificate properties"); - - if (!X509_sign(x509.get(), pkey.get(), EVP_sha256())) -- throw std::runtime_error("Unable to auto-sign certificate"); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to auto-sign certificate"); - - return Certificate(x509, pkey); - } -@@ -470,12 +472,12 @@ std::tuple Certificate::credentials() const { - return {mX509.get(), mPKey.get()}; - } - --string make_fingerprint(X509 *x509) { -+RTC_WRAPPED(string) make_fingerprint(X509 *x509) { - const size_t size = 32; - unsigned char buffer[size]; - unsigned int len = size; - if (!X509_digest(x509, EVP_sha256(), buffer, &len)) -- throw std::runtime_error("X509 fingerprint error"); -+ RTC_THROW RTC_RUNTIME_ERROR("X509 fingerprint error"); - - std::ostringstream oss; - oss << std::hex << std::uppercase << std::setfill('0'); -@@ -492,8 +494,10 @@ string make_fingerprint(X509 *x509) { - // Common for GnuTLS, Mbed TLS, and OpenSSL - - future_certificate_ptr make_certificate(CertificateType type) { -- return ThreadPool::Instance().enqueue([type, token = Init::Instance().token()]() { -- return std::make_shared(Certificate::Generate(type, "libdatachannel")); -+ return ThreadPool::Instance().enqueue([type, token = Init::Instance().token()]() -> RTC_WRAPPED(certificate_ptr) { -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW_DECL(auto, tmp, Certificate::Generate(type, "libdatachannel")); -+ return std::make_shared(tmp); - }); - } - -diff --git a/thirdparty/libdatachannel/src/impl/certificate.hpp b/thirdparty/libdatachannel/src/impl/certificate.hpp -index 800bcd2d9d..c25093a275 100644 ---- a/thirdparty/libdatachannel/src/impl/certificate.hpp -+++ b/thirdparty/libdatachannel/src/impl/certificate.hpp -@@ -20,11 +20,13 @@ - namespace rtc::impl { - - class Certificate { -+ RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(Certificate); -+ Certificate() {} - public: -- static Certificate FromString(string crt_pem, string key_pem); -- static Certificate FromFile(const string &crt_pem_file, const string &key_pem_file, -+ static RTC_WRAPPED(Certificate) FromString(string crt_pem, string key_pem); -+ static RTC_WRAPPED(Certificate) FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass = ""); -- static Certificate Generate(CertificateType type, const string &commonName); -+ static RTC_WRAPPED(Certificate) Generate(CertificateType type, const string &commonName); - - #if USE_GNUTLS - Certificate(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey); -@@ -66,7 +68,7 @@ string make_fingerprint(X509 *x509); - #endif - - using certificate_ptr = shared_ptr; --using future_certificate_ptr = std::shared_future; -+using future_certificate_ptr = std::shared_future; - - future_certificate_ptr make_certificate(CertificateType type = CertificateType::Default); - -diff --git a/thirdparty/libdatachannel/src/impl/channel.cpp b/thirdparty/libdatachannel/src/impl/channel.cpp -index e545f8ede4..061d1cf1ec 100644 ---- a/thirdparty/libdatachannel/src/impl/channel.cpp -+++ b/thirdparty/libdatachannel/src/impl/channel.cpp -@@ -13,36 +13,36 @@ namespace rtc::impl { - - void Channel::triggerOpen() { - mOpenTriggered = true; -- try { -+ RTC_TRY { - openCallback(); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - flushPendingMessages(); - } - - void Channel::triggerClosed() { -- try { -+ RTC_TRY { - closedCallback(); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } - - void Channel::triggerError(string error) { -- try { -+ RTC_TRY { - errorCallback(std::move(error)); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } - - void Channel::triggerAvailable(size_t count) { - if (count == 1) { -- try { -+ RTC_TRY { - availableCallback(); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } - -@@ -53,10 +53,10 @@ void Channel::triggerBufferedAmount(size_t amount) { - size_t previous = bufferedAmount.exchange(amount); - size_t threshold = bufferedAmountLowThreshold.load(); - if (previous > threshold && amount <= threshold) { -- try { -+ RTC_TRY { - bufferedAmountLowCallback(); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } - } -@@ -70,10 +70,10 @@ void Channel::flushPendingMessages() { - if (!next) - break; - -- try { -+ RTC_TRY { - messageCallback(*next); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } - } -diff --git a/thirdparty/libdatachannel/src/impl/datachannel.cpp b/thirdparty/libdatachannel/src/impl/datachannel.cpp -index c1ce337442..46fef55330 100644 ---- a/thirdparty/libdatachannel/src/impl/datachannel.cpp -+++ b/thirdparty/libdatachannel/src/impl/datachannel.cpp -@@ -79,10 +79,10 @@ DataChannel::DataChannel(weak_ptr pc, string label, string proto - - DataChannel::~DataChannel() { - PLOG_VERBOSE << "Destroying DataChannel"; -- try { -+ RTC_TRY { - close(); -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << e.RTC_WHAT(); - } - } - -@@ -148,16 +148,17 @@ size_t DataChannel::maxMessageSize() const { - return pc ? pc->remoteMaxMessageSize() : DEFAULT_MAX_MESSAGE_SIZE; - } - --void DataChannel::assignStream(uint16_t stream) { -+RTC_WRAPPED(void) DataChannel::assignStream(uint16_t stream) { - std::unique_lock lock(mMutex); - - if (mStream.has_value()) -- throw std::logic_error("DataChannel already has a stream assigned"); -+ RTC_THROW RTC_LOGIC_ERROR("DataChannel already has a stream assigned"); - - mStream = stream; -+ RTC_RET; - } - --void DataChannel::open(shared_ptr transport) { -+RTC_WRAPPED(void) DataChannel::open(shared_ptr transport) { - { - std::unique_lock lock(mMutex); - mSctpTransport = transport; -@@ -165,26 +166,28 @@ void DataChannel::open(shared_ptr transport) { - - if (!mIsClosed && !mIsOpen.exchange(true)) - triggerOpen(); -+ RTC_RET; - } - --void DataChannel::processOpenMessage(message_ptr) { -+RTC_WRAPPED(void) DataChannel::processOpenMessage(message_ptr) { - PLOG_WARNING << "Received an open message for a user-negotiated DataChannel, ignoring"; -+ RTC_RET; - } - --bool DataChannel::outgoing(message_ptr message) { -+RTC_WRAPPED(bool) DataChannel::outgoing(message_ptr message) { - shared_ptr transport; - { - std::shared_lock lock(mMutex); - transport = mSctpTransport.lock(); - - if (!transport || mIsClosed) -- throw std::runtime_error("DataChannel is closed"); -+ RTC_THROW RTC_RUNTIME_ERROR("DataChannel is closed"); - - if (!mStream.has_value()) -- throw std::logic_error("DataChannel has no stream assigned"); -+ RTC_THROW RTC_LOGIC_ERROR("DataChannel has no stream assigned"); - - if (message->size() > maxMessageSize()) -- throw std::invalid_argument("Message size exceeds limit"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Message size exceeds limit"); - - // Before the ACK has been received on a DataChannel, all messages must be sent ordered - message->reliability = mIsOpen ? mReliability : nullptr; -@@ -194,9 +197,10 @@ bool DataChannel::outgoing(message_ptr message) { - return transport->send(message); - } - --void DataChannel::incoming(message_ptr message) { -+RTC_WRAPPED(void) DataChannel::incoming(message_ptr message) { -+ RTC_BEGIN; - if (!message || mIsClosed) -- return; -+ RTC_RET; - - switch (message->type) { - case Message::Control: { -@@ -205,7 +209,7 @@ void DataChannel::incoming(message_ptr message) { - auto raw = reinterpret_cast(message->data()); - switch (raw[0]) { - case MESSAGE_OPEN: -- processOpenMessage(message); -+ RTC_UNWRAP_RETHROW(processOpenMessage(message)); - break; - case MESSAGE_ACK: - if (!mIsOpen.exchange(true)) { -@@ -230,6 +234,7 @@ void DataChannel::incoming(message_ptr message) { - // Ignore - break; - } -+ RTC_RET; - } - - OutgoingDataChannel::OutgoingDataChannel(weak_ptr pc, string label, string protocol, -@@ -238,12 +243,13 @@ OutgoingDataChannel::OutgoingDataChannel(weak_ptr pc, string lab - - OutgoingDataChannel::~OutgoingDataChannel() {} - --void OutgoingDataChannel::open(shared_ptr transport) { -+RTC_WRAPPED(void) OutgoingDataChannel::open(shared_ptr transport) { -+ RTC_BEGIN; - std::unique_lock lock(mMutex); - mSctpTransport = transport; - - if (!mStream.has_value()) -- throw std::runtime_error("DataChannel has no stream assigned"); -+ RTC_THROW RTC_RUNTIME_ERROR("DataChannel has no stream assigned"); - - uint8_t channelType; - uint32_t reliabilityParameter; -@@ -283,11 +289,13 @@ void OutgoingDataChannel::open(shared_ptr transport) { - - lock.unlock(); - -- transport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream.value())); -+ RTC_UNWRAP_RETHROW(transport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream.value()))); -+ RTC_RET; - } - --void OutgoingDataChannel::processOpenMessage(message_ptr) { -+RTC_WRAPPED(void) OutgoingDataChannel::processOpenMessage(message_ptr) { - PLOG_WARNING << "Received an open message for a locally-created DataChannel, ignoring"; -+ RTC_RET; - } - - IncomingDataChannel::IncomingDataChannel(weak_ptr pc, -@@ -299,21 +307,23 @@ IncomingDataChannel::IncomingDataChannel(weak_ptr pc, - - IncomingDataChannel::~IncomingDataChannel() {} - --void IncomingDataChannel::open(shared_ptr) { -+RTC_WRAPPED(void) IncomingDataChannel::open(shared_ptr) { - // Ignore -+ RTC_RET; - } - --void IncomingDataChannel::processOpenMessage(message_ptr message) { -+RTC_WRAPPED(void) IncomingDataChannel::processOpenMessage(message_ptr message) { -+ RTC_BEGIN; - std::unique_lock lock(mMutex); - auto transport = mSctpTransport.lock(); - if (!transport) -- throw std::logic_error("DataChannel has no transport"); -+ RTC_THROW RTC_LOGIC_ERROR("DataChannel has no transport"); - - if (!mStream.has_value()) -- throw std::logic_error("DataChannel has no stream assigned"); -+ RTC_THROW RTC_LOGIC_ERROR("DataChannel has no stream assigned"); - - if (message->size() < sizeof(OpenMessage)) -- throw std::invalid_argument("DataChannel open message too small"); -+ RTC_THROW RTC_INVALID_ARGUMENT("DataChannel open message too small"); - - OpenMessage open = *reinterpret_cast(message->data()); - open.priority = ntohs(open.priority); -@@ -322,7 +332,7 @@ void IncomingDataChannel::processOpenMessage(message_ptr message) { - open.protocolLength = ntohs(open.protocolLength); - - if (message->size() < sizeof(OpenMessage) + size_t(open.labelLength + open.protocolLength)) -- throw std::invalid_argument("DataChannel open message truncated"); -+ RTC_THROW RTC_INVALID_ARGUMENT("DataChannel open message truncated"); - - auto end = reinterpret_cast(message->data() + sizeof(OpenMessage)); - mLabel.assign(end, open.labelLength); -@@ -349,10 +359,11 @@ void IncomingDataChannel::processOpenMessage(message_ptr message) { - auto &ack = *reinterpret_cast(buffer.data()); - ack.type = MESSAGE_ACK; - -- transport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream.value())); -+ RTC_UNWRAP_RETHROW(transport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream.value()))); - - if (!mIsOpen.exchange(true)) - triggerOpen(); -+ RTC_RET; - } - - } // namespace rtc::impl -diff --git a/thirdparty/libdatachannel/src/impl/datachannel.hpp b/thirdparty/libdatachannel/src/impl/datachannel.hpp -index cd501bff2f..0080bb2454 100644 ---- a/thirdparty/libdatachannel/src/impl/datachannel.hpp -+++ b/thirdparty/libdatachannel/src/impl/datachannel.hpp -@@ -33,8 +33,8 @@ struct DataChannel : Channel, std::enable_shared_from_this { - - void close(); - void remoteClose(); -- bool outgoing(message_ptr message); -- void incoming(message_ptr message); -+ RTC_WRAPPED(bool) outgoing(message_ptr message); -+ RTC_WRAPPED(void) incoming(message_ptr message); - - optional receive() override; - optional peek() override; -@@ -49,9 +49,9 @@ struct DataChannel : Channel, std::enable_shared_from_this { - bool isClosed(void) const; - size_t maxMessageSize() const; - -- virtual void assignStream(uint16_t stream); -- virtual void open(shared_ptr transport); -- virtual void processOpenMessage(message_ptr); -+ virtual RTC_WRAPPED(void) assignStream(uint16_t stream); -+ virtual RTC_WRAPPED(void) open(shared_ptr transport); -+ virtual RTC_WRAPPED(void) processOpenMessage(message_ptr); - - protected: - const weak_ptr mPeerConnection; -@@ -76,16 +76,16 @@ struct OutgoingDataChannel final : public DataChannel { - Reliability reliability); - ~OutgoingDataChannel(); - -- void open(shared_ptr transport) override; -- void processOpenMessage(message_ptr message) override; -+ RTC_WRAPPED(void) open(shared_ptr transport) override; -+ RTC_WRAPPED(void) processOpenMessage(message_ptr message) override; - }; - - struct IncomingDataChannel final : public DataChannel { - IncomingDataChannel(weak_ptr pc, weak_ptr transport); - ~IncomingDataChannel(); - -- void open(shared_ptr transport) override; -- void processOpenMessage(message_ptr message) override; -+ RTC_WRAPPED(void) open(shared_ptr transport) override; -+ RTC_WRAPPED(void) processOpenMessage(message_ptr message) override; - }; - - } // namespace rtc::impl -diff --git a/thirdparty/libdatachannel/src/impl/dtlstransport.cpp b/thirdparty/libdatachannel/src/impl/dtlstransport.cpp -index 3779c5671e..07453a9d72 100644 ---- a/thirdparty/libdatachannel/src/impl/dtlstransport.cpp -+++ b/thirdparty/libdatachannel/src/impl/dtlstransport.cpp -@@ -46,17 +46,19 @@ void DtlsTransport::Init() { - - void DtlsTransport::Cleanup() { gnutls_global_deinit(); } - --DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate, -+DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate - optional mtu, verifier_callback verifierCallback, - state_callback stateChangeCallback) - : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate), - mVerifierCallback(std::move(verifierCallback)), - mIsClient(lower->role() == Description::Role::Active) { -+} - -+RTC_WRAPPED(void) DtlsTransport::construct() { - PLOG_DEBUG << "Initializing DTLS transport (GnuTLS)"; - - if (!mCertificate) -- throw std::invalid_argument("DTLS certificate is null"); -+ RTC_THROW RTC_INVALID_ARGUMENT("DTLS certificate is null"); - - gnutls_certificate_credentials_t creds = mCertificate->credentials(); - gnutls_certificate_set_verify_function(creds, CertificateCallback); -@@ -65,7 +67,7 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - GNUTLS_DATAGRAM | GNUTLS_NONBLOCK | (mIsClient ? GNUTLS_CLIENT : GNUTLS_SERVER); - gnutls::check(gnutls_init(&mSession, flags)); - -- try { -+ RTC_TRY { - // RFC 8261: SCTP performs segmentation and reassembly based on the path MTU. - // Therefore, the DTLS layer MUST NOT use any compression algorithm. - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 -@@ -92,14 +94,15 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - gnutls_transport_set_pull_function(mSession, ReadCallback); - gnutls_transport_set_pull_timeout_function(mSession, TimeoutCallback); - -- } catch (...) { -+ } RTC_CATCH (...) { - gnutls_deinit(mSession); -- throw; -+ RTC_RETHROW; - } - - // Set recommended medium-priority DSCP value for handshake - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability -+ RTC_RET; - } - - DtlsTransport::~DtlsTransport() { -@@ -109,7 +112,7 @@ DtlsTransport::~DtlsTransport() { - gnutls_deinit(mSession); - } - --void DtlsTransport::start() { -+RTC_WRAPPED(void) DtlsTransport::start() { - PLOG_DEBUG << "Starting DTLS transport"; - registerIncoming(); - changeState(State::Connecting); -@@ -185,7 +188,7 @@ void DtlsTransport::doRecv() { - if (state() != State::Connecting && state() != State::Connected) - return; - -- try { -+ RTC_TRY { - const size_t bufferSize = 4096; - char buffer[bufferSize]; - -@@ -206,7 +209,7 @@ void DtlsTransport::doRecv() { - } - - if (ret == GNUTLS_E_LARGE_PACKET) { -- throw std::runtime_error("MTU is too low"); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("MTU is too low")); - } - - } while (!gnutls::check(ret, "Handshake failed")); // Re-call on non-fatal error -@@ -257,8 +260,8 @@ void DtlsTransport::doRecv() { - } - } - } -- } catch (const std::exception &e) { -- PLOG_ERROR << "DTLS recv: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << "DTLS recv: " << e.RTC_WHAT(); - } - - gnutls_bye(mSession, GNUTLS_SHUT_WR); -@@ -275,7 +278,7 @@ void DtlsTransport::doRecv() { - - int DtlsTransport::CertificateCallback(gnutls_session_t session) { - DtlsTransport *t = static_cast(gnutls_session_get_ptr(session)); -- try { -+ RTC_TRY { - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { - return GNUTLS_E_CERTIFICATE_ERROR; - } -@@ -300,15 +303,15 @@ int DtlsTransport::CertificateCallback(gnutls_session_t session) { - bool success = t->mVerifierCallback(fingerprint); - return success ? GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR; - -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - return GNUTLS_E_CERTIFICATE_ERROR; - } - } - - ssize_t DtlsTransport::WriteCallback(gnutls_transport_ptr_t ptr, const void *data, size_t len) { - DtlsTransport *t = static_cast(ptr); -- try { -+ RTC_TRY { - if (len > 0) { - auto b = reinterpret_cast(data); - t->outgoing(make_message(b, b + len)); -@@ -316,8 +319,8 @@ ssize_t DtlsTransport::WriteCallback(gnutls_transport_ptr_t ptr, const void *dat - gnutls_transport_set_errno(t->mSession, 0); - return ssize_t(len); - -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - gnutls_transport_set_errno(t->mSession, ECONNRESET); - return -1; - } -@@ -325,7 +328,7 @@ ssize_t DtlsTransport::WriteCallback(gnutls_transport_ptr_t ptr, const void *dat - - ssize_t DtlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_t maxlen) { - DtlsTransport *t = static_cast(ptr); -- try { -+ RTC_TRY { - while (t->mIncomingQueue.running()) { - auto next = t->mIncomingQueue.pop(); - if (!next) { -@@ -347,8 +350,8 @@ ssize_t DtlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size - gnutls_transport_set_errno(t->mSession, 0); - return 0; - -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - gnutls_transport_set_errno(t->mSession, ECONNRESET); - return -1; - } -@@ -356,11 +359,11 @@ ssize_t DtlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size - - int DtlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int /* ms */) { - DtlsTransport *t = static_cast(ptr); -- try { -+ RTC_TRY { - return !t->mIncomingQueue.empty() ? 1 : 0; - -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - return 1; - } - } -@@ -376,14 +379,16 @@ int DtlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int /* m - DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate, - optional mtu, verifier_callback verifierCallback, - state_callback stateChangeCallback) -- : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate), -+ : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), - mVerifierCallback(std::move(verifierCallback)), - mIsClient(lower->role() == Description::Role::Active) { -+} - -+RTC_WRAPPED(void) DtlsTransport::construct() { - PLOG_DEBUG << "Initializing DTLS transport (MbedTLS)"; - - if (!mCertificate) -- throw std::invalid_argument("DTLS certificate is null"); -+ RTC_THROW RTC_INVALID_ARGUMENT("DTLS certificate is null"); - - mbedtls_entropy_init(&mEntropy); - mbedtls_ctr_drbg_init(&mDrbg); -@@ -391,14 +396,14 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - mbedtls_ssl_config_init(&mConf); - mbedtls_ctr_drbg_set_prediction_resistance(&mDrbg, MBEDTLS_CTR_DRBG_PR_ON); - -- try { -- mbedtls::check(mbedtls_ctr_drbg_seed(&mDrbg, mbedtls_entropy_func, &mEntropy, NULL, 0), -- "Failed creating Mbed TLS Context"); -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ctr_drbg_seed(&mDrbg, mbedtls_entropy_func, &mEntropy, NULL, 0), -+ "Failed creating Mbed TLS Context")); - -- mbedtls::check(mbedtls_ssl_config_defaults( -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ssl_config_defaults( - &mConf, mIsClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT), -- "Failed creating Mbed TLS Context"); -+ "Failed creating Mbed TLS Context")); - - mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_verify(&mConf, DtlsTransport::CertificateCallback, this); -@@ -406,29 +411,30 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mDrbg); - - auto [crt, pk] = mCertificate->credentials(); -- mbedtls::check(mbedtls_ssl_conf_own_cert(&mConf, crt.get(), pk.get()), -- "Failed creating Mbed TLS Context"); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ssl_conf_own_cert(&mConf, crt.get(), pk.get()), -+ "Failed creating Mbed TLS Context")); - - mbedtls_ssl_conf_dtls_cookies(&mConf, NULL, NULL, NULL); - // GODOT Deleted // mbedtls_ssl_conf_dtls_srtp_protection_profiles(&mConf, srtpSupportedProtectionProfiles); - -- mbedtls::check(mbedtls_ssl_setup(&mSsl, &mConf), "Failed creating Mbed TLS Context"); -+ RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ssl_setup(&mSsl, &mConf), "Failed creating Mbed TLS Context")); - - mbedtls_ssl_set_export_keys_cb(&mSsl, DtlsTransport::ExportKeysCallback, this); - mbedtls_ssl_set_bio(&mSsl, this, WriteCallback, ReadCallback, NULL); - mbedtls_ssl_set_timer_cb(&mSsl, this, SetTimerCallback, GetTimerCallback); - -- } catch (...) { -+ } RTC_CATCH (...) { - mbedtls_entropy_free(&mEntropy); - mbedtls_ctr_drbg_free(&mDrbg); - mbedtls_ssl_free(&mSsl); - mbedtls_ssl_config_free(&mConf); -- throw; -+ RTC_RETHROW; - } - - // Set recommended medium-priority DSCP value for handshake - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability -+ RTC_RET; - } - - DtlsTransport::~DtlsTransport() { -@@ -449,7 +455,7 @@ void DtlsTransport::Cleanup() { - // Nothing to do - } - --void DtlsTransport::start() { -+RTC_WRAPPED(void) DtlsTransport::start() { - PLOG_DEBUG << "Starting DTLS transport"; - registerIncoming(); - changeState(State::Connecting); -@@ -462,6 +468,7 @@ void DtlsTransport::start() { - } - - enqueueRecv(); // to initiate the handshake -+ RTC_RET; - } - - void DtlsTransport::stop() { -@@ -471,7 +478,7 @@ void DtlsTransport::stop() { - enqueueRecv(); - } - --bool DtlsTransport::send(message_ptr message) { -+RTC_WRAPPED(bool) DtlsTransport::send(message_ptr message) { - if (!message || state() != State::Connected) - return false; - -@@ -486,7 +493,12 @@ bool DtlsTransport::send(message_ptr message) { - mCurrentDscp = message->dscp; - ret = mbedtls_ssl_write(&mSsl, reinterpret_cast(message->data()), - message->size()); -- } while (!mbedtls::check(ret)); -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW_DECL(bool, cond, mbedtls::check(ret)); -+ if (cond) { -+ break; -+ } -+ } while (1); - - return mOutgoingResult; - } -@@ -502,10 +514,11 @@ void DtlsTransport::incoming(message_ptr message) { - enqueueRecv(); - } - --bool DtlsTransport::outgoing(message_ptr message) { -+RTC_WRAPPED(bool) DtlsTransport::outgoing(message_ptr message) { -+ RTC_BEGIN; - message->dscp = mCurrentDscp; - -- bool result = Transport::outgoing(std::move(message)); -+ RTC_UNWRAP_RETHROW_DECL(bool, result, Transport::outgoing(std::move(message))); - mOutgoingResult = result; - return result; - } -@@ -526,7 +539,7 @@ void DtlsTransport::doRecv() { - if (state() != State::Connecting && state() != State::Connected) - return; - -- try { -+ RTC_TRY { - const size_t bufferSize = 4096; - char buffer[bufferSize]; - -@@ -548,7 +561,8 @@ void DtlsTransport::doRecv() { - return; - } - -- if (mbedtls::check(ret, "Handshake failed")) { -+ RTC_UNWRAP_CATCH_DECL(bool, res, mbedtls::check(ret, "Handshake failed")); -+ if (res) { - // RFC 8261: DTLS MUST support sending messages larger than the current path MTU - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 - { -@@ -582,7 +596,8 @@ void DtlsTransport::doRecv() { - break; - } - -- if (mbedtls::check(ret)) { -+ RTC_UNWRAP_CATCH_DECL(bool, res, mbedtls::check(ret, "Handshake failed")); -+ if (res) { - if (ret == 0) { - PLOG_DEBUG << "DTLS connection terminated"; - break; -@@ -592,8 +607,8 @@ void DtlsTransport::doRecv() { - } - } - } -- } catch (const std::exception &e) { -- PLOG_ERROR << "DTLS recv: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << "DTLS recv: " << e.RTC_WHAT(); - } - - if (state() == State::Connected) { -@@ -629,22 +644,22 @@ void DtlsTransport::ExportKeysCallback(void *ctx, mbedtls_ssl_key_export_type /* - - int DtlsTransport::WriteCallback(void *ctx, const unsigned char *buf, size_t len) { - auto *t = static_cast(ctx); -- try { -+ RTC_TRY { - if (len > 0) { - auto b = reinterpret_cast(buf); -- t->outgoing(make_message(b, b + len)); -+ RTC_UNWRAP_CATCH(t->outgoing(make_message(b, b + len))); - } - return int(len); - -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - return MBEDTLS_ERR_SSL_INTERNAL_ERROR; - } - } - - int DtlsTransport::ReadCallback(void *ctx, unsigned char *buf, size_t len) { - auto *t = static_cast(ctx); -- try { -+ RTC_TRY { - while (t->mIncomingQueue.running()) { - auto next = t->mIncomingQueue.pop(); - if (!next) { -@@ -663,8 +678,8 @@ int DtlsTransport::ReadCallback(void *ctx, unsigned char *buf, size_t len) { - // Closed - return 0; - -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - return MBEDTLS_ERR_SSL_INTERNAL_ERROR; - ; - } -@@ -709,7 +724,7 @@ void DtlsTransport::Init() { - if (!BioMethods) { - BioMethods = BIO_meth_new(BIO_TYPE_BIO, "DTLS writer"); - if (!BioMethods) -- throw std::runtime_error("Failed to create BIO methods for DTLS writer"); -+ PLOG_ERROR << "Failed to create BIO methods for DTLS writer"; - BIO_meth_set_create(BioMethods, BioMethodNew); - BIO_meth_set_destroy(BioMethods, BioMethodFree); - BIO_meth_set_write(BioMethods, BioMethodWrite); -@@ -730,15 +745,18 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate), - mVerifierCallback(std::move(verifierCallback)), - mIsClient(lower->role() == Description::Role::Active) { -+} -+ -+RTC_WRAPPED(void) DtlsTransport::construct() { - PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)"; - - if (!mCertificate) -- throw std::invalid_argument("DTLS certificate is null"); -+ RTC_THROW RTC_INVALID_ARGUMENT("DTLS certificate is null"); - -- try { -+ RTC_TRY { - mCtx = SSL_CTX_new(DTLS_method()); - if (!mCtx) -- throw std::runtime_error("Failed to create SSL context"); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to create SSL context")); - - // RFC 8261: SCTP performs segmentation and reassembly based on the path MTU. - // Therefore, the DTLS layer MUST NOT use any compression algorithm. -@@ -776,7 +794,7 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - - mSsl = SSL_new(mCtx); - if (!mSsl) -- throw std::runtime_error("Failed to create SSL instance"); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to create SSL instance")); - - SSL_set_ex_data(mSsl, TransportExIndex, this); - -@@ -788,7 +806,7 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - mInBio = BIO_new(BIO_s_mem()); - mOutBio = BIO_new(BioMethods); - if (!mInBio || !mOutBio) -- throw std::runtime_error("Failed to create BIO"); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to create BIO")); - - BIO_set_mem_eof_return(mInBio, BIO_EOF); - BIO_set_data(mOutBio, this); -@@ -801,21 +819,22 @@ DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr cer - if (SSL_set_tlsext_use_srtp( - mSsl, "SRTP_AEAD_AES_256_GCM:SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80")) { - if (SSL_set_tlsext_use_srtp(mSsl, "SRTP_AES128_CM_SHA1_80")) -- throw std::runtime_error("Failed to set SRTP profile: " + -- openssl::error_string(ERR_get_error())); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to set SRTP profile: " + -+ openssl::error_string(ERR_get_error()))); - } - -- } catch (...) { -+ } RTC_CATCH (...) { - if (mSsl) - SSL_free(mSsl); - if (mCtx) - SSL_CTX_free(mCtx); -- throw; -+ RTC_RETHROW; - } - - // Set recommended medium-priority DSCP value for handshake - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability -+ RTC_RET; - } - - DtlsTransport::~DtlsTransport() { -@@ -912,7 +931,7 @@ void DtlsTransport::doRecv() { - if (state() != State::Connecting && state() != State::Connected) - return; - -- try { -+ RTC_TRY { - const size_t bufferSize = 4096; - byte buffer[bufferSize]; - -@@ -977,8 +996,8 @@ void DtlsTransport::doRecv() { - std::lock_guard lock(mSslMutex); - SSL_shutdown(mSsl); - -- } catch (const std::exception &e) { -- PLOG_ERROR << "DTLS recv: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << "DTLS recv: " << e.RTC_WHAT(); - } - - if (state() == State::Connected) { -@@ -991,13 +1010,13 @@ void DtlsTransport::doRecv() { - } - } - --void DtlsTransport::handleTimeout() { -+RTC_WRAPPED(void) DtlsTransport::handleTimeout() { - std::lock_guard lock(mSslMutex); - - // Warning: This function breaks the usual return value convention - int ret = DTLSv1_handle_timeout(mSsl); - if (ret < 0) { -- throw std::runtime_error("Handshake timeout"); // write BIO can't fail -+ RTC_THROW RTC_RUNTIME_ERROR("Handshake timeout"); // write BIO can't fail - } else if (ret > 0) { - LOG_VERBOSE << "DTLS retransmit done"; - } -@@ -1010,7 +1029,7 @@ void DtlsTransport::handleTimeout() { - // recommended 1s so this allows for 5 retransmissions and fails after - // roughly 30s. - if (timeout > 30s) -- throw std::runtime_error("Handshake timeout"); -+ RTC_THROW RTC_RUNTIME_ERROR("Handshake timeout"); - - LOG_VERBOSE << "DTLS retransmit timeout is " << timeout.count() << "ms"; - ThreadPool::Instance().schedule(timeout, [weak_this = weak_from_this()]() { -diff --git a/thirdparty/libdatachannel/src/impl/dtlstransport.hpp b/thirdparty/libdatachannel/src/impl/dtlstransport.hpp -index d84b312e80..3e70de01b7 100644 ---- a/thirdparty/libdatachannel/src/impl/dtlstransport.hpp -+++ b/thirdparty/libdatachannel/src/impl/dtlstransport.hpp -@@ -35,15 +35,16 @@ public: - verifier_callback verifierCallback, state_callback stateChangeCallback); - ~DtlsTransport(); - -- virtual void start() override; -+ RTC_WRAPPED(void) construct(); -+ virtual RTC_WRAPPED(void) start() override; - virtual void stop() override; -- virtual bool send(message_ptr message) override; // false if dropped -+ virtual RTC_WRAPPED(bool) send(message_ptr message) override; // false if dropped - - bool isClient() const { return mIsClient; } - - protected: - virtual void incoming(message_ptr message) override; -- virtual bool outgoing(message_ptr message) override; -+ virtual RTC_WRAPPED(bool) outgoing(message_ptr message) override; - virtual bool demuxMessage(message_ptr message); - virtual void postHandshake(); - -diff --git a/thirdparty/libdatachannel/src/impl/icetransport.cpp b/thirdparty/libdatachannel/src/impl/icetransport.cpp -index 3a19e92ac6..d9f725998b 100644 ---- a/thirdparty/libdatachannel/src/impl/icetransport.cpp -+++ b/thirdparty/libdatachannel/src/impl/icetransport.cpp -@@ -45,7 +45,7 @@ void IceTransport::Cleanup() { - // Dummy - } - --IceTransport::IceTransport(const Configuration &config, candidate_callback candidateCallback, -+IceTransport::IceTransport(candidate_callback candidateCallback, - state_callback stateChangeCallback, - gathering_state_callback gatheringStateChangeCallback) - : Transport(nullptr, std::move(stateChangeCallback)), mRole(Description::Role::ActPass), -@@ -53,7 +53,9 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi - mCandidateCallback(std::move(candidateCallback)), - mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)), - mAgent(nullptr, nullptr) { -+} - -+RTC_WRAPPED(void) IceTransport::construct(const Configuration &config) { - PLOG_DEBUG << "Initializing ICE transport (libjuice)"; - - juice_log_level_t level; -@@ -152,7 +154,8 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi - // Create agent - mAgent = decltype(mAgent)(juice_create(&jconfig), juice_destroy); - if (!mAgent) -- throw std::runtime_error("Failed to create the ICE agent"); -+ RTC_THROW RTC_RUNTIME_ERROR("Failed to create the ICE agent"); -+ RTC_RET; - } - - IceTransport::~IceTransport() { -@@ -162,27 +165,28 @@ IceTransport::~IceTransport() { - - Description::Role IceTransport::role() const { return mRole; } - --Description IceTransport::getLocalDescription(Description::Type type) const { -+RTC_WRAPPED(Description) IceTransport::getLocalDescription(Description::Type type) const { -+ RTC_BEGIN; - char sdp[JUICE_MAX_SDP_STRING_LEN]; - if (juice_get_local_description(mAgent.get(), sdp, JUICE_MAX_SDP_STRING_LEN) < 0) -- throw std::runtime_error("Failed to generate local SDP"); -+ RTC_THROW RTC_RUNTIME_ERROR("Failed to generate local SDP"); - - // RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of - // setup:actpass. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 -- Description desc(string(sdp), type, -- type == Description::Type::Offer ? Description::Role::ActPass : mRole); -+ RTC_UNWRAP_RETHROW_DECL(Description, desc, Description::create(string(sdp), type, -+ type == Description::Type::Offer ? Description::Role::ActPass : mRole)); - desc.addIceOption("trickle"); - return desc; - } - --void IceTransport::setRemoteDescription(const Description &description) { -+RTC_WRAPPED(void) IceTransport::setRemoteDescription(const Description &description) { - // RFC 5763: The answerer MUST use either a setup attribute value of setup:active or - // setup:passive. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 - if (description.type() == Description::Type::Answer && - description.role() == Description::Role::ActPass) -- throw std::invalid_argument("Illegal role actpass in remote answer description"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Illegal role actpass in remote answer description"); - - // RFC 5763: Note that if the answerer uses setup:passive, then the DTLS handshake - // will not begin until the answerer is received, which adds additional latency. -@@ -193,31 +197,33 @@ void IceTransport::setRemoteDescription(const Description &description) { - : Description::Role::Active; - - if (mRole == description.role()) -- throw std::invalid_argument("Incompatible roles with remote description"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Incompatible roles with remote description"); - - mMid = description.bundleMid(); - if (juice_set_remote_description(mAgent.get(), - description.generateApplicationSdp("\r\n").c_str()) < 0) -- throw std::invalid_argument("Invalid ICE settings from remote SDP"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid ICE settings from remote SDP"); -+ RTC_RET; - } - - bool IceTransport::addRemoteCandidate(const Candidate &candidate) { -- // Don't try to pass unresolved candidates for more safety -+ // Don't RTC_TRY to pass unresolved candidates for more safety - if (!candidate.isResolved()) - return false; - - return juice_add_remote_candidate(mAgent.get(), string(candidate).c_str()) >= 0; - } - --void IceTransport::gatherLocalCandidates(string mid) { -+RTC_WRAPPED(void) IceTransport::gatherLocalCandidates(string mid) { - mMid = std::move(mid); - - // Change state now as candidates calls can be synchronous - changeGatheringState(GatheringState::InProgress); - - if (juice_gather_candidates(mAgent.get()) < 0) { -- throw std::runtime_error("Failed to gather local ICE candidates"); -+ RTC_THROW RTC_RUNTIME_ERROR("Failed to gather local ICE candidates"); - } -+ RTC_RET; - } - - optional IceTransport::getLocalAddress() const { -@@ -237,17 +243,18 @@ optional IceTransport::getRemoteAddress() const { - return nullopt; - } - --bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) { -+RTC_WRAPPED(bool) IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) { -+ RTC_BEGIN; - char sdpLocal[JUICE_MAX_CANDIDATE_SDP_STRING_LEN]; - char sdpRemote[JUICE_MAX_CANDIDATE_SDP_STRING_LEN]; - if (juice_get_selected_candidates(mAgent.get(), sdpLocal, JUICE_MAX_CANDIDATE_SDP_STRING_LEN, - sdpRemote, JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0) { - if (local) { -- *local = Candidate(sdpLocal, mMid); -+ RTC_UNWRAP_RETHROW_VAR(*local, Candidate::create(sdpLocal, mMid)); - local->resolve(Candidate::ResolveMode::Simple); - } - if (remote) { -- *remote = Candidate(sdpRemote, mMid); -+ RTC_UNWRAP_RETHROW_VAR(*remote, Candidate::create(sdpRemote, mMid)); - remote->resolve(Candidate::ResolveMode::Simple); - } - return true; -@@ -255,7 +262,7 @@ bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) - return false; - } - --bool IceTransport::send(message_ptr message) { -+RTC_WRAPPED(bool) IceTransport::send(message_ptr message) { - auto s = state(); - if (!message || (s != State::Connected && s != State::Completed)) - return false; -@@ -264,7 +271,7 @@ bool IceTransport::send(message_ptr message) { - return outgoing(message); - } - --bool IceTransport::outgoing(message_ptr message) { -+RTC_WRAPPED(bool) IceTransport::outgoing(message_ptr message) { - // Explicit Congestion Notification takes the least-significant 2 bits of the DS field - int ds = int(message->dscp << 2); - return juice_send_diffserv(mAgent.get(), reinterpret_cast(message->data()), -@@ -296,47 +303,50 @@ void IceTransport::processStateChange(unsigned int state) { - }; - } - --void IceTransport::processCandidate(const string &candidate) { -- mCandidateCallback(Candidate(candidate, mMid)); -+RTC_WRAPPED(void) IceTransport::processCandidate(const string &candidate) { -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW_DECL(Candidate, tmp, Candidate::create(candidate, mMid)); -+ RTC_UNWRAP_RETHROW(mCandidateCallback(tmp)); -+ RTC_RET; - } - - void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); } - - void IceTransport::StateChangeCallback(juice_agent_t *, juice_state_t state, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); -- try { -+ RTC_TRY { - iceTransport->processStateChange(static_cast(state)); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void IceTransport::CandidateCallback(juice_agent_t *, const char *sdp, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); -- try { -- iceTransport->processCandidate(sdp); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(iceTransport->processCandidate(sdp)); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void IceTransport::GatheringDoneCallback(juice_agent_t *, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); -- try { -+ RTC_TRY { - iceTransport->processGatheringDone(); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void IceTransport::RecvCallback(juice_agent_t *, const char *data, size_t size, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); -- try { -+ RTC_TRY { - PLOG_VERBOSE << "Incoming size=" << size; - auto b = reinterpret_cast(data); - iceTransport->incoming(make_message(b, b + size)); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - -@@ -376,7 +386,7 @@ void IceTransport::Init() { - - MainLoop = decltype(MainLoop)(g_main_loop_new(nullptr, FALSE), g_main_loop_unref); - if (!MainLoop) -- throw std::runtime_error("Failed to create the main loop"); -+ PLOG_ERROR << "Failed to create the main loop"; - - MainLoopThread = std::thread(g_main_loop_run, MainLoop.get()); - } -@@ -396,7 +406,7 @@ static void closeNiceAgent(NiceAgent *niceAgent) { - nice_agent_close_async(niceAgent, closeNiceAgentCallback, nullptr); - } - --IceTransport::IceTransport(const Configuration &config, candidate_callback candidateCallback, -+IceTransport::IceTransport(candidate_callback candidateCallback, - state_callback stateChangeCallback, - gathering_state_callback gatheringStateChangeCallback) - : Transport(nullptr, std::move(stateChangeCallback)), mRole(Description::Role::ActPass), -@@ -404,11 +414,13 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi - mCandidateCallback(std::move(candidateCallback)), - mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)), - mNiceAgent(nullptr, nullptr), mOutgoingDscp(0) { -+} - -+RTC_WRAPPED(void) IceTransport::construct(const Configuration &config) { - PLOG_DEBUG << "Initializing ICE transport (libnice)"; - - if (!MainLoop) -- throw std::logic_error("Main loop for nice agent is not created"); -+ RTC_THROW RTC_LOGIC_ERROR("Main loop for nice agent is not created"); - - // RFC 8445: The nomination process that was referred to as "aggressive nomination" in RFC 5245 - // has been deprecated in this specification. -@@ -425,11 +437,11 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi - closeNiceAgent); - - if (!mNiceAgent) -- throw std::runtime_error("Failed to create the nice agent"); -+ RTC_THROW RTC_RUNTIME_ERROR("Failed to create the nice agent"); - - mStreamId = nice_agent_add_stream(mNiceAgent.get(), 1); - if (!mStreamId) -- throw std::runtime_error("Failed to add a stream"); -+ RTC_THROW RTC_RUNTIME_ERROR("Failed to add a stream"); - - g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", TRUE, nullptr); // decided later - g_object_set(G_OBJECT(mNiceAgent.get()), "ice-udp", TRUE, nullptr); -@@ -617,7 +629,7 @@ IceTransport::~IceTransport() { - - Description::Role IceTransport::role() const { return mRole; } - --Description IceTransport::getLocalDescription(Description::Type type) const { -+RTC_WRAPPED(Description) IceTransport::getLocalDescription(Description::Type type) const { - // RFC 8445: The initiating agent that started the ICE processing MUST take the controlling - // role, and the other MUST take the controlled role. - g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", -@@ -635,13 +647,13 @@ Description IceTransport::getLocalDescription(Description::Type type) const { - return desc; - } - --void IceTransport::setRemoteDescription(const Description &description) { -+RTC_WRAPPED(void) IceTransport::setRemoteDescription(const Description &description) { - // RFC 5763: The answerer MUST use either a setup attribute value of setup:active or - // setup:passive. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 - if (description.type() == Description::Type::Answer && - description.role() == Description::Role::ActPass) -- throw std::invalid_argument("Illegal role actpass in remote answer description"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Illegal role actpass in remote answer description"); - - // RFC 5763: Note that if the answerer uses setup:passive, then the DTLS handshake - // will not begin until the answerer is received, which adds additional latency. -@@ -652,7 +664,8 @@ void IceTransport::setRemoteDescription(const Description &description) { - : Description::Role::Active; - - if (mRole == description.role()) -- throw std::invalid_argument("Incompatible roles with remote description"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Incompatible roles with remote description"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Incompatible roles with remote description"); - - mMid = description.bundleMid(); - mTrickleTimeout = !description.ended() ? 30s : 0s; -@@ -660,11 +673,11 @@ void IceTransport::setRemoteDescription(const Description &description) { - // Warning: libnice expects "\n" as end of line - if (nice_agent_parse_remote_sdp(mNiceAgent.get(), - description.generateApplicationSdp("\n").c_str()) < 0) -- throw std::invalid_argument("Invalid ICE settings from remote SDP"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Invalid ICE settings from remote SDP"); - } - - bool IceTransport::addRemoteCandidate(const Candidate &candidate) { -- // Don't try to pass unresolved candidates to libnice for more safety -+ // Don't RTC_TRY to pass unresolved candidates to libnice for more safety - if (!candidate.isResolved()) - return false; - -@@ -685,14 +698,14 @@ bool IceTransport::addRemoteCandidate(const Candidate &candidate) { - return ret > 0; - } - --void IceTransport::gatherLocalCandidates(string mid) { -+RTC_WRAPPED(void) IceTransport::gatherLocalCandidates(string mid) { - mMid = std::move(mid); - - // Change state now as candidates calls can be synchronous - changeGatheringState(GatheringState::InProgress); - - if (!nice_agent_gather_candidates(mNiceAgent.get(), mStreamId)) { -- throw std::runtime_error("Failed to gather local ICE candidates"); -+ RTC_THROW RTC_RUNTIME_ERROR("Failed to gather local ICE candidates"); - } - } - -@@ -797,10 +810,10 @@ void IceTransport::CandidateCallback(NiceAgent *agent, NiceCandidate *candidate, - gpointer userData) { - auto iceTransport = static_cast(userData); - gchar *cand = nice_agent_generate_local_candidate_sdp(agent, candidate); -- try { -+ RTC_TRY { - iceTransport->processCandidate(cand); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - g_free(cand); - } -@@ -808,41 +821,41 @@ void IceTransport::CandidateCallback(NiceAgent *agent, NiceCandidate *candidate, - void IceTransport::GatheringDoneCallback(NiceAgent * /*agent*/, guint /*streamId*/, - gpointer userData) { - auto iceTransport = static_cast(userData); -- try { -+ RTC_TRY { - iceTransport->processGatheringDone(); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void IceTransport::StateChangeCallback(NiceAgent * /*agent*/, guint /*streamId*/, - guint /*componentId*/, guint state, gpointer userData) { - auto iceTransport = static_cast(userData); -- try { -+ RTC_TRY { - iceTransport->processStateChange(state); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void IceTransport::RecvCallback(NiceAgent * /*agent*/, guint /*streamId*/, guint /*componentId*/, - guint len, gchar *buf, gpointer userData) { - auto iceTransport = static_cast(userData); -- try { -+ RTC_TRY { - PLOG_VERBOSE << "Incoming size=" << len; - auto b = reinterpret_cast(buf); - iceTransport->incoming(make_message(b, b + len)); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - gboolean IceTransport::TimeoutCallback(gpointer userData) { - auto iceTransport = static_cast(userData); -- try { -+ RTC_TRY { - iceTransport->processTimeout(); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - return FALSE; - } -diff --git a/thirdparty/libdatachannel/src/impl/icetransport.hpp b/thirdparty/libdatachannel/src/impl/icetransport.hpp -index 7724e2bdad..8f590cc415 100644 ---- a/thirdparty/libdatachannel/src/impl/icetransport.hpp -+++ b/thirdparty/libdatachannel/src/impl/icetransport.hpp -@@ -37,35 +37,36 @@ public: - - enum class GatheringState { New = 0, InProgress = 1, Complete = 2 }; - -- using candidate_callback = std::function; -+ using candidate_callback = std::function; - using gathering_state_callback = std::function; - -- IceTransport(const Configuration &config, candidate_callback candidateCallback, -+ IceTransport(candidate_callback candidateCallback, - state_callback stateChangeCallback, - gathering_state_callback gatheringStateChangeCallback); - ~IceTransport(); - -+ RTC_WRAPPED(void) construct(const Configuration &config); - Description::Role role() const; - GatheringState gatheringState() const; -- Description getLocalDescription(Description::Type type) const; -- void setRemoteDescription(const Description &description); -+ RTC_WRAPPED(Description) getLocalDescription(Description::Type type) const; -+ RTC_WRAPPED(void) setRemoteDescription(const Description &description); - bool addRemoteCandidate(const Candidate &candidate); -- void gatherLocalCandidates(string mid); -+ RTC_WRAPPED(void) gatherLocalCandidates(string mid); - - optional getLocalAddress() const; - optional getRemoteAddress() const; - -- bool send(message_ptr message) override; // false if dropped -+ RTC_WRAPPED(bool) send(message_ptr message) override; // false if dropped - -- bool getSelectedCandidatePair(Candidate *local, Candidate *remote); -+ RTC_WRAPPED(bool) getSelectedCandidatePair(Candidate *local, Candidate *remote); - - private: -- bool outgoing(message_ptr message) override; -+ RTC_WRAPPED(bool) outgoing(message_ptr message) override; - - void changeGatheringState(GatheringState state); - - void processStateChange(unsigned int state); -- void processCandidate(const string &candidate); -+ RTC_WRAPPED(void) processCandidate(const string &candidate); - void processGatheringDone(); - void processTimeout(); - -diff --git a/thirdparty/libdatachannel/src/impl/init.cpp b/thirdparty/libdatachannel/src/impl/init.cpp -index aad72dd386..609bb536b6 100644 ---- a/thirdparty/libdatachannel/src/impl/init.cpp -+++ b/thirdparty/libdatachannel/src/impl/init.cpp -@@ -44,11 +44,11 @@ struct Init::TokenPayload { - std::thread t( - [](std::promise promise) { - utils::this_thread::set_name("RTC cleanup"); -- try { -+ RTC_TRY { - Init::Instance().doCleanup(); - promise.set_value(); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - promise.set_exception(std::make_exception_ptr(e)); - } - }, -@@ -96,12 +96,14 @@ std::shared_future Init::cleanup() { - return mCleanupFuture; - } - --void Init::setSctpSettings(SctpSettings s) { -+RTC_WRAPPED(void) Init::setSctpSettings(SctpSettings s) { -+ RTC_BEGIN; - std::lock_guard lock(mMutex); - if (mGlobal) -- SctpTransport::SetSettings(s); -+ RTC_UNWRAP_RETHROW(SctpTransport::SetSettings(s)); - - mCurrentSctpSettings = std::move(s); // store for next init -+ RTC_RET; - } - - void Init::doInit() { -@@ -115,7 +117,7 @@ void Init::doInit() { - #ifdef _WIN32 - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData)) -- throw std::runtime_error("WSAStartup failed, error=" + std::to_string(WSAGetLastError())); -+ PLOG_ERROR << ("WSAStartup failed, error=" + std::to_string(WSAGetLastError())); - #endif - - int concurrency = std::thread::hardware_concurrency(); -@@ -136,7 +138,11 @@ void Init::doInit() { - #endif - - SctpTransport::Init(); -- SctpTransport::SetSettings(mCurrentSctpSettings); -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(SctpTransport::SetSettings(mCurrentSctpSettings)); -+ } RTC_CATCH(RTC_EXCEPTION e) { -+ PLOG_ERROR << e.RTC_WHAT(); -+ } - DtlsTransport::Init(); - #if RTC_ENABLE_WEBSOCKET - TlsTransport::Init(); -diff --git a/thirdparty/libdatachannel/src/impl/init.hpp b/thirdparty/libdatachannel/src/impl/init.hpp -index cd42711ba9..17419713f3 100644 ---- a/thirdparty/libdatachannel/src/impl/init.hpp -+++ b/thirdparty/libdatachannel/src/impl/init.hpp -@@ -32,7 +32,7 @@ public: - init_token token(); - void preload(); - std::shared_future cleanup(); -- void setSctpSettings(SctpSettings s); -+ RTC_WRAPPED(void) setSctpSettings(SctpSettings s); - - private: - Init(); -diff --git a/thirdparty/libdatachannel/src/impl/peerconnection.cpp b/thirdparty/libdatachannel/src/impl/peerconnection.cpp -index 3bd9f9fcc4..4bfd7fba54 100644 ---- a/thirdparty/libdatachannel/src/impl/peerconnection.cpp -+++ b/thirdparty/libdatachannel/src/impl/peerconnection.cpp -@@ -49,11 +49,11 @@ PeerConnection::PeerConnection(Configuration config_) - PLOG_VERBOSE << "Creating PeerConnection"; - - if (config.portRangeEnd && config.portRangeBegin > config.portRangeEnd) -- throw std::invalid_argument("Invalid port range"); -+ PLOG_ERROR << "Invalid port range"; - - if (config.mtu) { - if (*config.mtu < 576) // Min MTU for IPv4 -- throw std::invalid_argument("Invalid MTU value"); -+ PLOG_ERROR << "Invalid MTU value"; - - if (*config.mtu > 1500) { // Standard Ethernet - PLOG_WARNING << "MTU set to " << *config.mtu; -@@ -121,13 +121,13 @@ size_t PeerConnection::remoteMaxMessageSize() const { - - // Helper for PeerConnection::initXTransport methods: start and emplace the transport - template --shared_ptr emplaceTransport(PeerConnection *pc, shared_ptr *member, shared_ptr transport) { -+static RTC_WRAPPED(shared_ptr) emplaceTransport(PeerConnection *pc, shared_ptr *member, shared_ptr transport) { - std::atomic_store(member, transport); -- try { -- transport->start(); -- } catch (...) { -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(transport->start()); -+ } RTC_CATCH (...) { - std::atomic_store(member, decltype(transport)(nullptr)); -- throw; -+ RTC_RETHROW; - } - - if (pc->closing.load() || pc->state.load() == PeerConnection::State::Closed) { -@@ -139,15 +139,17 @@ shared_ptr emplaceTransport(PeerConnection *pc, shared_ptr *member, shared - return transport; - } - --shared_ptr PeerConnection::initIceTransport() { -- try { -+RTC_WRAPPED(shared_ptr) PeerConnection::initIceTransport() { -+ RTC_TRY { - if (auto transport = std::atomic_load(&mIceTransport)) - return transport; - - PLOG_VERBOSE << "Starting ICE transport"; - - auto transport = std::make_shared( -- config, weak_bind(&PeerConnection::processLocalCandidate, this, _1), -+ [this, weak_this = weak_from_this()](Candidate candidate) -> RTC_WRAPPED(void) { -+ return PeerConnection::processLocalCandidate(candidate); -+ }, - [this, weak_this = weak_from_this()](IceTransport::State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) -@@ -159,7 +161,10 @@ shared_ptr PeerConnection::initIceTransport() { - break; - case IceTransport::State::Connected: - changeIceState(IceState::Connected); -- initDtlsTransport(); -+ { RTC_TRY { -+ RTC_UNWRAP_CATCH(initDtlsTransport()); -+ } RTC_CATCH(...) { -+ } } - break; - case IceTransport::State::Completed: - changeIceState(IceState::Completed); -@@ -178,6 +183,7 @@ shared_ptr PeerConnection::initIceTransport() { - // Ignore - break; - } -+ return; - }, - [this, weak_this = weak_from_this()](IceTransport::GatheringState gatheringState) { - auto shared_this = weak_this.lock(); -@@ -196,18 +202,19 @@ shared_ptr PeerConnection::initIceTransport() { - break; - } - }); -+ RTC_UNWRAP_CATCH(transport->construct(config)); - - return emplaceTransport(this, &mIceTransport, std::move(transport)); - -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << e.RTC_WHAT(); - changeState(State::Failed); -- throw std::runtime_error("ICE transport initialization failed"); -+ RTC_THROW RTC_RUNTIME_ERROR("ICE transport initialization failed"); - } - } - --shared_ptr PeerConnection::initDtlsTransport() { -- try { -+RTC_WRAPPED(shared_ptr) PeerConnection::initDtlsTransport() { -+ RTC_TRY { - if (auto transport = std::atomic_load(&mDtlsTransport)) - return transport; - -@@ -215,21 +222,25 @@ shared_ptr PeerConnection::initDtlsTransport() { - - auto lower = std::atomic_load(&mIceTransport); - if (!lower) -- throw std::logic_error("No underlying ICE transport for DTLS transport"); -+ RTC_THROW RTC_LOGIC_ERROR("No underlying ICE transport for DTLS transport"); - -- auto certificate = mCertificate.get(); -+ RTC_UNWRAP_CATCH_DECL(certificate_ptr, certificate, mCertificate.get()); - auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1); - auto dtlsStateChangeCallback = -- [this, weak_this = weak_from_this()](DtlsTransport::State transportState) { -+ [this, weak_this = weak_from_this()](DtlsTransport::State transportState) -> void { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - - switch (transportState) { - case DtlsTransport::State::Connected: -- if (auto remote = remoteDescription(); remote && remote->hasApplication()) -- initSctpTransport(); -- else -+ if (auto remote = remoteDescription(); remote && remote->hasApplication()) { -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(initSctpTransport()); -+ } RTC_CATCH(RTC_EXCEPTION e) { -+ PLOG_ERROR << e.RTC_WHAT(); -+ } -+ } else - changeState(State::Connected); - - #if RTC_ENABLE_MEDIA -@@ -248,6 +259,7 @@ shared_ptr PeerConnection::initDtlsTransport() { - // Ignore - break; - } -+ return; - }; - - shared_ptr transport; -@@ -269,19 +281,20 @@ shared_ptr PeerConnection::initDtlsTransport() { - // DTLS only - transport = std::make_shared(lower, certificate, config.mtu, - verifierCallback, dtlsStateChangeCallback); -+ RTC_UNWRAP_CATCH(transport->construct()); - } - - return emplaceTransport(this, &mDtlsTransport, std::move(transport)); - -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << e.RTC_WHAT(); - changeState(State::Failed); -- throw std::runtime_error("DTLS transport initialization failed"); -+ RTC_THROW RTC_RUNTIME_ERROR("DTLS transport initialization failed"); - } - } - --shared_ptr PeerConnection::initSctpTransport() { -- try { -+RTC_WRAPPED(shared_ptr) PeerConnection::initSctpTransport() { -+ RTC_TRY { - if (auto transport = std::atomic_load(&mSctpTransport)) - return transport; - -@@ -289,15 +302,15 @@ shared_ptr PeerConnection::initSctpTransport() { - - auto lower = std::atomic_load(&mDtlsTransport); - if (!lower) -- throw std::logic_error("No underlying DTLS transport for SCTP transport"); -+ RTC_THROW RTC_LOGIC_ERROR("No underlying DTLS transport for SCTP transport"); - - auto local = localDescription(); - if (!local || !local->application()) -- throw std::logic_error("Starting SCTP transport without local application description"); -+ RTC_THROW RTC_LOGIC_ERROR("Starting SCTP transport without local application description"); - - auto remote = remoteDescription(); - if (!remote || !remote->application()) -- throw std::logic_error( -+ RTC_THROW RTC_LOGIC_ERROR( - "Starting SCTP transport without remote application description"); - - SctpTransport::Ports ports = {}; -@@ -305,7 +318,17 @@ shared_ptr PeerConnection::initSctpTransport() { - ports.remote = remote->application()->sctpPort().value_or(DEFAULT_SCTP_PORT); - - auto transport = std::make_shared( -- lower, config, std::move(ports), weak_bind(&PeerConnection::forwardMessage, this, _1), -+ lower, std::move(ports), -+ [this, weak_this = weak_from_this()](message_ptr message) { -+ auto shared_this = weak_this.lock(); -+ if (!shared_this) -+ return; -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(shared_this->forwardMessage(message)); -+ } RTC_CATCH(RTC_EXCEPTION e) { -+ PLOG_WARNING << e.RTC_WHAT(); // FIXME -+ } -+ }, - weak_bind(&PeerConnection::forwardBufferedAmount, this, _1, _2), - [this, weak_this = weak_from_this()](SctpTransport::State transportState) { - auto shared_this = weak_this.lock(); -@@ -315,7 +338,10 @@ shared_ptr PeerConnection::initSctpTransport() { - switch (transportState) { - case SctpTransport::State::Connected: - changeState(State::Connected); -- assignDataChannels(); -+ { RTC_TRY { -+ RTC_UNWRAP_CATCH(assignDataChannels()); -+ } RTC_CATCH(...) { -+ } } - mProcessor.enqueue(&PeerConnection::openDataChannels, shared_from_this()); - break; - case SctpTransport::State::Failed: -@@ -331,13 +357,13 @@ shared_ptr PeerConnection::initSctpTransport() { - break; - } - }); -- -+ RTC_UNWRAP_CATCH(transport->construct(config)); - return emplaceTransport(this, &mSctpTransport, std::move(transport)); - -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << e.RTC_WHAT(); - changeState(State::Failed); -- throw std::runtime_error("SCTP transport initialization failed"); -+ RTC_THROW RTC_RUNTIME_ERROR("SCTP transport initialization failed"); - } - } - -@@ -434,16 +460,17 @@ bool PeerConnection::checkFingerprint(const std::string &fingerprint) const { - return false; - } - --void PeerConnection::forwardMessage(message_ptr message) { -+RTC_WRAPPED(void) PeerConnection::forwardMessage(message_ptr message) { -+ RTC_BEGIN; - if (!message) { - remoteCloseDataChannels(); -- return; -+ RTC_RET; - } - - auto iceTransport = std::atomic_load(&mIceTransport); - auto sctpTransport = std::atomic_load(&mSctpTransport); - if (!iceTransport || !sctpTransport) -- return; -+ RTC_RET; - - const uint16_t stream = uint16_t(message->stream); - auto [channel, found] = findDataChannel(stream); -@@ -457,7 +484,7 @@ void PeerConnection::forwardMessage(message_ptr message) { - else - sctpTransport->closeStream(message->stream); - -- return; -+ RTC_RET; - } - - const uint16_t remoteParity = (iceTransport->role() == Description::Role::Active) ? 1 : 0; -@@ -465,11 +492,11 @@ void PeerConnection::forwardMessage(message_ptr message) { - // The odd/even rule is violated, the receiver must close the DataChannel - PLOG_WARNING << "Got open message violating the odd/even rule on stream " << stream; - sctpTransport->closeStream(message->stream); -- return; -+ RTC_RET; - } - - channel = std::make_shared(weak_from_this(), sctpTransport); -- channel->assignStream(stream); -+ RTC_UNWRAP_RETHROW(channel->assignStream(stream)); - channel->openCallback = - weak_bind(&PeerConnection::triggerDataChannel, this, weak_ptr{channel}); - -@@ -477,12 +504,12 @@ void PeerConnection::forwardMessage(message_ptr message) { - mDataChannels.emplace(stream, channel); - } else if (!found) { - if (message->type == Message::Reset) -- return; // ignore -+ RTC_RET; // ignore - - // Invalid, close the DataChannel - PLOG_WARNING << "Got unexpected message on stream " << stream; - sctpTransport->closeStream(message->stream); -- return; -+ RTC_RET; - } - - if (message->type == Message::Reset) { -@@ -492,11 +519,12 @@ void PeerConnection::forwardMessage(message_ptr message) { - - if (channel) { - // Forward the message -- channel->incoming(message); -+ RTC_UNWRAP_RETHROW(channel->incoming(message)); - } else { - // DataChannel was destroyed, ignore - PLOG_DEBUG << "Ignored message on stream " << stream << ", DataChannel is destroyed"; - } -+ RTC_RET; - } - - void PeerConnection::forwardMedia(message_ptr message) { -@@ -597,7 +625,8 @@ void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) { - channel->triggerBufferedAmount(amount); - } - --shared_ptr PeerConnection::emplaceDataChannel(string label, DataChannelInit init) { -+RTC_WRAPPED(shared_ptr) PeerConnection::emplaceDataChannel(string label, DataChannelInit init) { -+ RTC_BEGIN; - std::unique_lock lock(mDataChannelsMutex); // we are going to emplace - - // If the DataChannel is user-negotiated, do not negotiate it in-band -@@ -613,9 +642,9 @@ shared_ptr PeerConnection::emplaceDataChannel(string label, DataCha - if (init.id) { - uint16_t stream = *init.id; - if (stream > maxDataChannelStream()) -- throw std::invalid_argument("DataChannel stream id is too high"); -+ RTC_THROW RTC_INVALID_ARGUMENT("DataChannel stream id is too high"); - -- channel->assignStream(stream); -+ RTC_UNWRAP_RETHROW(channel->assignStream(stream)); - mDataChannels.emplace(std::make_pair(stream, channel)); - - } else { -@@ -627,8 +656,8 @@ shared_ptr PeerConnection::emplaceDataChannel(string label, DataCha - // If SCTP is connected, assign and open now - auto sctpTransport = std::atomic_load(&mSctpTransport); - if (sctpTransport && sctpTransport->state() == SctpTransport::State::Connected) { -- assignDataChannels(); -- channel->open(sctpTransport); -+ RTC_UNWRAP_RETHROW(assignDataChannels()); -+ RTC_UNWRAP_RETHROW(channel->open(sctpTransport)); - } - - return channel; -@@ -652,12 +681,13 @@ uint16_t PeerConnection::maxDataChannelStream() const { - return sctpTransport ? sctpTransport->maxStream() : (MAX_SCTP_STREAMS_COUNT - 1); - } - --void PeerConnection::assignDataChannels() { -+RTC_WRAPPED(void) PeerConnection::assignDataChannels() { -+ RTC_BEGIN; - std::unique_lock lock(mDataChannelsMutex); // we are going to emplace - - auto iceTransport = std::atomic_load(&mIceTransport); - if (!iceTransport) -- throw std::logic_error("Attempted to assign DataChannels without ICE transport"); -+ RTC_THROW RTC_LOGIC_ERROR("Attempted to assign DataChannels without ICE transport"); - - const uint16_t maxStream = maxDataChannelStream(); - for (auto it = mUnassignedDataChannels.begin(); it != mUnassignedDataChannels.end(); ++it) { -@@ -673,7 +703,7 @@ void PeerConnection::assignDataChannels() { - uint16_t stream = (iceTransport->role() == Description::Role::Active) ? 0 : 1; - while (true) { - if (stream > maxStream) -- throw std::runtime_error("Too many DataChannels"); -+ RTC_THROW RTC_RUNTIME_ERROR("Too many DataChannels"); - - if (mDataChannels.find(stream) == mDataChannels.end()) - break; -@@ -683,15 +713,16 @@ void PeerConnection::assignDataChannels() { - - PLOG_DEBUG << "Assigning stream " << stream << " to DataChannel"; - -- channel->assignStream(stream); -+ RTC_UNWRAP_RETHROW(channel->assignStream(stream)); - mDataChannels.emplace(std::make_pair(stream, channel)); - } - - mUnassignedDataChannels.clear(); -+ RTC_RET; - } - - void PeerConnection::iterateDataChannels( -- std::function channel)> func) { -+ std::function channel)> func) { - std::vector> locked; - { - std::shared_lock lock(mDataChannelsMutex); // read-only -@@ -707,10 +738,10 @@ void PeerConnection::iterateDataChannels( - } - - for (auto &channel : locked) { -- try { -- func(std::move(channel)); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(func(std::move(channel))); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - } -@@ -719,16 +750,17 @@ void PeerConnection::openDataChannels() { - if (auto transport = std::atomic_load(&mSctpTransport)) - iterateDataChannels([&](shared_ptr channel) { - if (!channel->isOpen()) -- channel->open(transport); -+ return channel->open(transport); -+ RTC_RET; - }); - } - - void PeerConnection::closeDataChannels() { -- iterateDataChannels([&](shared_ptr channel) { channel->close(); }); -+ iterateDataChannels([&](shared_ptr channel) { channel->close(); RTC_RET; }); - } - - void PeerConnection::remoteCloseDataChannels() { -- iterateDataChannels([&](shared_ptr channel) { channel->remoteClose(); }); -+ iterateDataChannels([&](shared_ptr channel) { channel->remoteClose(); RTC_RET; }); - } - - #if RTC_ENABLE_MEDIA -@@ -761,10 +793,10 @@ void PeerConnection::iterateTracks(std::function track)> - for (auto it = mTrackLines.begin(); it != mTrackLines.end(); ++it) { - auto track = it->lock(); - if (track && !track->isClosed()) { -- try { -+ RTC_TRY { - func(std::move(track)); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - } -@@ -798,21 +830,23 @@ void PeerConnection::closeTracks() { - } - #endif - --void PeerConnection::validateRemoteDescription(const Description &description) { -+RTC_WRAPPED(void) PeerConnection::validateRemoteDescription(const Description &description) { -+ RTC_BEGIN; - if (!description.iceUfrag()) -- throw std::invalid_argument("Remote description has no ICE user fragment"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no ICE user fragment"); - - if (!description.icePwd()) -- throw std::invalid_argument("Remote description has no ICE password"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no ICE password"); - - if (!description.fingerprint()) -- throw std::invalid_argument("Remote description has no valid fingerprint"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no valid fingerprint"); - - if (description.mediaCount() == 0) -- throw std::invalid_argument("Remote description has no media line"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no media line"); - - int activeMediaCount = 0; -- for (unsigned int i = 0; i < description.mediaCount(); ++i) -+ for (unsigned int i = 0; i < description.mediaCount(); ++i) { -+ RTC_UNWRAP_RETHROW_DECL(auto, media, description.media(i)); - std::visit(rtc::overloaded{[&](const Description::Application *application) { - if (!application->isRemoved()) - ++activeMediaCount; -@@ -822,20 +856,23 @@ void PeerConnection::validateRemoteDescription(const Description &description) { - media->direction() != Description::Direction::Inactive) - ++activeMediaCount; - }}, -- description.media(i)); -+ media); -+ } - - if (activeMediaCount == 0) -- throw std::invalid_argument("Remote description has no active media"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no active media"); - - if (auto local = localDescription(); local && local->iceUfrag() && local->icePwd()) - if (*description.iceUfrag() == *local->iceUfrag() && - *description.icePwd() == *local->icePwd()) -- throw std::logic_error("Got the local description as remote description"); -+ RTC_THROW RTC_LOGIC_ERROR("Got the local description as remote description"); - - PLOG_VERBOSE << "Remote description looks valid"; -+ RTC_RET; - } - --void PeerConnection::processLocalDescription(Description description) { -+RTC_WRAPPED(void) PeerConnection::processLocalDescription(Description description) { -+ RTC_BEGIN; - const uint16_t localSctpPort = DEFAULT_SCTP_PORT; - const size_t localMaxMessageSize = - config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE); -@@ -845,7 +882,8 @@ void PeerConnection::processLocalDescription(Description description) { - - if (auto remote = remoteDescription()) { - // Reciprocate remote description -- for (unsigned int i = 0; i < remote->mediaCount(); ++i) -+ for (unsigned int i = 0; i < remote->mediaCount(); ++i) { -+ RTC_UNWRAP_RETHROW_DECL(auto, remote_media, remote->media(i)); - std::visit( // reciprocate each media - rtc::overloaded{ - [&](Description::Application *remoteApp) { -@@ -926,7 +964,8 @@ void PeerConnection::processLocalDescription(Description description) { - #endif - }, - }, -- remote->media(i)); -+ remote_media); -+ } - - // We need to update the SSRC cache for newly-created incoming tracks - updateTrackSsrcCache(*remote); -@@ -975,16 +1014,17 @@ void PeerConnection::processLocalDescription(Description description) { - // There might be no media at this point if the user created a Track, deleted it, - // then called setLocalDescription(). - if (description.mediaCount() == 0) -- throw std::runtime_error("No DataChannel or Track to negotiate"); -+ RTC_THROW RTC_RUNTIME_ERROR("No DataChannel or Track to negotiate"); - } - - // Set local fingerprint (wait for certificate if necessary) -- description.setFingerprint(mCertificate.get()->fingerprint()); -+ RTC_UNWRAP_RETHROW_DECL(certificate_ptr, certificate, mCertificate.get()); -+ RTC_UNWRAP_RETHROW(description.setFingerprint(certificate->fingerprint())); - - PLOG_VERBOSE << "Issuing local description: " << description; - - if (description.mediaCount() == 0) -- throw std::logic_error("Local description has no media line"); -+ RTC_THROW RTC_LOGIC_ERROR("Local description has no media line"); - - updateTrackSsrcCache(description); - -@@ -1011,17 +1051,18 @@ void PeerConnection::processLocalDescription(Description description) { - dtlsTransport && dtlsTransport->state() == Transport::State::Connected) - mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); - #endif -+ RTC_RET; - } - --void PeerConnection::processLocalCandidate(Candidate candidate) { -+RTC_WRAPPED(void) PeerConnection::processLocalCandidate(Candidate candidate) { - std::lock_guard lock(mLocalDescriptionMutex); - if (!mLocalDescription) -- throw std::logic_error("Got a local candidate without local description"); -+ RTC_THROW RTC_LOGIC_ERROR("Got a local candidate without local description"); - - if (config.iceTransportPolicy == TransportPolicy::Relay && - candidate.type() != Candidate::Type::Relayed) { - PLOG_VERBOSE << "Not issuing local candidate because of transport policy: " << candidate; -- return; -+ RTC_RET; - } - - PLOG_VERBOSE << "Issuing local candidate: " << candidate; -@@ -1031,9 +1072,11 @@ void PeerConnection::processLocalCandidate(Candidate candidate) { - - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &localCandidateCallback, std::move(candidate)); -+ RTC_RET; - } - --void PeerConnection::processRemoteDescription(Description description) { -+RTC_WRAPPED(void) PeerConnection::processRemoteDescription(Description description) { -+ RTC_BEGIN; - // Update the SSRC cache for existing tracks - updateTrackSsrcCache(description); - -@@ -1054,27 +1097,28 @@ void PeerConnection::processRemoteDescription(Description description) { - auto sctpTransport = std::atomic_load(&mSctpTransport); - if (!sctpTransport && dtlsTransport && - dtlsTransport->state() == Transport::State::Connected) -- initSctpTransport(); -+ RTC_UNWRAP_RETHROW(initSctpTransport()); - } else { - mProcessor.enqueue(&PeerConnection::remoteCloseDataChannels, shared_from_this()); - } -+ RTC_RET; - } - --void PeerConnection::processRemoteCandidate(Candidate candidate) { -+RTC_WRAPPED(void) PeerConnection::processRemoteCandidate(Candidate candidate) { - auto iceTransport = std::atomic_load(&mIceTransport); - { - // Set as remote candidate - std::lock_guard lock(mRemoteDescriptionMutex); - if (!mRemoteDescription) -- throw std::logic_error("Got a remote candidate without remote description"); -+ RTC_THROW RTC_LOGIC_ERROR("Got a remote candidate without remote description"); - - if (!iceTransport) -- throw std::logic_error("Got a remote candidate without ICE transport"); -+ RTC_THROW RTC_LOGIC_ERROR("Got a remote candidate without ICE transport"); - - candidate.hintMid(mRemoteDescription->bundleMid()); - - if (mRemoteDescription->hasCandidate(candidate)) -- return; // already in description, ignore -+ RTC_RET; // already in description, ignore - - candidate.resolve(Candidate::ResolveMode::Simple); - mRemoteDescription->addCandidate(candidate); -@@ -1096,6 +1140,7 @@ void PeerConnection::processRemoteCandidate(Candidate candidate) { - t.detach(); - } - } -+ RTC_RET; - } - - string PeerConnection::localBundleMid() const { -@@ -1145,10 +1190,10 @@ void PeerConnection::triggerPendingDataChannels() { - - auto impl = std::move(*next); - -- try { -+ RTC_TRY { - dataChannelCallback(std::make_shared(impl)); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - - impl->triggerOpen(); -@@ -1164,10 +1209,10 @@ void PeerConnection::triggerPendingTracks() { - - auto impl = std::move(*next); - -- try { -+ RTC_TRY { - trackCallback(std::make_shared(impl)); -- } catch (const std::exception &e) { -- PLOG_WARNING << "Uncaught exception in callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - - // Do not trigger open immediately for tracks as it'll be done later -diff --git a/thirdparty/libdatachannel/src/impl/peerconnection.hpp b/thirdparty/libdatachannel/src/impl/peerconnection.hpp -index 47fd4dc071..facf07d744 100644 ---- a/thirdparty/libdatachannel/src/impl/peerconnection.hpp -+++ b/thirdparty/libdatachannel/src/impl/peerconnection.hpp -@@ -43,9 +43,9 @@ struct PeerConnection : std::enable_shared_from_this { - optional remoteDescription() const; - size_t remoteMaxMessageSize() const; - -- shared_ptr initIceTransport(); -- shared_ptr initDtlsTransport(); -- shared_ptr initSctpTransport(); -+ RTC_WRAPPED(shared_ptr) initIceTransport(); -+ RTC_WRAPPED(shared_ptr) initDtlsTransport(); -+ RTC_WRAPPED(shared_ptr) initSctpTransport(); - shared_ptr getIceTransport() const; - shared_ptr getDtlsTransport() const; - shared_ptr getSctpTransport() const; -@@ -54,16 +54,16 @@ struct PeerConnection : std::enable_shared_from_this { - void endLocalCandidates(); - void rollbackLocalDescription(); - bool checkFingerprint(const std::string &fingerprint) const; -- void forwardMessage(message_ptr message); -+ RTC_WRAPPED(void) forwardMessage(message_ptr message); - void forwardMedia(message_ptr message); - void forwardBufferedAmount(uint16_t stream, size_t amount); - -- shared_ptr emplaceDataChannel(string label, DataChannelInit init); -+ RTC_WRAPPED(shared_ptr) emplaceDataChannel(string label, DataChannelInit init); - std::pair, bool> findDataChannel(uint16_t stream); - bool removeDataChannel(uint16_t stream); - uint16_t maxDataChannelStream() const; -- void assignDataChannels(); -- void iterateDataChannels(std::function channel)> func); -+ RTC_WRAPPED(void) assignDataChannels(); -+ void iterateDataChannels(std::function channel)> func); - void openDataChannels(); - void closeDataChannels(); - void remoteCloseDataChannels(); -@@ -75,11 +75,11 @@ struct PeerConnection : std::enable_shared_from_this { - void closeTracks(); - #endif - -- void validateRemoteDescription(const Description &description); -- void processLocalDescription(Description description); -- void processLocalCandidate(Candidate candidate); -- void processRemoteDescription(Description description); -- void processRemoteCandidate(Candidate candidate); -+ RTC_WRAPPED(void) validateRemoteDescription(const Description &description); -+ RTC_WRAPPED(void) processLocalDescription(Description description); -+ RTC_WRAPPED(void) processLocalCandidate(Candidate candidate); -+ RTC_WRAPPED(void) processRemoteDescription(Description description); -+ RTC_WRAPPED(void) processRemoteCandidate(Candidate candidate); - string localBundleMid() const; - - #if RTC_ENABLE_MEDIA -diff --git a/thirdparty/libdatachannel/src/impl/sctptransport.cpp b/thirdparty/libdatachannel/src/impl/sctptransport.cpp -index 5071c89f0b..424218f123 100644 ---- a/thirdparty/libdatachannel/src/impl/sctptransport.cpp -+++ b/thirdparty/libdatachannel/src/impl/sctptransport.cpp -@@ -52,20 +52,20 @@ using namespace std::chrono; - - namespace { - --template uint16_t to_uint16(T i) { -+template RTC_WRAPPED(uint16_t) to_uint16(T i) { - if (i >= 0 && static_cast::type>(i) <= - std::numeric_limits::max()) - return static_cast(i); - else -- throw std::invalid_argument("Integer out of range"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Integer out of range"); - } - --template uint32_t to_uint32(T i) { -+template RTC_WRAPPED(uint32_t) to_uint32(T i) { - if (i >= 0 && static_cast::type>(i) <= - std::numeric_limits::max()) - return static_cast(i); - else -- throw std::invalid_argument("Integer out of range"); -+ RTC_THROW RTC_INVALID_ARGUMENT("Integer out of range"); - } - - } // namespace -@@ -110,53 +110,55 @@ void SctpTransport::Init() { - #endif - } - --void SctpTransport::SetSettings(const SctpSettings &s) { -+RTC_WRAPPED(void) SctpTransport::SetSettings(const SctpSettings &s) { -+ RTC_BEGIN; - // The send and receive window size of usrsctp is 256KiB, which is too small for realistic RTTs, - // therefore we increase it to 1MiB by default for better performance. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685 -- usrsctp_sysctl_set_sctp_recvspace(to_uint32(s.recvBufferSize.value_or(1024 * 1024))); -- usrsctp_sysctl_set_sctp_sendspace(to_uint32(s.sendBufferSize.value_or(1024 * 1024))); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_recvspace, to_uint32(s.recvBufferSize.value_or(1024 * 1024))); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_sendspace, to_uint32(s.sendBufferSize.value_or(1024 * 1024))); - - // Increase maximum chunks number on queue to 10K by default -- usrsctp_sysctl_set_sctp_max_chunks_on_queue(to_uint32(s.maxChunksOnQueue.value_or(10 * 1024))); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_max_chunks_on_queue, to_uint32(s.maxChunksOnQueue.value_or(10 * 1024))); - - // Increase initial congestion window size to 10 MTUs (RFC 6928) by default -- usrsctp_sysctl_set_sctp_initial_cwnd(to_uint32(s.initialCongestionWindow.value_or(10))); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_initial_cwnd, to_uint32(s.initialCongestionWindow.value_or(10))); - - // Set max burst to 10 MTUs by default (max burst is initially 0, meaning disabled) -- usrsctp_sysctl_set_sctp_max_burst_default(to_uint32(s.maxBurst.value_or(10))); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_max_burst_default, to_uint32(s.maxBurst.value_or(10))); - - // Use standard SCTP congestion control (RFC 4960) by default - // See https://github.com/paullouisageneau/libdatachannel/issues/354 -- usrsctp_sysctl_set_sctp_default_cc_module(to_uint32(s.congestionControlModule.value_or(0))); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_default_cc_module, to_uint32(s.congestionControlModule.value_or(0))); - - // Reduce SACK delay to 20ms by default (the recommended default value from RFC 4960 is 200ms) -- usrsctp_sysctl_set_sctp_delayed_sack_time_default( -- to_uint32(s.delayedSackTime.value_or(20ms).count())); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_delayed_sack_time_default, -+ to_uint32(s.delayedSackTime.value_or(20ms).count())); - - // RTO settings - // RFC 2988 recommends a 1s min RTO, which is very high, but TCP on Linux has a 200ms min RTO -- usrsctp_sysctl_set_sctp_rto_min_default( -- to_uint32(s.minRetransmitTimeout.value_or(200ms).count())); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_rto_min_default, -+ to_uint32(s.minRetransmitTimeout.value_or(200ms).count())); - // Set only 10s as max RTO instead of 60s for shorter connection timeout -- usrsctp_sysctl_set_sctp_rto_max_default( -- to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); -- usrsctp_sysctl_set_sctp_init_rto_max_default( -- to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_rto_max_default, -+ to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_init_rto_max_default, -+ to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); - // Still set 1s as initial RTO -- usrsctp_sysctl_set_sctp_rto_initial_default( -- to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count())); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_rto_initial_default, -+ to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count())); - - // RTX settings - // 5 retransmissions instead of 8 to shorten the backoff for shorter connection timeout -- auto maxRtx = to_uint32(s.maxRetransmitAttempts.value_or(5)); -+ RTC_UNWRAP_RETHROW_DECL(auto, maxRtx, to_uint32(s.maxRetransmitAttempts.value_or(5))); - usrsctp_sysctl_set_sctp_init_rtx_max_default(maxRtx); - usrsctp_sysctl_set_sctp_assoc_rtx_max_default(maxRtx); - usrsctp_sysctl_set_sctp_path_rtx_max_default(maxRtx); // single path - - // Heartbeat interval -- usrsctp_sysctl_set_sctp_heartbeat_interval_default( -- to_uint32(s.heartbeatInterval.value_or(10000ms).count())); -+ RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_heartbeat_interval_default, -+ to_uint32(s.heartbeatInterval.value_or(10000ms).count())); -+ RTC_RET; - } - - void SctpTransport::Cleanup() { -@@ -164,41 +166,44 @@ void SctpTransport::Cleanup() { - std::this_thread::sleep_for(100ms); - } - --SctpTransport::SctpTransport(shared_ptr lower, const Configuration &config, Ports ports, -+SctpTransport::SctpTransport(shared_ptr lower, Ports ports, - message_callback recvCallback, amount_callback bufferedAmountCallback, - state_callback stateChangeCallback) - : Transport(lower, std::move(stateChangeCallback)), mPorts(std::move(ports)), - mSendQueue(0, message_size_func), mBufferedAmountCallback(std::move(bufferedAmountCallback)) { - onRecv(std::move(recvCallback)); -+} - -+RTC_WRAPPED(void) SctpTransport::construct(const Configuration &config) { -+ RTC_BEGIN; - PLOG_DEBUG << "Initializing SCTP transport"; - - mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, nullptr, nullptr, 0, nullptr); - if (!mSock) -- throw std::runtime_error("Could not create SCTP socket, errno=" + std::to_string(errno)); -+ RTC_THROW RTC_RUNTIME_ERROR("Could not create SCTP socket, errno=" + std::to_string(errno)); - - usrsctp_set_upcall(mSock, &SctpTransport::UpcallCallback, this); - - if (usrsctp_set_non_blocking(mSock, 1)) -- throw std::runtime_error("Unable to set non-blocking mode, errno=" + std::to_string(errno)); -+ RTC_THROW RTC_RUNTIME_ERROR("Unable to set non-blocking mode, errno=" + std::to_string(errno)); - - // SCTP must stop sending after the lower layer is shut down, so disable linger - struct linger sol = {}; - sol.l_onoff = 1; - sol.l_linger = 0; - if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_LINGER, &sol, sizeof(sol))) -- throw std::runtime_error("Could not set socket option SO_LINGER, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SO_LINGER, errno=" + - std::to_string(errno)); - - struct sctp_assoc_value av = {}; - av.assoc_id = SCTP_ALL_ASSOC; - av.assoc_value = 1; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, &av, sizeof(av))) -- throw std::runtime_error("Could not set socket option SCTP_ENABLE_STREAM_RESET, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_ENABLE_STREAM_RESET, errno=" + - std::to_string(errno)); - int on = 1; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on))) -- throw std::runtime_error("Could set socket option SCTP_RECVRCVINFO, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could set socket option SCTP_RECVRCVINFO, errno=" + - std::to_string(errno)); - - struct sctp_event se = {}; -@@ -206,15 +211,15 @@ SctpTransport::SctpTransport(shared_ptr lower, const Configuration &c - se.se_on = 1; - se.se_type = SCTP_ASSOC_CHANGE; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se))) -- throw std::runtime_error("Could not subscribe to event SCTP_ASSOC_CHANGE, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not subscribe to event SCTP_ASSOC_CHANGE, errno=" + - std::to_string(errno)); - se.se_type = SCTP_SENDER_DRY_EVENT; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se))) -- throw std::runtime_error("Could not subscribe to event SCTP_SENDER_DRY_EVENT, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not subscribe to event SCTP_SENDER_DRY_EVENT, errno=" + - std::to_string(errno)); - se.se_type = SCTP_STREAM_RESET_EVENT; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se))) -- throw std::runtime_error("Could not subscribe to event SCTP_STREAM_RESET_EVENT, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not subscribe to event SCTP_STREAM_RESET_EVENT, errno=" + - std::to_string(errno)); - - // RFC 8831 6.6. Transferring User Data on a Data Channel -@@ -222,7 +227,7 @@ SctpTransport::SctpTransport(shared_ptr lower, const Configuration &c - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.6 - int nodelay = 1; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay))) -- throw std::runtime_error("Could not set socket option SCTP_NODELAY, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_NODELAY, errno=" + - std::to_string(errno)); - - struct sctp_paddrparams spp = {}; -@@ -252,12 +257,12 @@ SctpTransport::SctpTransport(shared_ptr lower, const Configuration &c - // The MTU value provided specifies the space available for chunks in the - // packet, so we also subtract the SCTP header size. - size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 48 - 8 - 40; // SCTP/DTLS/UDP/IPv6 -- spp.spp_pathmtu = to_uint32(pmtu); -+ RTC_UNWRAP_RETHROW_VAR(spp.spp_pathmtu, to_uint32(pmtu)); - PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu; - } - - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &spp, sizeof(spp))) -- throw std::runtime_error("Could not set socket option SCTP_PEER_ADDR_PARAMS, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_PEER_ADDR_PARAMS, errno=" + - std::to_string(errno)); - - // RFC 8831 6.2. SCTP Association Management -@@ -271,7 +276,7 @@ SctpTransport::SctpTransport(shared_ptr lower, const Configuration &c - sinit.sinit_num_ostreams = MAX_SCTP_STREAMS_COUNT; - sinit.sinit_max_instreams = MAX_SCTP_STREAMS_COUNT; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_INITMSG, &sinit, sizeof(sinit))) -- throw std::runtime_error("Could not set socket option SCTP_INITMSG, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_INITMSG, errno=" + - std::to_string(errno)); - - // Prevent fragmented interleave of messages (i.e. level 0), see RFC 6458 section 8.1.20. -@@ -279,18 +284,18 @@ SctpTransport::SctpTransport(shared_ptr lower, const Configuration &c - // may also be interleaved with partially delivered messages. - int level = 0; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &level, sizeof(level))) -- throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not disable SCTP fragmented interleave, errno=" + - std::to_string(errno)); - - int rcvBuf = 0; - socklen_t rcvBufLen = sizeof(rcvBuf); - if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen)) -- throw std::runtime_error("Could not get SCTP recv buffer size, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not get SCTP recv buffer size, errno=" + - std::to_string(errno)); - int sndBuf = 0; - socklen_t sndBufLen = sizeof(sndBuf); - if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, &sndBufLen)) -- throw std::runtime_error("Could not get SCTP send buffer size, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not get SCTP send buffer size, errno=" + - std::to_string(errno)); - - // Ensure the buffer is also large enough to accomodate the largest messages -@@ -300,15 +305,16 @@ SctpTransport::SctpTransport(shared_ptr lower, const Configuration &c - sndBuf = std::max(sndBuf, minBuf); - - if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, sizeof(rcvBuf))) -- throw std::runtime_error("Could not set SCTP recv buffer size, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set SCTP recv buffer size, errno=" + - std::to_string(errno)); - - if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, sizeof(sndBuf))) -- throw std::runtime_error("Could not set SCTP send buffer size, errno=" + -+ RTC_THROW RTC_RUNTIME_ERROR("Could not set SCTP send buffer size, errno=" + - std::to_string(errno)); - - usrsctp_register_address(this); - Instances->insert(this); -+ RTC_RET; - } - - SctpTransport::~SctpTransport() { -@@ -333,9 +339,9 @@ void SctpTransport::onBufferedAmount(amount_callback callback) { - mBufferedAmountCallback = std::move(callback); - } - --void SctpTransport::start() { -+RTC_WRAPPED(void) SctpTransport::start() { - registerIncoming(); -- connect(); -+ return connect(); - } - - void SctpTransport::stop() { close(); } -@@ -351,14 +357,14 @@ struct sockaddr_conn SctpTransport::getSockAddrConn(uint16_t port) { - return sconn; - } - --void SctpTransport::connect() { -+RTC_WRAPPED(void) SctpTransport::connect() { - PLOG_DEBUG << "SCTP connecting (local port=" << mPorts.local - << ", remote port=" << mPorts.remote << ")"; - changeState(State::Connecting); - - auto local = getSockAddrConn(mPorts.local); - if (usrsctp_bind(mSock, reinterpret_cast(&local), sizeof(local))) -- throw std::runtime_error("Could not bind usrsctp socket, errno=" + std::to_string(errno)); -+ RTC_THROW RTC_RUNTIME_ERROR("Could not bind usrsctp socket, errno=" + std::to_string(errno)); - - // According to RFC 8841, both endpoints must initiate the SCTP association, in a - // simultaneous-open manner, irrelevent to the SDP setup role. -@@ -366,10 +372,12 @@ void SctpTransport::connect() { - auto remote = getSockAddrConn(mPorts.remote); - int ret = usrsctp_connect(mSock, reinterpret_cast(&remote), sizeof(remote)); - if (ret && errno != EINPROGRESS) -- throw std::runtime_error("Connection attempt failed, errno=" + std::to_string(errno)); -+ RTC_THROW RTC_RUNTIME_ERROR("Connection attempt failed, errno=" + std::to_string(errno)); -+ RTC_RET; - } - --bool SctpTransport::send(message_ptr message) { -+RTC_WRAPPED(bool) SctpTransport::send(message_ptr message) { -+ RTC_BEGIN; - std::lock_guard lock(mSendMutex); - if (state() != State::Connected) - return false; -@@ -380,25 +388,31 @@ bool SctpTransport::send(message_ptr message) { - PLOG_VERBOSE << "Send size=" << message->size(); - - // Flush the queue, and if nothing is pending, try to send directly -- if (trySendQueue() && trySendMessage(message)) -- return true; -+ RTC_UNWRAP_RETHROW_DECL(bool, res1, trySendQueue()); -+ if (res1) { -+ RTC_UNWRAP_RETHROW_DECL(bool, res2, trySendMessage(message)); -+ if (res2) { -+ return true; -+ } -+ } - - mSendQueue.push(message); -- updateBufferedAmount(to_uint16(message->stream), ptrdiff_t(message_size_func(message))); -+ RTC_UNWRAP_RETHROW_DECL(uint16_t, tmp, to_uint16(message->stream)); -+ updateBufferedAmount(tmp, ptrdiff_t(message_size_func(message))); - return false; - } - - bool SctpTransport::flush() { -- try { -+ RTC_TRY { - std::lock_guard lock(mSendMutex); - if (state() != State::Connected) - return false; - -- trySendQueue(); -+ RTC_UNWRAP_CATCH(trySendQueue()); - return true; - -- } catch (const std::exception &e) { -- PLOG_WARNING << "SCTP flush: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "SCTP flush: " << e.RTC_WHAT(); - return false; - } - } -@@ -409,7 +423,11 @@ void SctpTransport::closeStream(unsigned int stream) { - // RFC 8831 6.7. Closing a Data Channel - // Closing of a data channel MUST be signaled by resetting the corresponding outgoing streams - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.7 -- mSendQueue.push(make_message(0, Message::Reset, to_uint16(stream))); -+ RTC_TRY { -+ RTC_UNWRAP_CATCH_DECL(uint16_t, sid, to_uint16(stream)); -+ mSendQueue.push(make_message(0, Message::Reset, sid)); -+ } RTC_CATCH(...) { -+ } - - // This method must not call the buffered callback synchronously - mProcessor.enqueue(&SctpTransport::flush, shared_from_this()); -@@ -462,7 +480,7 @@ void SctpTransport::incoming(message_ptr message) { - usrsctp_conninput(this, message->data(), message->size(), 0); - } - --bool SctpTransport::outgoing(message_ptr message) { -+RTC_WRAPPED(bool) SctpTransport::outgoing(message_ptr message) { - // Set recommended medium-priority DSCP value - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - message->dscp = 10; // AF11: Assured Forwarding class 1, low drop probability -@@ -472,7 +490,7 @@ bool SctpTransport::outgoing(message_ptr message) { - void SctpTransport::doRecv() { - std::lock_guard lock(mRecvMutex); - --mPendingRecvCount; -- try { -+ RTC_TRY { - while (state() != State::Disconnected && state() != State::Failed) { - const size_t bufferSize = 65536; - byte buffer[bufferSize]; -@@ -487,7 +505,7 @@ void SctpTransport::doRecv() { - if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ECONNRESET) - break; - else -- throw std::runtime_error("SCTP recv failed, errno=" + std::to_string(errno)); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("SCTP recv failed, errno=" + std::to_string(errno))); - } else if (len == 0) { - break; - } -@@ -512,7 +530,7 @@ void SctpTransport::doRecv() { - if (flags & MSG_EOR) { - // Message is complete, process it - if (infotype != SCTP_RECVV_RCVINFO) -- throw std::runtime_error("Missing SCTP recv info"); -+ RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Missing SCTP recv info")); - - processData(std::move(mPartialMessage), info.rcv_sid, - PayloadId(ntohl(info.rcv_ppid))); -@@ -520,18 +538,18 @@ void SctpTransport::doRecv() { - } - } - } -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void SctpTransport::doFlush() { - std::lock_guard lock(mSendMutex); - --mPendingFlushCount; -- try { -- trySendQueue(); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ RTC_TRY { -+ RTC_UNWRAP_CATCH(trySendQueue()); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - -@@ -557,15 +575,18 @@ void SctpTransport::enqueueFlush() { - } - } - --bool SctpTransport::trySendQueue() { -+RTC_WRAPPED(bool) SctpTransport::trySendQueue() { -+ RTC_BEGIN; - // Requires mSendMutex to be locked - while (auto next = mSendQueue.peek()) { - message_ptr message = std::move(*next); -- if (!trySendMessage(message)) -+ RTC_UNWRAP_RETHROW_DECL(bool, res, trySendMessage(message)); -+ if (!res) - return false; - - mSendQueue.pop(); -- updateBufferedAmount(to_uint16(message->stream), -ptrdiff_t(message_size_func(message))); -+ RTC_UNWRAP_RETHROW_DECL(uint16_t, tmp, to_uint16(message->stream)); -+ updateBufferedAmount(tmp, -ptrdiff_t(message_size_func(message))); - } - - if (!mSendQueue.running() && !std::exchange(mSendShutdown, true)) { -@@ -584,7 +605,8 @@ bool SctpTransport::trySendQueue() { - return true; - } - --bool SctpTransport::trySendMessage(message_ptr message) { -+RTC_WRAPPED(bool) SctpTransport::trySendMessage(message_ptr message) { -+ RTC_BEGIN; - // Requires mSendMutex to be locked - if (state() != State::Connected) - return false; -@@ -632,12 +654,12 @@ bool SctpTransport::trySendMessage(message_ptr message) { - case Reliability::Type::Rexmit: - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; -- spa.sendv_prinfo.pr_value = to_uint32(std::get(reliability.rexmit)); -+ RTC_UNWRAP_RETHROW_VAR(spa.sendv_prinfo.pr_value, to_uint32(std::get(reliability.rexmit))); - break; - case Reliability::Type::Timed: - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL; -- spa.sendv_prinfo.pr_value = to_uint32(std::get(reliability.rexmit).count()); -+ RTC_UNWRAP_RETHROW_VAR(spa.sendv_prinfo.pr_value, to_uint32(std::get(reliability.rexmit).count())); - break; - default: - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE; -@@ -660,7 +682,7 @@ bool SctpTransport::trySendMessage(message_ptr message) { - } - - PLOG_ERROR << "SCTP sending failed, errno=" << errno; -- throw std::runtime_error("Sending failed, errno=" + std::to_string(errno)); -+ RTC_THROW RTC_RUNTIME_ERROR("Sending failed, errno=" + std::to_string(errno)); - } - - PLOG_VERBOSE << "SCTP sent size=" << message->size(); -@@ -687,10 +709,10 @@ void SctpTransport::updateBufferedAmount(uint16_t streamId, ptrdiff_t delta) { - } - - void SctpTransport::triggerBufferedAmount(uint16_t streamId, size_t amount) { -- try { -+ RTC_TRY { - mBufferedAmountCallback(streamId, amount); -- } catch (const std::exception &e) { -- PLOG_WARNING << "SCTP buffered amount callback: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << "SCTP buffered amount callback: " << e.RTC_WHAT(); - } - } - -@@ -722,7 +744,7 @@ void SctpTransport::sendReset(uint16_t streamId) { - } - - void SctpTransport::handleUpcall() noexcept { -- try { -+ RTC_TRY { - PLOG_VERBOSE << "Handle upcall"; - - int events = usrsctp_get_events(mSock); -@@ -733,26 +755,27 @@ void SctpTransport::handleUpcall() noexcept { - if (events & SCTP_EVENT_WRITE) - enqueueFlush(); - -- } catch (const std::exception &e) { -- PLOG_ERROR << "SCTP upcall: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << "SCTP upcall: " << e.RTC_WHAT(); - } - } - - int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, - uint8_t /*set_df*/) noexcept { -- try { -+ RTC_TRY { - std::unique_lock lock(mWriteMutex); - PLOG_VERBOSE << "Handle write, len=" << len; - -- if (!outgoing(make_message(data, data + len))) -+ RTC_UNWRAP_CATCH_DECL(bool, res, outgoing(make_message(data, data + len))); -+ if (!res) - return -1; - - mWritten = true; - mWrittenOnce = true; - mWrittenCondition.notify_all(); - -- } catch (const std::exception &e) { -- PLOG_ERROR << "SCTP write: " << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_ERROR << "SCTP write: " << e.RTC_WHAT(); - return -1; - } - return 0; // success -diff --git a/thirdparty/libdatachannel/src/impl/sctptransport.hpp b/thirdparty/libdatachannel/src/impl/sctptransport.hpp -index 0ef4b8f725..3d65487a15 100644 ---- a/thirdparty/libdatachannel/src/impl/sctptransport.hpp -+++ b/thirdparty/libdatachannel/src/impl/sctptransport.hpp -@@ -28,7 +28,7 @@ namespace rtc::impl { - class SctpTransport final : public Transport, public std::enable_shared_from_this { - public: - static void Init(); -- static void SetSettings(const SctpSettings &s); -+ static RTC_WRAPPED(void) SetSettings(const SctpSettings &s); - static void Cleanup(); - - using amount_callback = std::function; -@@ -38,16 +38,17 @@ public: - uint16_t remote = DEFAULT_SCTP_PORT; - }; - -- SctpTransport(shared_ptr lower, const Configuration &config, Ports ports, -+ SctpTransport(shared_ptr lower, Ports ports, - message_callback recvCallback, amount_callback bufferedAmountCallback, - state_callback stateChangeCallback); - ~SctpTransport(); -+ RTC_WRAPPED(void) construct(const Configuration &config); - - void onBufferedAmount(amount_callback callback); - -- void start() override; -+ RTC_WRAPPED(void) start() override; - void stop() override; -- bool send(message_ptr message) override; // false if buffered -+ RTC_WRAPPED(bool) send(message_ptr message) override; // false if buffered - bool flush(); - void closeStream(unsigned int stream); - void close(); -@@ -75,17 +76,17 @@ private: - - struct sockaddr_conn getSockAddrConn(uint16_t port); - -- void connect(); -+ RTC_WRAPPED(void) connect(); - void shutdown(); - void incoming(message_ptr message) override; -- bool outgoing(message_ptr message) override; -+ RTC_WRAPPED(bool) outgoing(message_ptr message) override; - - void doRecv(); - void doFlush(); - void enqueueRecv(); - void enqueueFlush(); -- bool trySendQueue(); -- bool trySendMessage(message_ptr message); -+ RTC_WRAPPED(bool) trySendQueue(); -+ RTC_WRAPPED(bool) trySendMessage(message_ptr message); - void updateBufferedAmount(uint16_t streamId, ptrdiff_t delta); - void triggerBufferedAmount(uint16_t streamId, size_t amount); - void sendReset(uint16_t streamId); -diff --git a/thirdparty/libdatachannel/src/impl/tls.cpp b/thirdparty/libdatachannel/src/impl/tls.cpp -index 4ea7d89cc0..fc096d68fb 100644 ---- a/thirdparty/libdatachannel/src/impl/tls.cpp -+++ b/thirdparty/libdatachannel/src/impl/tls.cpp -@@ -16,12 +16,12 @@ - namespace rtc::gnutls { - - // Return false on non-fatal error --bool check(int ret, const string &message) { -+RTC_WRAPPED(bool) check(int ret, const string &message) { - if (ret < 0) { - if (!gnutls_error_is_fatal(ret)) { - return false; - } -- throw std::runtime_error(message + ": " + gnutls_strerror(ret)); -+ RTC_THROW RTC_RUNTIME_ERROR(message + ": " + gnutls_strerror(ret)); - } - return true; - } -@@ -97,7 +97,7 @@ size_t my_strftme(char *buf, size_t size, const char *format, const time_t *t) { - namespace rtc::mbedtls { - - // Return false on non-fatal error --bool check(int ret, const string &message) { -+RTC_WRAPPED(bool) check(int ret, const string &message) { - if (ret < 0) { - if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE || - ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS || ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS || -@@ -107,17 +107,17 @@ bool check(int ret, const string &message) { - // const size_t bufferSize = 1024; - // char buffer[bufferSize]; - // mbedtls_strerror(ret, reinterpret_cast(buffer), bufferSize); -- throw std::runtime_error(message + ": Error " + std::to_string(ret)); -+ RTC_THROW RTC_RUNTIME_ERROR(message + ": Error " + std::to_string(ret)); - } - return true; - } - --string format_time(const std::chrono::system_clock::time_point &tp) { -+RTC_WRAPPED(string) format_time(const std::chrono::system_clock::time_point &tp) { - time_t t = std::chrono::system_clock::to_time_t(tp); - const size_t bufferSize = 256; - char buffer[bufferSize]; - if (my_strftme(buffer, bufferSize, "%Y%m%d%H%M%S", &t) == 0) -- throw std::runtime_error("Time conversion failed"); -+ RTC_THROW RTC_RUNTIME_ERROR("Time conversion failed"); - - return string(buffer); - }; -@@ -170,18 +170,18 @@ string error_string(unsigned long error) { - return string(buffer); - } - --bool check(int success, const string &message) { -+RTC_WRAPPED(bool) check(int success, const string &message) { - unsigned long last_error = ERR_peek_last_error(); - ERR_clear_error(); - - if (success > 0) - return true; - -- throw std::runtime_error(message + (last_error != 0 ? ": " + error_string(last_error) : "")); -+ RTC_THROW RTC_RUNTIME_ERROR(message + (last_error != 0 ? ": " + error_string(last_error) : "")); - } - - // Return false on recoverable error --bool check_error(int err, const string &message) { -+RTC_WRAPPED(bool) check_error(int err, const string &message) { - unsigned long last_error = ERR_peek_last_error(); - ERR_clear_error(); - -@@ -189,13 +189,13 @@ bool check_error(int err, const string &message) { - return true; - - if (err == SSL_ERROR_ZERO_RETURN) -- throw std::runtime_error(message + ": peer closed connection"); -+ RTC_THROW RTC_RUNTIME_ERROR(message + ": peer closed connection"); - - if (err == SSL_ERROR_SYSCALL) -- throw std::runtime_error(message + ": fatal I/O error"); -+ RTC_THROW RTC_RUNTIME_ERROR(message + ": fatal I/O error"); - - if (err == SSL_ERROR_SSL) -- throw std::runtime_error(message + -+ RTC_THROW RTC_RUNTIME_ERROR(message + - (last_error != 0 ? ": " + error_string(last_error) : "")); - - // SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE end up here -@@ -204,7 +204,7 @@ bool check_error(int err, const string &message) { - - BIO *BIO_new_from_file(const string &filename) { - BIO *bio = nullptr; -- try { -+ RTC_TRY { - std::ifstream ifs(filename, std::ifstream::in | std::ifstream::binary); - if (!ifs.is_open()) - return nullptr; -@@ -220,7 +220,7 @@ BIO *BIO_new_from_file(const string &filename) { - ifs.close(); - return bio; - -- } catch (const std::exception &) { -+ } RTC_CATCH (const RTC_EXCEPTION &) { - BIO_free(bio); - return nullptr; - } -diff --git a/thirdparty/libdatachannel/src/impl/tls.hpp b/thirdparty/libdatachannel/src/impl/tls.hpp -index 36ad6155ff..61c2f08fd7 100644 ---- a/thirdparty/libdatachannel/src/impl/tls.hpp -+++ b/thirdparty/libdatachannel/src/impl/tls.hpp -@@ -23,7 +23,7 @@ - - namespace rtc::gnutls { - --bool check(int ret, const string &message = "GnuTLS error"); -+RTC_WRAPPED(bool) check(int ret, const string &message = "GnuTLS error"); - - gnutls_certificate_credentials_t *new_credentials(); - void free_credentials(gnutls_certificate_credentials_t *creds); -@@ -52,9 +52,9 @@ gnutls_datum_t make_datum(char *data, size_t size); - - namespace rtc::mbedtls { - --bool check(int ret, const string &message = "MbedTLS error"); -+RTC_WRAPPED(bool) check(int ret, const string &message = "MbedTLS error"); - --string format_time(const std::chrono::system_clock::time_point &tp); -+RTC_WRAPPED(string) format_time(const std::chrono::system_clock::time_point &tp); - - std::shared_ptr new_pk_context(); - std::shared_ptr new_x509_crt(); -@@ -84,8 +84,8 @@ namespace rtc::openssl { - void init(); - string error_string(unsigned long error); - --bool check(int success, const string &message = "OpenSSL error"); --bool check_error(int err, const string &message = "OpenSSL error"); -+RTC_WRAPPED(bool) check(int success, const string &message = "OpenSSL error"); -+RTC_WRAPPED(bool) check_error(int err, const string &message = "OpenSSL error"); - - BIO *BIO_new_from_file(const string &filename); - -diff --git a/thirdparty/libdatachannel/src/impl/transport.cpp b/thirdparty/libdatachannel/src/impl/transport.cpp -index 1c28e4f365..3da1dd488f 100644 ---- a/thirdparty/libdatachannel/src/impl/transport.cpp -+++ b/thirdparty/libdatachannel/src/impl/transport.cpp -@@ -25,7 +25,13 @@ Transport::~Transport() { - void Transport::registerIncoming() { - if (mLower) { - PLOG_VERBOSE << "Registering incoming callback"; -- mLower->onRecv(std::bind(&Transport::incoming, this, std::placeholders::_1)); -+ mLower->onRecv([this](message_ptr message) -> void { -+ RTC_TRY { -+ Transport::incoming(message); -+ } RTC_CATCH(RTC_EXCEPTION e) { -+ PLOG_WARNING << e.RTC_WHAT(); // FIXME -+ } -+ }); - } - } - -@@ -44,32 +50,32 @@ void Transport::onStateChange(state_callback callback) { - mStateChangeCallback = std::move(callback); - } - --void Transport::start() { registerIncoming(); } -+RTC_WRAPPED(void) Transport::start() { registerIncoming(); RTC_RET; } - - void Transport::stop() { unregisterIncoming(); } - --bool Transport::send(message_ptr message) { return outgoing(message); } -+RTC_WRAPPED(bool) Transport::send(message_ptr message) { return outgoing(message); } - - void Transport::recv(message_ptr message) { -- try { -+ RTC_TRY { - mRecvCallback(message); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void Transport::changeState(State state) { -- try { -+ RTC_TRY { - if (mState.exchange(state) != state) - mStateChangeCallback(state); -- } catch (const std::exception &e) { -- PLOG_WARNING << e.what(); -+ } RTC_CATCH (const RTC_EXCEPTION &e) { -+ PLOG_WARNING << e.RTC_WHAT(); - } - } - - void Transport::incoming(message_ptr message) { recv(message); } - --bool Transport::outgoing(message_ptr message) { -+RTC_WRAPPED(bool) Transport::outgoing(message_ptr message) { - if (mLower) - return mLower->send(message); - else -diff --git a/thirdparty/libdatachannel/src/impl/transport.hpp b/thirdparty/libdatachannel/src/impl/transport.hpp -index fc879df2b6..5d8ed725a1 100644 ---- a/thirdparty/libdatachannel/src/impl/transport.hpp -+++ b/thirdparty/libdatachannel/src/impl/transport.hpp -@@ -35,15 +35,15 @@ public: - void onRecv(message_callback callback); - void onStateChange(state_callback callback); - -- virtual void start(); -+ virtual RTC_WRAPPED(void) start(); - virtual void stop(); -- virtual bool send(message_ptr message); -+ virtual RTC_WRAPPED(bool) send(message_ptr message); - - protected: - void recv(message_ptr message); - void changeState(State state); - virtual void incoming(message_ptr message); -- virtual bool outgoing(message_ptr message); -+ virtual RTC_WRAPPED(bool) outgoing(message_ptr message); - - private: - const init_token mInitToken = Init::Instance().token(); -diff --git a/thirdparty/libdatachannel/src/impl/utils.cpp b/thirdparty/libdatachannel/src/impl/utils.cpp -index 262fdaed4a..16250158ef 100644 ---- a/thirdparty/libdatachannel/src/impl/utils.cpp -+++ b/thirdparty/libdatachannel/src/impl/utils.cpp -@@ -62,15 +62,11 @@ string url_decode(const string &str) { - char c = str[i++]; - if (c == '%') { - auto value = str.substr(i, 2); -- try { -- if (value.size() != 2 || !std::isxdigit(value[0]) || !std::isxdigit(value[1])) -- throw std::exception(); -- -+ if (value.size() != 2 || !std::isxdigit(value[0]) || !std::isxdigit(value[1])) { -+ PLOG_WARNING << "Invalid percent-encoded character in URL: \"%" + value + "\""; -+ } else { - c = static_cast(std::stoi(value, nullptr, 16)); - i += 2; -- -- } catch (...) { -- PLOG_WARNING << "Invalid percent-encoded character in URL: \"%" + value + "\""; - } - } - -diff --git a/thirdparty/libdatachannel/src/peerconnection.cpp b/thirdparty/libdatachannel/src/peerconnection.cpp -index bde4fb013c..7c5e17d1fc 100644 ---- a/thirdparty/libdatachannel/src/peerconnection.cpp -+++ b/thirdparty/libdatachannel/src/peerconnection.cpp -@@ -38,11 +38,7 @@ PeerConnection::PeerConnection(Configuration config) - : CheshireCat(std::move(config)) {} - - PeerConnection::~PeerConnection() { -- try { -- impl()->remoteClose(); -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -- } -+ impl()->remoteClose(); - } - - void PeerConnection::close() { impl()->close(); } -@@ -74,7 +70,8 @@ bool PeerConnection::hasMedia() const { - return local && local->hasAudioOrVideo(); - } - --void PeerConnection::setLocalDescription(Description::Type type) { -+RTC_WRAPPED(void) PeerConnection::setLocalDescription(Description::Type type) { -+ RTC_BEGIN; - std::unique_lock signalingLock(impl()->signalingMutex); - PLOG_VERBOSE << "Setting local description, type=" << Description::typeToString(type); - -@@ -85,7 +82,7 @@ void PeerConnection::setLocalDescription(Description::Type type) { - impl()->rollbackLocalDescription(); - impl()->changeSignalingState(SignalingState::Stable); - } -- return; -+ RTC_RET; - } - - // Guess the description type if unspecified -@@ -99,7 +96,7 @@ void PeerConnection::setLocalDescription(Description::Type type) { - // Only a local offer resets the negotiation needed flag - if (type == Description::Type::Offer && !impl()->negotiationNeeded.exchange(false)) { - PLOG_DEBUG << "No negotiation needed"; -- return; -+ RTC_RET; - } - - // Get the new signaling state -@@ -110,7 +107,7 @@ void PeerConnection::setLocalDescription(Description::Type type) { - std::ostringstream oss; - oss << "Unexpected local desciption type " << type << " in signaling state " - << signalingState; -- throw std::logic_error(oss.str()); -+ RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::HaveLocalOffer; - break; -@@ -121,7 +118,7 @@ void PeerConnection::setLocalDescription(Description::Type type) { - std::ostringstream oss; - oss << "Unexpected local description type " << type - << " description in signaling state " << signalingState; -- throw std::logic_error(oss.str()); -+ RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::Stable; - break; -@@ -130,26 +127,28 @@ void PeerConnection::setLocalDescription(Description::Type type) { - std::ostringstream oss; - oss << "Unexpected local description in signaling state " << signalingState << ", ignoring"; - LOG_WARNING << oss.str(); -- return; -+ RTC_RET; - } - } - -- auto iceTransport = impl()->initIceTransport(); -+ RTC_UNWRAP_RETHROW_DECL(auto, iceTransport, impl()->initIceTransport()); - if (!iceTransport) -- return; // closed -+ RTC_RET; // closed - -- Description local = iceTransport->getLocalDescription(type); -- impl()->processLocalDescription(std::move(local)); -+ RTC_UNWRAP_RETHROW_DECL(Description, local, iceTransport->getLocalDescription(type)); -+ RTC_UNWRAP_RETHROW(impl()->processLocalDescription(std::move(local))); - - impl()->changeSignalingState(newSignalingState); - signalingLock.unlock(); - - if (impl()->gatheringState == GatheringState::New) { -- iceTransport->gatherLocalCandidates(impl()->localBundleMid()); -+ RTC_UNWRAP_RETHROW(iceTransport->gatherLocalCandidates(impl()->localBundleMid())); - } -+ RTC_RET; - } - --void PeerConnection::setRemoteDescription(Description description) { -+RTC_WRAPPED(void) PeerConnection::setRemoteDescription(Description description) { -+ RTC_BEGIN; - std::unique_lock signalingLock(impl()->signalingMutex); - PLOG_VERBOSE << "Setting remote description: " << string(description); - -@@ -157,10 +156,10 @@ void PeerConnection::setRemoteDescription(Description description) { - // This is mostly useless because we accept any offer - PLOG_VERBOSE << "Rolling back pending remote description"; - impl()->changeSignalingState(SignalingState::Stable); -- return; -+ RTC_RET; - } - -- impl()->validateRemoteDescription(description); -+ RTC_UNWRAP_RETHROW(impl()->validateRemoteDescription(description)); - - // Get the new signaling state - SignalingState signalingState = impl()->signalingState.load(); -@@ -172,7 +171,7 @@ void PeerConnection::setRemoteDescription(Description description) { - std::ostringstream oss; - oss << "Unexpected remote " << description.type() << " description in signaling state " - << signalingState; -- throw std::logic_error(oss.str()); -+ RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::HaveRemoteOffer; - break; -@@ -193,7 +192,7 @@ void PeerConnection::setRemoteDescription(Description description) { - std::ostringstream oss; - oss << "Unexpected remote " << description.type() << " description in signaling state " - << signalingState; -- throw std::logic_error(oss.str()); -+ RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::Stable; - break; -@@ -205,7 +204,7 @@ void PeerConnection::setRemoteDescription(Description description) { - std::ostringstream oss; - oss << "Unexpected remote " << description.type() << " description in signaling state " - << signalingState; -- throw std::logic_error(oss.str()); -+ RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::Stable; - break; -@@ -213,7 +212,7 @@ void PeerConnection::setRemoteDescription(Description description) { - default: { - std::ostringstream oss; - oss << "Unexpected remote description in signaling state " << signalingState; -- throw std::logic_error(oss.str()); -+ RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - } - -@@ -221,30 +220,31 @@ void PeerConnection::setRemoteDescription(Description description) { - auto remoteCandidates = description.extractCandidates(); - auto type = description.type(); - -- auto iceTransport = impl()->initIceTransport(); -+ RTC_UNWRAP_RETHROW_DECL(auto, iceTransport, impl()->initIceTransport()); - if (!iceTransport) -- return; // closed -+ RTC_RET; // closed - -- iceTransport->setRemoteDescription(description); // ICE transport might reject the description -+ RTC_UNWRAP_RETHROW(iceTransport->setRemoteDescription(description)); // ICE transport might reject the description - -- impl()->processRemoteDescription(std::move(description)); -+ RTC_UNWRAP_RETHROW(impl()->processRemoteDescription(std::move(description))); - impl()->changeSignalingState(newSignalingState); - signalingLock.unlock(); - - if (type == Description::Type::Offer) { - // This is an offer, we need to answer - if (!impl()->config.disableAutoNegotiation) -- setLocalDescription(Description::Type::Answer); -+ RTC_UNWRAP_RETHROW(setLocalDescription(Description::Type::Answer)); - } - - for (const auto &candidate : remoteCandidates) -- addRemoteCandidate(candidate); -+ RTC_UNWRAP_RETHROW(addRemoteCandidate(candidate)); -+ RTC_RET; - } - --void PeerConnection::addRemoteCandidate(Candidate candidate) { -+RTC_WRAPPED(void) PeerConnection::addRemoteCandidate(Candidate candidate) { - std::unique_lock signalingLock(impl()->signalingMutex); - PLOG_VERBOSE << "Adding remote candidate: " << string(candidate); -- impl()->processRemoteCandidate(std::move(candidate)); -+ return impl()->processRemoteCandidate(std::move(candidate)); - } - - #if RTC_ENABLE_MEDIA -@@ -267,8 +267,9 @@ optional PeerConnection::remoteAddress() const { - - uint16_t PeerConnection::maxDataChannelId() const { return impl()->maxDataChannelStream(); } - --shared_ptr PeerConnection::createDataChannel(string label, DataChannelInit init) { -- auto channelImpl = impl()->emplaceDataChannel(std::move(label), std::move(init)); -+RTC_WRAPPED(shared_ptr) PeerConnection::createDataChannel(string label, DataChannelInit init) { -+ RTC_BEGIN; -+ RTC_UNWRAP_RETHROW_DECL(auto, channelImpl, impl()->emplaceDataChannel(std::move(label), std::move(init))); - auto channel = std::make_shared(channelImpl); - - // Renegotiation is needed iff the current local description does not have application -@@ -277,7 +278,7 @@ shared_ptr PeerConnection::createDataChannel(string label, DataChan - impl()->negotiationNeeded = true; - - if (!impl()->config.disableAutoNegotiation) -- setLocalDescription(); -+ RTC_UNWRAP_RETHROW(setLocalDescription()); - - return channel; - } -@@ -331,9 +332,13 @@ void PeerConnection::onSignalingStateChange(std::functionresetCallbacks(); } - --bool PeerConnection::getSelectedCandidatePair(Candidate *local, Candidate *remote) { -+RTC_WRAPPED(bool) PeerConnection::getSelectedCandidatePair(Candidate *local, Candidate *remote) { -+ RTC_BEGIN; - auto iceTransport = impl()->getIceTransport(); -- return iceTransport ? iceTransport->getSelectedCandidatePair(local, remote) : false; -+ if (iceTransport) { -+ RTC_UNWRAP_RETHROW(iceTransport->getSelectedCandidatePair(local, remote)); -+ } -+ return false; - } - - void PeerConnection::clearStats() { diff --git a/godot/thirdparty/libdatachannel/patches/disable_logging.patch b/godot/thirdparty/libdatachannel/patches/disable_logging.patch deleted file mode 100644 index 8a40507b..00000000 --- a/godot/thirdparty/libdatachannel/patches/disable_logging.patch +++ /dev/null @@ -1,163 +0,0 @@ -diff --git a/thirdparty/libdatachannel/deps/libjuice/src/log.c b/thirdparty/libdatachannel/deps/libjuice/src/log.c -index d19e767292..05282de78e 100644 ---- a/thirdparty/libdatachannel/deps/libjuice/src/log.c -+++ b/thirdparty/libdatachannel/deps/libjuice/src/log.c -@@ -6,6 +6,8 @@ - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -+#if !defined(GODOT_JUICE_DISABLE_LOG) -+ - #include "log.h" - #include "thread.h" // for mutexes and atomics - -@@ -129,3 +131,13 @@ void juice_log_write(juice_log_level_t level, const char *file, int line, const - __exit: - mutex_unlock(&log_mutex); - } -+ -+#else // !defined(GODOT_JUICE_DISABLE_LOG) -+ -+#include "juice.h" -+ -+JUICE_EXPORT void juice_set_log_level(juice_log_level_t level) { } -+ -+JUICE_EXPORT void juice_set_log_handler(juice_log_cb_t cb) { } -+ -+#endif // defined(GODOT_JUICE_DISABLE_LOG) -diff --git a/thirdparty/libdatachannel/deps/libjuice/src/log.h b/thirdparty/libdatachannel/deps/libjuice/src/log.h -index 4ac34a6896..eb65a8ae8c 100644 ---- a/thirdparty/libdatachannel/deps/libjuice/src/log.h -+++ b/thirdparty/libdatachannel/deps/libjuice/src/log.h -@@ -13,9 +13,18 @@ - - #include - -+#if !defined(GODOT_JUICE_DISABLE_LOG) -+ - bool juice_log_is_enabled(juice_log_level_t level); - void juice_log_write(juice_log_level_t level, const char *file, int line, const char *fmt, ...); - -+#else // !defined(GODOT_JUICE_DISABLE_LOG) -+ -+inline bool juice_log_is_enabled(juice_log_level_t level) { return false; } -+inline void juice_log_write(juice_log_level_t level, const char *file, int line, const char *fmt, ...) { } -+ -+#endif // defined(GODOT_JUICE_DEBUG_LOG) -+ - #define JLOG_VERBOSE(...) juice_log_write(JUICE_LOG_LEVEL_VERBOSE, __FILE__, __LINE__, __VA_ARGS__) - #define JLOG_DEBUG(...) juice_log_write(JUICE_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) - #define JLOG_INFO(...) juice_log_write(JUICE_LOG_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__) -diff --git a/thirdparty/libdatachannel/deps/plog/include/plog/Log.h b/thirdparty/libdatachannel/deps/plog/include/plog/Log.h -index 138d92f5fe..13d0da70a3 100644 ---- a/thirdparty/libdatachannel/deps/plog/include/plog/Log.h -+++ b/thirdparty/libdatachannel/deps/plog/include/plog/Log.h -@@ -4,6 +4,44 @@ - // License: MIT, https://choosealicense.com/licenses/mit - - #pragma once -+ -+#if defined(GODOT_PLOG_DISABLE_LOG) -+ -+#include -+#include -+#include -+ -+#define PLOG_GET_FUNC() "" -+#define PLOG_GET_THIS() reinterpret_cast(0) -+#define PLOG_GET_FILE() "" -+ -+class NullLog { -+public: -+ template NullLog &operator<<(const T&) { return *this; } -+}; -+ -+namespace plog { -+ class Logger_ { -+ public: -+ Severity getMaxSeverity() const { return none; } -+ }; -+ inline Logger_ *get() { return nullptr; } -+} -+ -+#define PLOG_DEFAULT_INSTANCE_ID 0 -+ -+#define PLOG_(inst, sev) NullLog() -+#define PLOG(sev) NullLog() -+ -+#ifdef _MSC_VER -+# define IF_PLOG_(instanceId, severity) __pragma(warning(push)) __pragma(warning(disable:4127)) if (true) {;} else __pragma(warning(pop)) // conditional expression is constant -+#else -+# define IF_PLOG_(instanceId, severity) if (true) {;} else -+#endif -+#define IF_PLOG(severity) IF_PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity) -+ -+#else // defined(GODOT_PLOG_DISABLE_LOG) -+ - #include - - ////////////////////////////////////////////////////////////////////////// -@@ -50,6 +88,8 @@ - #define PLOG_(instanceId, severity) IF_PLOG_(instanceId, severity) (*plog::get()) += plog::Record(severity, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS(), instanceId).ref() - #define PLOG(severity) PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity) - -+#endif // !defined(GODOT_PLOG_DISABLE_LOG) -+ - #define PLOG_VERBOSE PLOG(plog::verbose) - #define PLOG_DEBUG PLOG(plog::debug) - #define PLOG_INFO PLOG(plog::info) -diff --git a/thirdparty/libdatachannel/src/global.cpp b/thirdparty/libdatachannel/src/global.cpp -index e7a5896d28..747dd217a2 100644 ---- a/thirdparty/libdatachannel/src/global.cpp -+++ b/thirdparty/libdatachannel/src/global.cpp -@@ -6,6 +6,7 @@ - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -+#if !defined(GODOT_PLOG_DISABLE_LOG) - #include "plog/Appenders/ColorConsoleAppender.h" - #include "plog/Converters/UTF8Converter.h" - #include "plog/Formatters/FuncMessageFormatter.h" -@@ -13,6 +14,7 @@ - #include "plog/Init.h" - #include "plog/Log.h" - #include "plog/Logger.h" -+#endif // !defined(GODOT_PLOG_DISABLE_LOG) - // - #include "global.hpp" - -@@ -22,6 +24,7 @@ - - namespace { - -+#if !defined(GODOT_PLOG_DISABLE_LOG) - void plogInit(plog::Severity severity, plog::IAppender *appender) { - using Logger = plog::Logger; - static Logger *logger = nullptr; -@@ -41,11 +44,13 @@ void plogInit(plog::Severity severity, plog::IAppender *appender) { - logger->addAppender(appender); - } - } -+#endif // !defined(GODOT_PLOG_DISABLE_LOG) - - } // namespace - - namespace rtc { - -+#if !defined(GODOT_PLOG_DISABLE_LOG) - struct LogAppender : public plog::IAppender { - synchronized_callback callback; - -@@ -82,6 +87,12 @@ void InitLogger(LogLevel level, LogCallback callback) { - void InitLogger(plog::Severity severity, plog::IAppender *appender) { - plogInit(severity, appender); - } -+#else // !defined(GODOT_PLOG_DISABLE_LOG) -+ -+void InitLogger(LogLevel level, LogCallback callback) { -+} -+ -+#endif // defined(GODOT_PLOG_DISABLE_LOG) - - void Preload() { impl::Init::Instance().preload(); } - std::shared_future Cleanup() { return impl::Init::Instance().cleanup(); } diff --git a/godot/thirdparty/libdatachannel/patches/disable_media.patch b/godot/thirdparty/libdatachannel/patches/disable_media.patch deleted file mode 100644 index 4b17b430..00000000 --- a/godot/thirdparty/libdatachannel/patches/disable_media.patch +++ /dev/null @@ -1,2335 +0,0 @@ -diff --git a/thirdparty/libdatachannel/include/rtc/peerconnection.hpp b/thirdparty/libdatachannel/include/rtc/peerconnection.hpp -index 66238cb6bb..512bed3c83 100644 ---- a/thirdparty/libdatachannel/include/rtc/peerconnection.hpp -+++ b/thirdparty/libdatachannel/include/rtc/peerconnection.hpp -@@ -93,15 +93,19 @@ public: - void setRemoteDescription(Description description); - void addRemoteCandidate(Candidate candidate); - -+#if RTC_ENABLE_MEDIA - void setMediaHandler(shared_ptr handler); - shared_ptr getMediaHandler(); -+#endif - - [[nodiscard]] shared_ptr createDataChannel(string label, - DataChannelInit init = {}); - void onDataChannel(std::function dataChannel)> callback); - -+#if RTC_ENABLE_MEDIA - [[nodiscard]] shared_ptr addTrack(Description::Media description); - void onTrack(std::function track)> callback); -+#endif - - void onLocalDescription(std::function callback); - void onLocalCandidate(std::function callback); -diff --git a/thirdparty/libdatachannel/src/impl/peerconnection.cpp b/thirdparty/libdatachannel/src/impl/peerconnection.cpp -index c53469d981..3bd9f9fcc4 100644 ---- a/thirdparty/libdatachannel/src/impl/peerconnection.cpp -+++ b/thirdparty/libdatachannel/src/impl/peerconnection.cpp -@@ -84,7 +84,9 @@ void PeerConnection::remoteClose() { - if (state.load() != State::Closed) { - // Close data channels and tracks asynchronously - mProcessor.enqueue(&PeerConnection::closeDataChannels, shared_from_this()); -+#if RTC_ENABLE_MEDIA - mProcessor.enqueue(&PeerConnection::closeTracks, shared_from_this()); -+#endif - - closeTransports(); - } -@@ -230,7 +232,9 @@ shared_ptr PeerConnection::initDtlsTransport() { - else - changeState(State::Connected); - -+#if RTC_ENABLE_MEDIA - mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); -+#endif - break; - case DtlsTransport::State::Failed: - changeState(State::Failed); -@@ -360,7 +364,9 @@ void PeerConnection::closeTransports() { - return; // already closed - - // Reset interceptor and callbacks now that state is changed -+#if RTC_ENABLE_MEDIA - setMediaHandler(nullptr); -+#endif - resetCallbacks(); - - // Pass the pointers to a thread, allowing to terminate a transport from its own thread -@@ -494,6 +500,7 @@ void PeerConnection::forwardMessage(message_ptr message) { - } - - void PeerConnection::forwardMedia(message_ptr message) { -+#if RTC_ENABLE_MEDIA - if (!message) - return; - -@@ -581,6 +588,7 @@ void PeerConnection::forwardMedia(message_ptr message) { - // PLOG_WARNING << "Track not found for SSRC " << ssrc << ", dropping"; - return; - } -+#endif - } - - void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) { -@@ -723,6 +731,7 @@ void PeerConnection::remoteCloseDataChannels() { - iterateDataChannels([&](shared_ptr channel) { channel->remoteClose(); }); - } - -+#if RTC_ENABLE_MEDIA - shared_ptr PeerConnection::emplaceTrack(Description::Media description) { - #if !RTC_ENABLE_MEDIA - // No media support, mark as removed -@@ -762,7 +771,6 @@ void PeerConnection::iterateTracks(std::function track)> - } - - void PeerConnection::openTracks() { --#if RTC_ENABLE_MEDIA - if (auto transport = std::atomic_load(&mDtlsTransport)) { - auto srtpTransport = std::dynamic_pointer_cast(transport); - -@@ -782,13 +790,13 @@ void PeerConnection::openTracks() { - } - }); - } --#endif - } - - void PeerConnection::closeTracks() { - std::shared_lock lock(mTracksMutex); // read-only - iterateTracks([&](shared_ptr track) { track->close(); }); - } -+#endif - - void PeerConnection::validateRemoteDescription(const Description &description) { - if (!description.iceUfrag()) -@@ -865,6 +873,7 @@ void PeerConnection::processLocalDescription(Description description) { - description.addMedia(std::move(reciprocated)); - }, - [&](Description::Media *remoteMedia) { -+#if RTC_ENABLE_MEDIA - std::shared_lock lock(mTracksMutex); - if (auto it = mTracks.find(remoteMedia->mid()); it != mTracks.end()) { - // Prefer local description -@@ -889,7 +898,7 @@ void PeerConnection::processLocalDescription(Description description) { - } - return; - } -- -+#endif - auto reciprocated = remoteMedia->reciprocate(); - #if !RTC_ENABLE_MEDIA - if (!reciprocated.isRemoved()) { -@@ -898,7 +907,7 @@ void PeerConnection::processLocalDescription(Description description) { - reciprocated.markRemoved(); - } - #endif -- -+#if RTC_ENABLE_MEDIA - PLOG_DEBUG << "Reciprocating media in local description, mid=\"" - << reciprocated.mid() << "\", removed=" << std::boolalpha - << reciprocated.isRemoved(); -@@ -914,6 +923,7 @@ void PeerConnection::processLocalDescription(Description description) { - track->close(); - - description.addMedia(track->description()); -+#endif - }, - }, - remote->media(i)); -@@ -924,6 +934,7 @@ void PeerConnection::processLocalDescription(Description description) { - - if (description.type() == Description::Type::Offer) { - // This is an offer, add locally created data channels and tracks -+#if RTC_ENABLE_MEDIA - // Add media for local tracks - std::shared_lock lock(mTracksMutex); - for (auto it = mTrackLines.begin(); it != mTrackLines.end(); ++it) { -@@ -939,6 +950,7 @@ void PeerConnection::processLocalDescription(Description description) { - description.addMedia(std::move(media)); - } - } -+#endif - - // Add application for data channels - if (!description.hasApplication()) { -@@ -994,9 +1006,11 @@ void PeerConnection::processLocalDescription(Description description) { - &localDescriptionCallback, std::move(description)); - - // Reciprocated tracks might need to be open -+#if RTC_ENABLE_MEDIA - if (auto dtlsTransport = std::atomic_load(&mDtlsTransport); - dtlsTransport && dtlsTransport->state() == Transport::State::Connected) - mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); -+#endif - } - - void PeerConnection::processLocalCandidate(Candidate candidate) { -@@ -1089,6 +1103,7 @@ string PeerConnection::localBundleMid() const { - return mLocalDescription ? mLocalDescription->bundleMid() : "0"; - } - -+#if RTC_ENABLE_MEDIA - void PeerConnection::setMediaHandler(shared_ptr handler) { - std::unique_lock lock(mMediaHandlerMutex); - if (mMediaHandler) -@@ -1100,6 +1115,7 @@ shared_ptr PeerConnection::getMediaHandler() { - std::shared_lock lock(mMediaHandlerMutex); - return mMediaHandler; - } -+#endif - - void PeerConnection::triggerDataChannel(weak_ptr weakDataChannel) { - auto dataChannel = weakDataChannel.lock(); -@@ -1110,6 +1126,7 @@ void PeerConnection::triggerDataChannel(weak_ptr weakDataChannel) { - triggerPendingDataChannels(); - } - -+#if RTC_ENABLE_MEDIA - void PeerConnection::triggerTrack(weak_ptr weakTrack) { - auto track = weakTrack.lock(); - if (track) { -@@ -1118,6 +1135,7 @@ void PeerConnection::triggerTrack(weak_ptr weakTrack) { - } - triggerPendingTracks(); - } -+#endif - - void PeerConnection::triggerPendingDataChannels() { - while (dataChannelCallback) { -@@ -1138,6 +1156,7 @@ void PeerConnection::triggerPendingDataChannels() { - } - - void PeerConnection::triggerPendingTracks() { -+#if RTC_ENABLE_MEDIA - while (trackCallback) { - auto next = mPendingTracks.pop(); - if (!next) -@@ -1153,6 +1172,7 @@ void PeerConnection::triggerPendingTracks() { - - // Do not trigger open immediately for tracks as it'll be done later - } -+#endif - } - - void PeerConnection::flushPendingDataChannels() { -@@ -1160,7 +1180,9 @@ void PeerConnection::flushPendingDataChannels() { - } - - void PeerConnection::flushPendingTracks() { -+#if RTC_ENABLE_MEDIA - mProcessor.enqueue(&PeerConnection::triggerPendingTracks, shared_from_this()); -+#endif - } - - bool PeerConnection::changeState(State newState) { -@@ -1241,10 +1263,13 @@ void PeerConnection::resetCallbacks() { - iceStateChangeCallback = nullptr; - gatheringStateChangeCallback = nullptr; - signalingStateChangeCallback = nullptr; -+#if RTC_ENABLE_MEDIA - trackCallback = nullptr; -+#endif - } - - void PeerConnection::updateTrackSsrcCache(const Description &description) { -+#if RTC_ENABLE_MEDIA - std::unique_lock lock(mTracksMutex); // for safely writing to mTracksBySsrc - - // Setup SSRC -> Track mapping -@@ -1277,6 +1302,7 @@ void PeerConnection::updateTrackSsrcCache(const Description &description) { - }, - }, - description.media(i)); -+#endif - } - - } // namespace rtc::impl -diff --git a/thirdparty/libdatachannel/src/impl/peerconnection.hpp b/thirdparty/libdatachannel/src/impl/peerconnection.hpp -index 79c6e5b42c..47fd4dc071 100644 ---- a/thirdparty/libdatachannel/src/impl/peerconnection.hpp -+++ b/thirdparty/libdatachannel/src/impl/peerconnection.hpp -@@ -68,10 +68,12 @@ struct PeerConnection : std::enable_shared_from_this { - void closeDataChannels(); - void remoteCloseDataChannels(); - -+#if RTC_ENABLE_MEDIA - shared_ptr emplaceTrack(Description::Media description); - void iterateTracks(std::function track)> func); - void openTracks(); - void closeTracks(); -+#endif - - void validateRemoteDescription(const Description &description); - void processLocalDescription(Description description); -@@ -80,11 +82,15 @@ struct PeerConnection : std::enable_shared_from_this { - void processRemoteCandidate(Candidate candidate); - string localBundleMid() const; - -+#if RTC_ENABLE_MEDIA - void setMediaHandler(shared_ptr handler); - shared_ptr getMediaHandler(); -+#endif - - void triggerDataChannel(weak_ptr weakDataChannel); -+#if RTC_ENABLE_MEDIA - void triggerTrack(weak_ptr weakTrack); -+#endif - - void triggerPendingDataChannels(); - void triggerPendingTracks(); -@@ -124,7 +130,9 @@ struct PeerConnection : std::enable_shared_from_this { - synchronized_callback iceStateChangeCallback; - synchronized_callback gatheringStateChangeCallback; - synchronized_callback signalingStateChangeCallback; -+#if RTC_ENABLE_MEDIA - synchronized_callback> trackCallback; -+#endif - - private: - void updateTrackSsrcCache(const Description &description); -@@ -137,10 +145,11 @@ private: - optional mCurrentLocalDescription; - mutable std::mutex mLocalDescriptionMutex, mRemoteDescriptionMutex; - -+#if RTC_ENABLE_MEDIA - shared_ptr mMediaHandler; - - mutable std::shared_mutex mMediaHandlerMutex; -- -+#endif - shared_ptr mIceTransport; - shared_ptr mDtlsTransport; - shared_ptr mSctpTransport; -@@ -149,13 +158,18 @@ private: - std::vector> mUnassignedDataChannels; - std::shared_mutex mDataChannelsMutex; - -+#if RTC_ENABLE_MEDIA - std::unordered_map> mTracks; // by mid - std::unordered_map> mTracksBySsrc; // by SSRC - std::vector> mTrackLines; // by SDP order - std::shared_mutex mTracksMutex; -+#endif - - Queue> mPendingDataChannels; -+ -+#if RTC_ENABLE_MEDIA - Queue> mPendingTracks; -+#endif - }; - - } // namespace rtc::impl -diff --git a/thirdparty/libdatachannel/src/impl/track.cpp b/thirdparty/libdatachannel/src/impl/track.cpp -deleted file mode 100644 -index 99cdd5acd9..0000000000 ---- a/thirdparty/libdatachannel/src/impl/track.cpp -+++ /dev/null -@@ -1,225 +0,0 @@ --/** -- * Copyright (c) 2020 Paul-Louis Ageneau -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#include "track.hpp" --#include "internals.hpp" --#include "logcounter.hpp" --#include "peerconnection.hpp" --#include "rtp.hpp" -- --namespace rtc::impl { -- --static LogCounter COUNTER_MEDIA_BAD_DIRECTION(plog::warning, -- "Number of media packets sent in invalid directions"); --static LogCounter COUNTER_QUEUE_FULL(plog::warning, -- "Number of media packets dropped due to a full queue"); -- --Track::Track(weak_ptr pc, Description::Media description) -- : mPeerConnection(pc), mMediaDescription(std::move(description)), -- mRecvQueue(RECV_QUEUE_LIMIT, [](const message_ptr &m) { return m->size(); }) { -- -- // Discard messages by default if track is send only -- if (mMediaDescription.direction() == Description::Direction::SendOnly) -- messageCallback = [](message_variant) {}; --} -- --Track::~Track() { -- PLOG_VERBOSE << "Destroying Track"; -- try { -- close(); -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -- } --} -- --string Track::mid() const { -- std::shared_lock lock(mMutex); -- return mMediaDescription.mid(); --} -- --Description::Direction Track::direction() const { -- std::shared_lock lock(mMutex); -- return mMediaDescription.direction(); --} -- --Description::Media Track::description() const { -- std::shared_lock lock(mMutex); -- return mMediaDescription; --} -- --void Track::setDescription(Description::Media description) { -- std::unique_lock lock(mMutex); -- if (description.mid() != mMediaDescription.mid()) -- throw std::logic_error("Media description mid does not match track mid"); -- -- mMediaDescription = std::move(description); --} -- --void Track::close() { -- PLOG_VERBOSE << "Closing Track"; -- -- if (!mIsClosed.exchange(true)) -- triggerClosed(); -- -- setMediaHandler(nullptr); -- resetCallbacks(); --} -- --optional Track::receive() { -- if (auto next = mRecvQueue.pop()) { -- message_ptr message = *next; -- if (message->type == Message::Control) -- return to_variant(**next); // The same message may be frowarded into multiple Tracks -- else -- return to_variant(std::move(*message)); -- } -- return nullopt; --} -- --optional Track::peek() { -- if (auto next = mRecvQueue.peek()) { -- message_ptr message = *next; -- if (message->type == Message::Control) -- return to_variant(**next); // The same message may be forwarded into multiple Tracks -- else -- return to_variant(std::move(*message)); -- } -- return nullopt; --} -- --size_t Track::availableAmount() const { return mRecvQueue.amount(); } -- --bool Track::isOpen(void) const { --#if RTC_ENABLE_MEDIA -- std::shared_lock lock(mMutex); -- return !mIsClosed && mDtlsSrtpTransport.lock(); --#else -- return false; --#endif --} -- --bool Track::isClosed(void) const { return mIsClosed; } -- --size_t Track::maxMessageSize() const { -- optional mtu; -- if (auto pc = mPeerConnection.lock()) -- mtu = pc->config.mtu; -- -- return mtu.value_or(DEFAULT_MTU) - 12 - 8 - 40; // SRTP/UDP/IPv6 --} -- --#if RTC_ENABLE_MEDIA --void Track::open(shared_ptr transport) { -- { -- std::lock_guard lock(mMutex); -- mDtlsSrtpTransport = transport; -- } -- -- if (!mIsClosed) -- triggerOpen(); --} --#endif -- --void Track::incoming(message_ptr message) { -- if (!message) -- return; -- -- auto handler = getMediaHandler(); -- -- auto dir = direction(); -- if ((dir == Description::Direction::SendOnly || dir == Description::Direction::Inactive) && -- message->type != Message::Control) { -- COUNTER_MEDIA_BAD_DIRECTION++; -- return; -- } -- -- if (handler) { -- message = handler->incoming(message); -- if (!message) -- return; -- } -- -- // Tail drop if queue is full -- if (mRecvQueue.full()) { -- COUNTER_QUEUE_FULL++; -- return; -- } -- -- mRecvQueue.push(message); -- triggerAvailable(mRecvQueue.size()); --} -- --bool Track::outgoing(message_ptr message) { -- if (mIsClosed) -- throw std::runtime_error("Track is closed"); -- -- auto handler = getMediaHandler(); -- -- // If there is no handler, the track expects RTP or RTCP packets -- if (!handler && IsRtcp(*message)) -- message->type = Message::Control; // to allow sending RTCP packets irrelevant of direction -- -- auto dir = direction(); -- if ((dir == Description::Direction::RecvOnly || dir == Description::Direction::Inactive) && -- message->type != Message::Control) { -- COUNTER_MEDIA_BAD_DIRECTION++; -- return false; -- } -- -- if (handler) { -- message = handler->outgoing(message); -- if (!message) -- return false; -- } -- -- return transportSend(message); --} -- --bool Track::transportSend([[maybe_unused]] message_ptr message) { --#if RTC_ENABLE_MEDIA -- shared_ptr transport; -- { -- std::shared_lock lock(mMutex); -- transport = mDtlsSrtpTransport.lock(); -- if (!transport) -- throw std::runtime_error("Track is closed"); -- -- // Set recommended medium-priority DSCP value -- // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 -- if (mMediaDescription.type() == "audio") -- message->dscp = 46; // EF: Expedited Forwarding -- else -- message->dscp = 36; // AF42: Assured Forwarding class 4, medium drop probability -- } -- -- return transport->sendMedia(message); --#else -- throw std::runtime_error("Track is disabled (not compiled with media support)"); --#endif --} -- --void Track::setMediaHandler(shared_ptr handler) { -- auto currentHandler = getMediaHandler(); -- if (currentHandler) -- currentHandler->onOutgoing(nullptr); -- -- { -- std::unique_lock lock(mMutex); -- mMediaHandler = handler; -- } -- -- if (handler) -- handler->onOutgoing(std::bind(&Track::transportSend, this, std::placeholders::_1)); --} -- --shared_ptr Track::getMediaHandler() { -- std::shared_lock lock(mMutex); -- return mMediaHandler; --} -- --} // namespace rtc::impl -diff --git a/thirdparty/libdatachannel/src/mediachainablehandler.cpp b/thirdparty/libdatachannel/src/mediachainablehandler.cpp -deleted file mode 100644 -index 5094b52a69..0000000000 ---- a/thirdparty/libdatachannel/src/mediachainablehandler.cpp -+++ /dev/null -@@ -1,163 +0,0 @@ --/** -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "mediachainablehandler.hpp" -- --#include "impl/internals.hpp" -- --#include -- --namespace rtc { -- --MediaChainableHandler::MediaChainableHandler(shared_ptr root) -- : MediaHandler(), root(root), leaf(root) {} -- --MediaChainableHandler::~MediaChainableHandler() { leaf->recursiveRemoveChain(); } -- --bool MediaChainableHandler::sendProduct(ChainedOutgoingProduct product) { -- bool result = true; -- if (product.control) { -- assert(product.control->type == Message::Control); -- auto sendResult = send(product.control); -- if (!sendResult) { -- LOG_DEBUG << "Failed to send control message"; -- } -- result = result && sendResult; -- } -- if (product.messages) { -- auto messages = product.messages; -- for (unsigned i = 0; i < messages->size(); i++) { -- auto message = messages->at(i); -- if (!message) { -- LOG_DEBUG << "Invalid message to send " << i + 1 << "/" << messages->size(); -- } -- auto sendResult = send(make_message(*message)); -- if (!sendResult) { -- LOG_DEBUG << "Failed to send message " << i + 1 << "/" << messages->size(); -- } -- result = result && sendResult; -- } -- } -- return result; --} -- --message_ptr MediaChainableHandler::handleIncomingBinary(message_ptr msg) { -- assert(msg->type == Message::Binary); -- auto messages = root->split(msg); -- auto incoming = getLeaf()->formIncomingBinaryMessage( -- messages, [this](ChainedOutgoingProduct outgoing) { return sendProduct(outgoing); }); -- if (incoming) { -- return root->reduce(incoming); -- } else { -- return nullptr; -- } --} -- --message_ptr MediaChainableHandler::handleIncomingControl(message_ptr msg) { -- assert(msg->type == Message::Control); -- auto incoming = getLeaf()->formIncomingControlMessage( -- msg, [this](ChainedOutgoingProduct outgoing) { return sendProduct(outgoing); }); -- assert(!incoming || incoming->type == Message::Control); -- return incoming; --} -- --message_ptr MediaChainableHandler::handleOutgoingBinary(message_ptr msg) { -- assert(msg->type == Message::Binary); -- auto messages = make_chained_messages_product(msg); -- auto optOutgoing = root->formOutgoingBinaryMessage(ChainedOutgoingProduct(messages)); -- if (!optOutgoing.has_value()) { -- LOG_ERROR << "Generating outgoing message failed"; -- return nullptr; -- } -- auto outgoing = optOutgoing.value(); -- if (outgoing.control) { -- if (!send(outgoing.control)) { -- LOG_DEBUG << "Failed to send control message"; -- } -- } -- auto lastMessage = outgoing.messages->back(); -- if (!lastMessage) { -- LOG_DEBUG << "Invalid message to send"; -- return nullptr; -- } -- for (unsigned i = 0; i < outgoing.messages->size() - 1; i++) { -- auto message = outgoing.messages->at(i); -- if (!message) { -- LOG_DEBUG << "Invalid message to send " << i + 1 << "/" << outgoing.messages->size(); -- } -- if (!send(make_message(*message))) { -- LOG_DEBUG << "Failed to send message " << i + 1 << "/" << outgoing.messages->size(); -- } -- } -- return make_message(*lastMessage); --} -- --message_ptr MediaChainableHandler::handleOutgoingControl(message_ptr msg) { -- assert(msg->type == Message::Control); -- auto outgoing = root->formOutgoingControlMessage(msg); -- assert(!outgoing || outgoing->type == Message::Control); -- if (!outgoing) { -- LOG_ERROR << "Generating outgoing control message failed"; -- return nullptr; -- } -- return outgoing; --} -- --message_ptr MediaChainableHandler::outgoing(message_ptr ptr) { -- assert(ptr); -- if (!ptr) { -- LOG_ERROR << "Outgoing message is nullptr, ignoring"; -- return nullptr; -- } -- if (ptr->type == Message::Binary) { -- return handleOutgoingBinary(ptr); -- } else if (ptr->type == Message::Control) { -- return handleOutgoingControl(ptr); -- } -- return ptr; --} -- --message_ptr MediaChainableHandler::incoming(message_ptr ptr) { -- if (!ptr) { -- LOG_ERROR << "Incoming message is nullptr, ignoring"; -- return nullptr; -- } -- if (ptr->type == Message::Binary) { -- return handleIncomingBinary(ptr); -- } else if (ptr->type == Message::Control) { -- return handleIncomingControl(ptr); -- } -- return ptr; --} -- --bool MediaChainableHandler::send(message_ptr msg) { -- try { -- outgoingCallback(std::move(msg)); -- return true; -- } catch (const std::exception &e) { -- LOG_DEBUG << "Send in RTCP chain handler failed: " << e.what(); -- } -- return false; --} -- --shared_ptr MediaChainableHandler::getLeaf() const { -- std::lock_guard lock(mutex); -- return leaf; --} -- --void MediaChainableHandler::addToChain(shared_ptr chainable) { -- std::lock_guard lock(mutex); -- assert(leaf); -- leaf = leaf->chainWith(chainable); --} -- --} // namespace rtc -- --#endif /* RTC_ENABLE_MEDIA */ -diff --git a/thirdparty/libdatachannel/src/mediahandlerelement.cpp b/thirdparty/libdatachannel/src/mediahandlerelement.cpp -deleted file mode 100644 -index 5ec13ce2e5..0000000000 ---- a/thirdparty/libdatachannel/src/mediahandlerelement.cpp -+++ /dev/null -@@ -1,211 +0,0 @@ --/** -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "mediahandlerelement.hpp" -- --#include "impl/internals.hpp" -- --#include -- --namespace rtc { -- --ChainedMessagesProduct make_chained_messages_product() { -- return std::make_shared>(); --} -- --ChainedMessagesProduct make_chained_messages_product(message_ptr msg) { -- std::vector msgs = {msg}; -- return std::make_shared>(msgs); --} -- --ChainedOutgoingProduct::ChainedOutgoingProduct(ChainedMessagesProduct messages, message_ptr control) -- : messages(messages), control(control) {} -- --ChainedIncomingProduct::ChainedIncomingProduct(ChainedMessagesProduct incoming, -- ChainedMessagesProduct outgoing) -- : incoming(incoming), outgoing(outgoing) {} -- --ChainedIncomingControlProduct::ChainedIncomingControlProduct( -- message_ptr incoming, optional outgoing) -- : incoming(incoming), outgoing(outgoing) {} -- --MediaHandlerElement::MediaHandlerElement() {} -- --void MediaHandlerElement::removeFromChain() { -- if (upstream) { -- upstream->downstream = downstream; -- } -- if (downstream) { -- downstream->upstream = upstream; -- } -- upstream = nullptr; -- downstream = nullptr; --} -- --void MediaHandlerElement::recursiveRemoveChain() { -- if (downstream) { -- // `recursiveRemoveChain` removes last strong reference to downstream element -- // we need to keep strong reference to prevent deallocation of downstream element -- // during `recursiveRemoveChain` -- auto strongDownstreamPtr = downstream; -- downstream->recursiveRemoveChain(); -- } -- removeFromChain(); --} -- --optional --MediaHandlerElement::processOutgoingResponse(ChainedOutgoingProduct messages) { -- if (messages.messages) { -- if (upstream) { -- auto msgs = upstream->formOutgoingBinaryMessage( -- ChainedOutgoingProduct(messages.messages, messages.control)); -- if (msgs.has_value()) { -- return msgs.value(); -- } else { -- LOG_ERROR << "Generating outgoing message failed"; -- return nullopt; -- } -- } else { -- return messages; -- } -- } else if (messages.control) { -- if (upstream) { -- auto control = upstream->formOutgoingControlMessage(messages.control); -- if (control) { -- return ChainedOutgoingProduct(nullptr, control); -- } else { -- LOG_ERROR << "Generating outgoing control message failed"; -- return nullopt; -- } -- } else { -- return messages; -- } -- } else { -- return ChainedOutgoingProduct(); -- } --} -- --void MediaHandlerElement::prepareAndSendResponse(optional outgoing, -- std::function send) { -- if (outgoing.has_value()) { -- auto message = outgoing.value(); -- auto response = processOutgoingResponse(message); -- if (response.has_value()) { -- if (!send(response.value())) { -- LOG_DEBUG << "Send failed"; -- } -- } else { -- LOG_DEBUG << "No response to send"; -- } -- } --} -- --message_ptr --MediaHandlerElement::formIncomingControlMessage(message_ptr message, -- std::function send) { -- assert(message); -- auto product = processIncomingControlMessage(message); -- prepareAndSendResponse(product.outgoing, send); -- if (product.incoming) { -- if (downstream) { -- return downstream->formIncomingControlMessage(product.incoming, send); -- } else { -- return product.incoming; -- } -- } else { -- return nullptr; -- } --} -- --ChainedMessagesProduct --MediaHandlerElement::formIncomingBinaryMessage(ChainedMessagesProduct messages, -- std::function send) { -- assert(messages); -- auto product = processIncomingBinaryMessage(messages); -- prepareAndSendResponse(product.outgoing, send); -- if (product.incoming) { -- if (downstream) { -- return downstream->formIncomingBinaryMessage(product.incoming, send); -- } else { -- return product.incoming; -- } -- } else { -- return nullptr; -- } --} -- --message_ptr MediaHandlerElement::formOutgoingControlMessage(message_ptr message) { -- assert(message); -- auto newMessage = processOutgoingControlMessage(message); -- assert(newMessage); -- if (!newMessage) { -- LOG_ERROR << "Failed to generate outgoing message"; -- return nullptr; -- } -- if (upstream) { -- return upstream->formOutgoingControlMessage(newMessage); -- } else { -- return newMessage; -- } --} -- --optional --MediaHandlerElement::formOutgoingBinaryMessage(ChainedOutgoingProduct product) { -- assert(product.messages && !product.messages->empty()); -- auto newProduct = processOutgoingBinaryMessage(product.messages, product.control); -- assert(!product.control || newProduct.control); -- assert(newProduct.messages && !newProduct.messages->empty()); -- if (product.control && !newProduct.control) { -- LOG_ERROR << "Outgoing message must not remove control message"; -- return nullopt; -- } -- if (!newProduct.messages || newProduct.messages->empty()) { -- LOG_ERROR << "Failed to generate message"; -- return nullopt; -- } -- if (upstream) { -- return upstream->formOutgoingBinaryMessage(newProduct); -- } else { -- return newProduct; -- } --} -- --ChainedIncomingControlProduct --MediaHandlerElement::processIncomingControlMessage(message_ptr messages) { -- return {messages}; --} -- --message_ptr MediaHandlerElement::processOutgoingControlMessage(message_ptr messages) { -- return messages; --} -- --ChainedIncomingProduct --MediaHandlerElement::processIncomingBinaryMessage(ChainedMessagesProduct messages) { -- return {messages}; --} -- --ChainedOutgoingProduct --MediaHandlerElement::processOutgoingBinaryMessage(ChainedMessagesProduct messages, -- message_ptr control) { -- return {messages, control}; --} -- --shared_ptr --MediaHandlerElement::chainWith(shared_ptr upstream) { -- assert(this->upstream == nullptr); -- assert(upstream->downstream == nullptr); -- this->upstream = upstream; -- upstream->downstream = shared_from_this(); -- return upstream; --} -- --} // namespace rtc -- --#endif /* RTC_ENABLE_MEDIA */ -diff --git a/thirdparty/libdatachannel/src/mediahandlerrootelement.cpp b/thirdparty/libdatachannel/src/mediahandlerrootelement.cpp -deleted file mode 100644 -index ccdfc5d090..0000000000 ---- a/thirdparty/libdatachannel/src/mediahandlerrootelement.cpp -+++ /dev/null -@@ -1,34 +0,0 @@ --/** -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "mediahandlerrootelement.hpp" -- --namespace rtc { -- --message_ptr MediaHandlerRootElement::reduce(ChainedMessagesProduct messages) { -- if (messages && !messages->empty()) { -- auto msg_ptr = messages->front(); -- if (msg_ptr) { -- return make_message(*msg_ptr); -- } else { -- return nullptr; -- } -- } else { -- return nullptr; -- } --} -- --ChainedMessagesProduct MediaHandlerRootElement::split(message_ptr message) { -- return make_chained_messages_product(message); --} -- --} // namespace rtc -- --#endif /* RTC_ENABLE_MEDIA */ -diff --git a/thirdparty/libdatachannel/src/nalunit.cpp b/thirdparty/libdatachannel/src/nalunit.cpp -deleted file mode 100644 -index a638beb202..0000000000 ---- a/thirdparty/libdatachannel/src/nalunit.cpp -+++ /dev/null -@@ -1,99 +0,0 @@ --/** -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "nalunit.hpp" -- --#include "impl/internals.hpp" -- --#include -- --namespace rtc { -- --NalUnitFragmentA::NalUnitFragmentA(FragmentType type, bool forbiddenBit, uint8_t nri, -- uint8_t unitType, binary data) -- : NalUnit(data.size() + 2) { -- setForbiddenBit(forbiddenBit); -- setNRI(nri); -- fragmentIndicator()->setUnitType(NalUnitFragmentA::nal_type_fu_A); -- setFragmentType(type); -- setUnitType(unitType); -- copy(data.begin(), data.end(), begin() + 2); --} -- --std::vector> --NalUnitFragmentA::fragmentsFrom(shared_ptr nalu, uint16_t maximumFragmentSize) { -- assert(nalu->size() > maximumFragmentSize); -- auto fragments_count = ceil(double(nalu->size()) / maximumFragmentSize); -- maximumFragmentSize = uint16_t(int(ceil(nalu->size() / fragments_count))); -- -- // 2 bytes for FU indicator and FU header -- maximumFragmentSize -= 2; -- auto f = nalu->forbiddenBit(); -- uint8_t nri = nalu->nri() & 0x03; -- uint8_t naluType = nalu->unitType() & 0x1F; -- auto payload = nalu->payload(); -- vector> result{}; -- uint64_t offset = 0; -- while (offset < payload.size()) { -- vector fragmentData; -- FragmentType fragmentType; -- if (offset == 0) { -- fragmentType = FragmentType::Start; -- } else if (offset + maximumFragmentSize < payload.size()) { -- fragmentType = FragmentType::Middle; -- } else { -- if (offset + maximumFragmentSize > payload.size()) { -- maximumFragmentSize = uint16_t(payload.size() - offset); -- } -- fragmentType = FragmentType::End; -- } -- fragmentData = {payload.begin() + offset, payload.begin() + offset + maximumFragmentSize}; -- auto fragment = -- std::make_shared(fragmentType, f, nri, naluType, fragmentData); -- result.push_back(fragment); -- offset += maximumFragmentSize; -- } -- return result; --} -- --void NalUnitFragmentA::setFragmentType(FragmentType type) { -- fragmentHeader()->setReservedBit6(false); -- switch (type) { -- case FragmentType::Start: -- fragmentHeader()->setStart(true); -- fragmentHeader()->setEnd(false); -- break; -- case FragmentType::End: -- fragmentHeader()->setStart(false); -- fragmentHeader()->setEnd(true); -- break; -- default: -- fragmentHeader()->setStart(false); -- fragmentHeader()->setEnd(false); -- } --} -- --std::vector> NalUnits::generateFragments(uint16_t maximumFragmentSize) { -- vector> result{}; -- for (auto nalu : *this) { -- if (nalu->size() > maximumFragmentSize) { -- std::vector> fragments = -- NalUnitFragmentA::fragmentsFrom(nalu, maximumFragmentSize); -- result.insert(result.end(), fragments.begin(), fragments.end()); -- } else { -- result.push_back(nalu); -- } -- } -- return result; --} -- --} // namespace rtc -- --#endif /* RTC_ENABLE_MEDIA */ -diff --git a/thirdparty/libdatachannel/src/peerconnection.cpp b/thirdparty/libdatachannel/src/peerconnection.cpp -index 6395f909df..bde4fb013c 100644 ---- a/thirdparty/libdatachannel/src/peerconnection.cpp -+++ b/thirdparty/libdatachannel/src/peerconnection.cpp -@@ -247,11 +247,13 @@ void PeerConnection::addRemoteCandidate(Candidate candidate) { - impl()->processRemoteCandidate(std::move(candidate)); - } - -+#if RTC_ENABLE_MEDIA - void PeerConnection::setMediaHandler(shared_ptr handler) { - impl()->setMediaHandler(std::move(handler)); - }; - - shared_ptr PeerConnection::getMediaHandler() { return impl()->getMediaHandler(); }; -+#endif - - optional PeerConnection::localAddress() const { - auto iceTransport = impl()->getIceTransport(); -@@ -286,6 +288,7 @@ void PeerConnection::onDataChannel( - impl()->flushPendingDataChannels(); - } - -+#if RTC_ENABLE_MEDIA - std::shared_ptr PeerConnection::addTrack(Description::Media description) { - auto trackImpl = impl()->emplaceTrack(std::move(description)); - auto track = std::make_shared(trackImpl); -@@ -300,6 +303,7 @@ void PeerConnection::onTrack(std::function)> callbac - impl()->trackCallback = callback; - impl()->flushPendingTracks(); - } -+#endif - - void PeerConnection::onLocalDescription(std::function callback) { - impl()->localDescriptionCallback = callback; -diff --git a/thirdparty/libdatachannel/src/rtcpnackresponder.cpp b/thirdparty/libdatachannel/src/rtcpnackresponder.cpp -deleted file mode 100644 -index efae6d94a4..0000000000 ---- a/thirdparty/libdatachannel/src/rtcpnackresponder.cpp -+++ /dev/null -@@ -1,122 +0,0 @@ --/** -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "rtcpnackresponder.hpp" -- --#include "impl/internals.hpp" -- --#include -- --namespace rtc { -- --RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, -- shared_ptr next) -- : packet(packet), sequenceNumber(sequenceNumber), next(next) {} -- --unsigned RtcpNackResponder::Storage::size() { return unsigned(storage.size()); } -- --RtcpNackResponder::Storage::Storage(unsigned _maximumSize) : maximumSize(_maximumSize) { -- assert(maximumSize > 0); -- storage.reserve(maximumSize); --} -- --optional RtcpNackResponder::Storage::get(uint16_t sequenceNumber) { -- std::lock_guard lock(mutex); -- auto position = storage.find(sequenceNumber); -- return position != storage.end() ? std::make_optional(storage.at(sequenceNumber)->packet) -- : nullopt; --} -- --void RtcpNackResponder::Storage::store(binary_ptr packet) { -- if (!packet || packet->size() < 12) { -- return; -- } -- auto rtp = reinterpret_cast(packet->data()); -- auto sequenceNumber = rtp->seqNumber(); -- -- std::lock_guard lock(mutex); -- assert((storage.empty() && !oldest && !newest) || (!storage.empty() && oldest && newest)); -- -- if (size() == 0) { -- newest = std::make_shared(packet, sequenceNumber); -- oldest = newest; -- } else { -- auto current = std::make_shared(packet, sequenceNumber); -- newest->next = current; -- newest = current; -- } -- -- storage.emplace(sequenceNumber, newest); -- -- if (size() > maximumSize) { -- assert(oldest); -- if (oldest) { -- storage.erase(oldest->sequenceNumber); -- oldest = oldest->next; -- } -- } --} -- --RtcpNackResponder::RtcpNackResponder(unsigned maxStoredPacketCount) -- : MediaHandlerElement(), storage(std::make_shared(maxStoredPacketCount)) {} -- --ChainedIncomingControlProduct --RtcpNackResponder::processIncomingControlMessage(message_ptr message) { -- optional optPackets = ChainedOutgoingProduct(nullptr); -- auto packets = make_chained_messages_product(); -- -- size_t p = 0; -- while (p < message->size()) { -- auto nack = reinterpret_cast(message->data() + p); -- p += nack->header.header.lengthInBytes(); -- // check if rtcp is nack -- if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) { -- continue; -- } -- -- auto fieldsCount = nack->getSeqNoCount(); -- -- std::vector missingSequenceNumbers{}; -- for (unsigned int i = 0; i < fieldsCount; i++) { -- auto field = nack->parts[i]; -- auto newMissingSeqenceNumbers = field.getSequenceNumbers(); -- missingSequenceNumbers.insert(missingSequenceNumbers.end(), -- newMissingSeqenceNumbers.begin(), -- newMissingSeqenceNumbers.end()); -- } -- packets->reserve(packets->size() + missingSequenceNumbers.size()); -- for (auto sequenceNumber : missingSequenceNumbers) { -- auto optPacket = storage->get(sequenceNumber); -- if (optPacket.has_value()) { -- auto packet = optPacket.value(); -- packets->push_back(packet); -- } -- } -- } -- -- if (!packets->empty()) { -- return {message, ChainedOutgoingProduct(packets)}; -- } else { -- return {message, nullopt}; -- } --} -- --ChainedOutgoingProduct --RtcpNackResponder::processOutgoingBinaryMessage(ChainedMessagesProduct messages, -- message_ptr control) { -- for (auto message : *messages) { -- storage->store(message); -- } -- return {messages, control}; --} -- --} // namespace rtc -- --#endif /* RTC_ENABLE_MEDIA */ -diff --git a/thirdparty/libdatachannel/src/rtcpreceivingsession.cpp b/thirdparty/libdatachannel/src/rtcpreceivingsession.cpp -deleted file mode 100644 -index 0ae719199a..0000000000 ---- a/thirdparty/libdatachannel/src/rtcpreceivingsession.cpp -+++ /dev/null -@@ -1,135 +0,0 @@ --/** -- * Copyright (c) 2020 Staz Modrzynski -- * Copyright (c) 2020 Paul-Louis Ageneau -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "rtcpreceivingsession.hpp" --#include "track.hpp" -- --#include "impl/logcounter.hpp" -- --#include --#include -- --#ifdef _WIN32 --#include --#else --#include --#endif -- --namespace rtc { -- --static impl::LogCounter COUNTER_BAD_RTP_HEADER(plog::warning, "Number of malformed RTP headers"); --static impl::LogCounter COUNTER_UNKNOWN_PPID(plog::warning, "Number of Unknown PPID messages"); --static impl::LogCounter COUNTER_BAD_NOTIF_LEN(plog::warning, -- "Number of Bad-Lengthed notifications"); --static impl::LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning, -- "Number of unknown SCTP_STATUS errors"); -- --message_ptr RtcpReceivingSession::outgoing(message_ptr ptr) { return ptr; } -- --message_ptr RtcpReceivingSession::incoming(message_ptr ptr) { -- if (ptr->type == Message::Binary) { -- auto rtp = reinterpret_cast(ptr->data()); -- -- // https://www.rfc-editor.org/rfc/rfc3550.html#appendix-A.1 -- if (rtp->version() != 2) { -- COUNTER_BAD_RTP_HEADER++; -- PLOG_VERBOSE << "RTP packet is not version 2"; -- -- return nullptr; -- } -- if (rtp->payloadType() == 201 || rtp->payloadType() == 200) { -- COUNTER_BAD_RTP_HEADER++; -- PLOG_VERBOSE << "RTP packet has a payload type indicating RR/SR"; -- -- return nullptr; -- } -- -- // Padding-processing is a user-level thing -- -- mSsrc = rtp->ssrc(); -- -- return ptr; -- } -- -- assert(ptr->type == Message::Control); -- auto rr = reinterpret_cast(ptr->data()); -- if (rr->header.payloadType() == 201) { -- // RR -- mSsrc = rr->senderSSRC(); -- rr->log(); -- } else if (rr->header.payloadType() == 200) { -- // SR -- mSsrc = rr->senderSSRC(); -- auto sr = reinterpret_cast(ptr->data()); -- mSyncRTPTS = sr->rtpTimestamp(); -- mSyncNTPTS = sr->ntpTimestamp(); -- sr->log(); -- -- // TODO For the time being, we will send RR's/REMB's when we get an SR -- pushRR(0); -- if (mRequestedBitrate > 0) -- pushREMB(mRequestedBitrate); -- } -- return nullptr; --} -- --void RtcpReceivingSession::requestBitrate(unsigned int newBitrate) { -- mRequestedBitrate = newBitrate; -- -- PLOG_DEBUG << "[GOOG-REMB] Requesting bitrate: " << newBitrate << std::endl; -- pushREMB(newBitrate); --} -- --void RtcpReceivingSession::pushREMB(unsigned int bitrate) { -- message_ptr msg = make_message(RtcpRemb::SizeWithSSRCs(1), Message::Control); -- auto remb = reinterpret_cast(msg->data()); -- remb->preparePacket(mSsrc, 1, bitrate); -- remb->setSsrc(0, mSsrc); -- -- send(msg); --} -- --void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) { -- auto msg = make_message(RtcpRr::SizeWithReportBlocks(1), Message::Control); -- auto rr = reinterpret_cast(msg->data()); -- rr->preparePacket(mSsrc, 1); -- rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS, -- lastSR_delay); -- rr->log(); -- -- send(msg); --} -- --bool RtcpReceivingSession::send(message_ptr msg) { -- try { -- outgoingCallback(std::move(msg)); -- return true; -- } catch (const std::exception &e) { -- LOG_DEBUG << "RTCP tx failed: " << e.what(); -- } -- return false; --} -- --bool RtcpReceivingSession::requestKeyframe() { -- pushPLI(); -- return true; --} -- --void RtcpReceivingSession::pushPLI() { -- auto msg = make_message(RtcpPli::Size(), Message::Control); -- auto *pli = reinterpret_cast(msg->data()); -- pli->preparePacket(mSsrc); -- send(msg); --} -- --} // namespace rtc -- --#endif // RTC_ENABLE_MEDIA -diff --git a/thirdparty/libdatachannel/src/rtcpsrreporter.cpp b/thirdparty/libdatachannel/src/rtcpsrreporter.cpp -deleted file mode 100644 -index 6bf8d65fe8..0000000000 ---- a/thirdparty/libdatachannel/src/rtcpsrreporter.cpp -+++ /dev/null -@@ -1,88 +0,0 @@ --/** -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_MEDIA -- --#include "rtcpsrreporter.hpp" -- --#include --#include --#include -- --namespace { -- --uint64_t ntp_time() { -- const auto now = std::chrono::system_clock::now(); -- const double secs = std::chrono::duration(now.time_since_epoch()).count(); -- // Assume the epoch is 01/01/1970 and adds the number of seconds between 1900 and 1970 -- return uint64_t(std::floor((secs + 2208988800.) * double(uint64_t(1) << 32))); --} -- --} // namespace -- --namespace rtc { -- --ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, -- message_ptr control) { -- if (std::exchange(mNeedsToReport, false)) { -- auto timestamp = rtpConfig->timestamp; -- auto sr = getSenderReport(timestamp); -- if (control) { -- control->insert(control->end(), sr->begin(), sr->end()); -- } else { -- control = sr; -- } -- } -- for (auto message : *messages) { -- auto rtp = reinterpret_cast(message->data()); -- addToReport(rtp, uint32_t(message->size())); -- } -- return {messages, control}; --} -- --void RtcpSrReporter::addToReport(RtpHeader *rtp, uint32_t rtpSize) { -- mPacketCount += 1; -- assert(!rtp->padding()); -- mPayloadOctets += rtpSize - uint32_t(rtp->getSize()); --} -- --RtcpSrReporter::RtcpSrReporter(shared_ptr rtpConfig) -- : MediaHandlerElement(), rtpConfig(rtpConfig) { -- mLastReportedTimestamp = rtpConfig->timestamp; --} -- --message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) { -- auto srSize = RtcpSr::Size(0); -- auto msg = make_message(srSize + RtcpSdes::Size({{uint8_t(rtpConfig->cname.size())}}), -- Message::Control); -- auto sr = reinterpret_cast(msg->data()); -- sr->setNtpTimestamp(ntp_time()); -- sr->setRtpTimestamp(timestamp); -- sr->setPacketCount(mPacketCount); -- sr->setOctetCount(mPayloadOctets); -- sr->preparePacket(rtpConfig->ssrc, 0); -- -- auto sdes = reinterpret_cast(msg->data() + srSize); -- auto chunk = sdes->getChunk(0); -- chunk->setSSRC(rtpConfig->ssrc); -- auto item = chunk->getItem(0); -- item->type = 1; -- item->setText(rtpConfig->cname); -- sdes->preparePacket(1); -- -- mLastReportedTimestamp = timestamp; -- return msg; --} -- --void RtcpSrReporter::setNeedsToReport() { mNeedsToReport = true; } -- --uint32_t RtcpSrReporter::lastReportedTimestamp() const { return mLastReportedTimestamp; } -- --} // namespace rtc -- --#endif /* RTC_ENABLE_MEDIA */ -diff --git a/thirdparty/libdatachannel/src/rtp.cpp b/thirdparty/libdatachannel/src/rtp.cpp -deleted file mode 100644 -index bedfb18f47..0000000000 ---- a/thirdparty/libdatachannel/src/rtp.cpp -+++ /dev/null -@@ -1,662 +0,0 @@ --/** -- * Copyright (c) 2020 Staz Modrzynski -- * Copyright (c) 2020 Paul-Louis Ageneau -- * Copyright (c) 2020 Filip Klembara (in2core) -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#include "rtp.hpp" -- --#include "impl/internals.hpp" -- --#include --#include -- --#ifdef _WIN32 --#include --#else --#include --#endif -- --#ifndef htonll --#define htonll(x) \ -- ((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32))) --#endif --#ifndef ntohll --#define ntohll(x) htonll(x) --#endif -- --namespace rtc { -- --bool IsRtcp(const binary &data) { -- if (data.size() < 8) -- return false; -- -- uint8_t payloadType = std::to_integer(data[1]) & 0x7F; -- PLOG_VERBOSE << "Demultiplexing RTCP and RTP with payload type, value=" << int(payloadType); -- -- // RFC 5761 Multiplexing RTP and RTCP 4. Distinguishable RTP and RTCP Packets -- // https://www.rfc-editor.org/rfc/rfc5761.html#section-4 -- // It is RECOMMENDED to follow the guidelines in the RTP/AVP profile for the choice of RTP -- // payload type values, with the additional restriction that payload type values in the -- // range 64-95 MUST NOT be used. Specifically, dynamic RTP payload types SHOULD be chosen in -- // the range 96-127 where possible. Values below 64 MAY be used if that is insufficient -- // [...] -- return (payloadType >= 64 && payloadType <= 95); // Range 64-95 (inclusive) MUST be RTCP --} -- --uint8_t RtpHeader::version() const { return _first >> 6; } --bool RtpHeader::padding() const { return (_first >> 5) & 0x01; } --bool RtpHeader::extension() const { return (_first >> 4) & 0x01; } --uint8_t RtpHeader::csrcCount() const { return _first & 0x0F; } --uint8_t RtpHeader::marker() const { return _payloadType & 0b10000000; } --uint8_t RtpHeader::payloadType() const { return _payloadType & 0b01111111; } --uint16_t RtpHeader::seqNumber() const { return ntohs(_seqNumber); } --uint32_t RtpHeader::timestamp() const { return ntohl(_timestamp); } --uint32_t RtpHeader::ssrc() const { return ntohl(_ssrc); } -- --size_t RtpHeader::getSize() const { -- return reinterpret_cast(&_ssrc + 1 + csrcCount()) - -- reinterpret_cast(this); --} -- --size_t RtpHeader::getExtensionHeaderSize() const { -- auto header = getExtensionHeader(); -- return header ? header->getSize() + sizeof(RtpExtensionHeader) : 0; --} -- --const RtpExtensionHeader *RtpHeader::getExtensionHeader() const { -- return extension() ? reinterpret_cast(&_ssrc + 1 + csrcCount()) -- : nullptr; --} -- --RtpExtensionHeader *RtpHeader::getExtensionHeader() { -- return extension() ? reinterpret_cast(&_ssrc + 1 + csrcCount()) : nullptr; --} -- --const char *RtpHeader::getBody() const { -- return reinterpret_cast(&_ssrc + 1 + csrcCount()) + getExtensionHeaderSize(); --} -- --char *RtpHeader::getBody() { -- return reinterpret_cast(&_ssrc + 1 + csrcCount()) + getExtensionHeaderSize(); --} -- --void RtpHeader::preparePacket() { _first |= (1 << 7); } -- --void RtpHeader::setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); } -- --void RtpHeader::setPayloadType(uint8_t newPayloadType) { -- _payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType); --} -- --void RtpHeader::setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); } -- --void RtpHeader::setMarker(bool marker) { _payloadType = (_payloadType & 0x7F) | (marker << 7); }; -- --void RtpHeader::setTimestamp(uint32_t i) { _timestamp = htonl(i); } -- --void RtpHeader::setExtension(bool extension) { _first = (_first & ~0x10) | ((extension & 1) << 4); } -- --void RtpHeader::log() const { -- PLOG_VERBOSE << "RtpHeader V: " << (int)version() << " P: " << (padding() ? "P" : " ") -- << " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount() -- << " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType() -- << " SEQNO: " << seqNumber() << " TS: " << timestamp(); --} -- --uint16_t RtpExtensionHeader::profileSpecificId() const { return ntohs(_profileSpecificId); } -- --uint16_t RtpExtensionHeader::headerLength() const { return ntohs(_headerLength); } -- --size_t RtpExtensionHeader::getSize() const { return headerLength() * 4; } -- --const char *RtpExtensionHeader::getBody() const { -- return reinterpret_cast((&_headerLength) + 1); --} -- --char *RtpExtensionHeader::getBody() { return reinterpret_cast((&_headerLength) + 1); } -- --void RtpExtensionHeader::setProfileSpecificId(uint16_t profileSpecificId) { -- _profileSpecificId = htons(profileSpecificId); --} -- --void RtpExtensionHeader::setHeaderLength(uint16_t headerLength) { -- _headerLength = htons(headerLength); --} -- --void RtpExtensionHeader::clearBody() { std::memset(getBody(), 0, getSize()); } -- --void RtpExtensionHeader::writeOneByteHeader(size_t offset, uint8_t id, const byte *value, -- size_t size) { -- if ((id == 0) || (id > 14) || (size == 0) || (size > 16) || ((offset + 1 + size) > getSize())) -- return; -- auto buf = getBody() + offset; -- buf[0] = id << 4; -- if (size != 1) { -- buf[0] |= (uint8_t(size) - 1); -- } -- std::memcpy(buf + 1, value, size); --} -- --void RtpExtensionHeader::writeCurrentVideoOrientation(size_t offset, const uint8_t id, -- uint8_t value) { -- auto v = std::byte{value}; -- writeOneByteHeader(offset, id, &v, 1); --} -- --SSRC RtcpReportBlock::getSSRC() const { return ntohl(_ssrc); } -- --void RtcpReportBlock::preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost, -- [[maybe_unused]] unsigned int totalPackets, -- uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter, -- uint64_t lastSR_NTP, uint64_t lastSR_DELAY) { -- setSeqNo(highestSeqNo, seqNoCycles); -- setJitter(jitter); -- setSSRC(in_ssrc); -- -- // Middle 32 bits of NTP Timestamp -- // _lastReport = lastSR_NTP >> 16u; -- setNTPOfSR(uint64_t(lastSR_NTP)); -- setDelaySinceSR(uint32_t(lastSR_DELAY)); -- -- // The delay, expressed in units of 1/65536 seconds -- // _delaySinceLastReport = lastSR_DELAY; --} -- --void RtcpReportBlock::setSSRC(SSRC in_ssrc) { _ssrc = htonl(in_ssrc); } -- --void RtcpReportBlock::setPacketsLost([[maybe_unused]] unsigned int packetsLost, -- [[maybe_unused]] unsigned int totalPackets) { -- // TODO Implement loss percentages. -- _fractionLostAndPacketsLost = 0; --} -- --unsigned int RtcpReportBlock::getLossPercentage() const { -- // TODO Implement loss percentages. -- return 0; --} -- --unsigned int RtcpReportBlock::getPacketLostCount() const { -- // TODO Implement total packets lost. -- return 0; --} -- --uint16_t RtcpReportBlock::seqNoCycles() const { return ntohs(_seqNoCycles); } -- --uint16_t RtcpReportBlock::highestSeqNo() const { return ntohs(_highestSeqNo); } -- --uint32_t RtcpReportBlock::jitter() const { return ntohl(_jitter); } -- --uint32_t RtcpReportBlock::delaySinceSR() const { return ntohl(_delaySinceLastReport); } -- --void RtcpReportBlock::setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) { -- _highestSeqNo = htons(highestSeqNo); -- _seqNoCycles = htons(seqNoCycles); --} -- --void RtcpReportBlock::setJitter(uint32_t jitter) { _jitter = htonl(jitter); } -- --void RtcpReportBlock::setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); } -- --uint32_t RtcpReportBlock::getNTPOfSR() const { return ntohl(_lastReport) << 16u; } -- --void RtcpReportBlock::setDelaySinceSR(uint32_t sr) { -- // The delay, expressed in units of 1/65536 seconds -- _delaySinceLastReport = htonl(sr); --} -- --void RtcpReportBlock::log() const { -- PLOG_VERBOSE << "RTCP report block: " -- << "ssrc=" -- << ntohl(_ssrc) -- // TODO: Implement these reports -- // << ", fractionLost=" << fractionLost -- // << ", packetsLost=" << packetsLost -- << ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles() -- << ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR() -- << ", lastSRDelay=" << delaySinceSR(); --} -- --uint8_t RtcpHeader::version() const { return _first >> 6; } -- --bool RtcpHeader::padding() const { return (_first >> 5) & 0x01; } -- --uint8_t RtcpHeader::reportCount() const { return _first & 0x1F; } -- --uint8_t RtcpHeader::payloadType() const { return _payloadType; } -- --uint16_t RtcpHeader::length() const { return ntohs(_length); } -- --size_t RtcpHeader::lengthInBytes() const { return (1 + length()) * 4; } -- --void RtcpHeader::setPayloadType(uint8_t type) { _payloadType = type; } -- --void RtcpHeader::setReportCount(uint8_t count) { -- _first = (_first & 0b11100000u) | (count & 0b00011111u); --} -- --void RtcpHeader::setLength(uint16_t length) { _length = htons(length); } -- --void RtcpHeader::prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) { -- _first = 0b10000000; // version 2, no padding -- setReportCount(reportCount); -- setPayloadType(payloadType); -- setLength(length); --} -- --void RtcpHeader::log() const { -- PLOG_VERBOSE << "RTCP header: " -- << "version=" << unsigned(version()) << ", padding=" << padding() -- << ", reportCount=" << unsigned(reportCount()) -- << ", payloadType=" << unsigned(payloadType()) << ", length=" << length(); --} -- --SSRC RtcpFbHeader::packetSenderSSRC() const { return ntohl(_packetSender); } -- --SSRC RtcpFbHeader::mediaSourceSSRC() const { return ntohl(_mediaSource); } -- --void RtcpFbHeader::setPacketSenderSSRC(SSRC ssrc) { _packetSender = htonl(ssrc); } -- --void RtcpFbHeader::setMediaSourceSSRC(SSRC ssrc) { _mediaSource = htonl(ssrc); } -- --void RtcpFbHeader::log() const { -- header.log(); -- PLOG_VERBOSE << "FB: " -- << " packet sender: " << packetSenderSSRC() -- << " media source: " << mediaSourceSSRC(); --} -- --unsigned int RtcpSr::Size(unsigned int reportCount) { -- return sizeof(RtcpHeader) + 24 + reportCount * sizeof(RtcpReportBlock); --} -- --void RtcpSr::preparePacket(SSRC senderSSRC, uint8_t reportCount) { -- unsigned int length = ((sizeof(header) + 24 + reportCount * sizeof(RtcpReportBlock)) / 4) - 1; -- header.prepareHeader(200, reportCount, uint16_t(length)); -- this->_senderSSRC = htonl(senderSSRC); --} -- --const RtcpReportBlock *RtcpSr::getReportBlock(int num) const { return &_reportBlocks + num; } -- --RtcpReportBlock *RtcpSr::getReportBlock(int num) { return &_reportBlocks + num; } -- --size_t RtcpSr::getSize() const { -- // "length" in packet is one less than the number of 32 bit words in the packet. -- return sizeof(uint32_t) * (1 + size_t(header.length())); --} -- --uint64_t RtcpSr::ntpTimestamp() const { return ntohll(_ntpTimestamp); } --uint32_t RtcpSr::rtpTimestamp() const { return ntohl(_rtpTimestamp); } --uint32_t RtcpSr::packetCount() const { return ntohl(_packetCount); } --uint32_t RtcpSr::octetCount() const { return ntohl(_octetCount); } --uint32_t RtcpSr::senderSSRC() const { return ntohl(_senderSSRC); } -- --void RtcpSr::setNtpTimestamp(uint64_t ts) { _ntpTimestamp = htonll(ts); } --void RtcpSr::setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); } --void RtcpSr::setOctetCount(uint32_t ts) { _octetCount = htonl(ts); } --void RtcpSr::setPacketCount(uint32_t ts) { _packetCount = htonl(ts); } -- --void RtcpSr::log() const { -- header.log(); -- PLOG_VERBOSE << "RTCP SR: " -- << " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp() -- << ", RtpTS=" << rtpTimestamp() << ", packetCount=" << packetCount() -- << ", octetCount=" << octetCount(); -- -- for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { -- getReportBlock(i)->log(); -- } --} -- --unsigned int RtcpSdesItem::Size(uint8_t textLength) { return textLength + 2; } -- --std::string RtcpSdesItem::text() const { return std::string(_text, _length); } -- --void RtcpSdesItem::setText(std::string text) { -- if (text.size() > 0xFF) -- throw std::invalid_argument("text is too long"); -- -- _length = uint8_t(text.size()); -- memcpy(_text, text.data(), text.size()); --} -- --uint8_t RtcpSdesItem::length() const { return _length; } -- --unsigned int RtcpSdesChunk::Size(const std::vector textLengths) { -- unsigned int itemsSize = 0; -- for (auto length : textLengths) { -- itemsSize += RtcpSdesItem::Size(length); -- } -- auto nullTerminatedItemsSize = itemsSize + 1; -- auto words = uint8_t(std::ceil(double(nullTerminatedItemsSize) / 4)) + 1; -- return words * 4; --} -- --SSRC RtcpSdesChunk::ssrc() const { return ntohl(_ssrc); } -- --void RtcpSdesChunk::setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); } -- --const RtcpSdesItem *RtcpSdesChunk::getItem(int num) const { -- auto base = &_items; -- while (num-- > 0) { -- auto itemSize = RtcpSdesItem::Size(base->length()); -- base = reinterpret_cast(reinterpret_cast(base) + -- itemSize); -- } -- return reinterpret_cast(base); --} -- --RtcpSdesItem *RtcpSdesChunk::getItem(int num) { -- auto base = &_items; -- while (num-- > 0) { -- auto itemSize = RtcpSdesItem::Size(base->length()); -- base = reinterpret_cast(reinterpret_cast(base) + itemSize); -- } -- return reinterpret_cast(base); --} -- --unsigned int RtcpSdesChunk::getSize() const { -- std::vector textLengths{}; -- unsigned int i = 0; -- auto item = getItem(i); -- while (item->type != 0) { -- textLengths.push_back(item->length()); -- item = getItem(++i); -- } -- return Size(textLengths); --} -- --long RtcpSdesChunk::safelyCountChunkSize(size_t maxChunkSize) const { -- if (maxChunkSize < RtcpSdesChunk::Size({})) { -- // chunk is truncated -- return -1; -- } -- -- size_t size = sizeof(SSRC); -- unsigned int i = 0; -- // We can always access first 4 bytes of first item (in case of no items there will be 4 -- // null bytes) -- auto item = getItem(i); -- std::vector textsLength{}; -- while (item->type != 0) { -- if (size + RtcpSdesItem::Size(0) > maxChunkSize) { -- // item is too short -- return -1; -- } -- auto itemLength = item->length(); -- if (size + RtcpSdesItem::Size(itemLength) >= maxChunkSize) { -- // item is too large (it can't be equal to chunk size because after item there -- // must be 1-4 null bytes as padding) -- return -1; -- } -- textsLength.push_back(itemLength); -- // safely to access next item -- item = getItem(++i); -- } -- auto realSize = RtcpSdesChunk::Size(textsLength); -- if (realSize > maxChunkSize) { -- // Chunk is too large -- return -1; -- } -- return realSize; --} -- --unsigned int RtcpSdes::Size(const std::vector> lengths) { -- unsigned int chunks_size = 0; -- for (auto length : lengths) -- chunks_size += RtcpSdesChunk::Size(length); -- -- return 4 + chunks_size; --} -- --bool RtcpSdes::isValid() const { -- auto chunksSize = header.lengthInBytes() - sizeof(header); -- if (chunksSize == 0) { -- return true; -- } -- // there is at least one chunk -- unsigned int i = 0; -- unsigned int size = 0; -- while (size < chunksSize) { -- if (chunksSize < size + RtcpSdesChunk::Size({})) { -- // chunk is truncated -- return false; -- } -- auto chunk = getChunk(i++); -- auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size); -- if (chunkSize < 0) { -- // chunk is invalid -- return false; -- } -- size += chunkSize; -- } -- return size == chunksSize; --} -- --unsigned int RtcpSdes::chunksCount() const { -- if (!isValid()) { -- return 0; -- } -- uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header); -- unsigned int size = 0; -- unsigned int i = 0; -- while (size < chunksSize) { -- size += getChunk(i++)->getSize(); -- } -- return i; --} -- --const RtcpSdesChunk *RtcpSdes::getChunk(int num) const { -- auto base = &_chunks; -- while (num-- > 0) { -- auto chunkSize = base->getSize(); -- base = reinterpret_cast(reinterpret_cast(base) + -- chunkSize); -- } -- return reinterpret_cast(base); --} -- --RtcpSdesChunk *RtcpSdes::getChunk(int num) { -- auto base = &_chunks; -- while (num-- > 0) { -- auto chunkSize = base->getSize(); -- base = reinterpret_cast(reinterpret_cast(base) + chunkSize); -- } -- return reinterpret_cast(base); --} -- --void RtcpSdes::preparePacket(uint8_t chunkCount) { -- unsigned int chunkSize = 0; -- for (uint8_t i = 0; i < chunkCount; i++) { -- auto chunk = getChunk(i); -- chunkSize += chunk->getSize(); -- } -- uint16_t length = uint16_t((sizeof(header) + chunkSize) / 4 - 1); -- header.prepareHeader(202, chunkCount, length); --} -- --const RtcpReportBlock *RtcpRr::getReportBlock(int num) const { return &_reportBlocks + num; } -- --RtcpReportBlock *RtcpRr::getReportBlock(int num) { return &_reportBlocks + num; } -- --size_t RtcpRr::SizeWithReportBlocks(uint8_t reportCount) { -- return sizeof(header) + 4 + size_t(reportCount) * sizeof(RtcpReportBlock); --} -- --SSRC RtcpRr::senderSSRC() const { return ntohl(_senderSSRC); } -- --bool RtcpRr::isSenderReport() { return header.payloadType() == 200; } -- --bool RtcpRr::isReceiverReport() { return header.payloadType() == 201; } -- --size_t RtcpRr::getSize() const { -- // "length" in packet is one less than the number of 32 bit words in the packet. -- return sizeof(uint32_t) * (1 + size_t(header.length())); --} -- --void RtcpRr::preparePacket(SSRC senderSSRC, uint8_t reportCount) { -- // "length" in packet is one less than the number of 32 bit words in the packet. -- size_t length = (SizeWithReportBlocks(reportCount) / 4) - 1; -- header.prepareHeader(201, reportCount, uint16_t(length)); -- this->_senderSSRC = htonl(senderSSRC); --} -- --void RtcpRr::setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); } -- --void RtcpRr::log() const { -- header.log(); -- PLOG_VERBOSE << "RTCP RR: " -- << " SSRC=" << ntohl(_senderSSRC); -- -- for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { -- getReportBlock(i)->log(); -- } --} -- --size_t RtcpRemb::SizeWithSSRCs(int count) { return sizeof(RtcpRemb) + (count - 1) * sizeof(SSRC); } -- --unsigned int RtcpRemb::getSize() const { -- // "length" in packet is one less than the number of 32 bit words in the packet. -- return sizeof(uint32_t) * (1 + header.header.length()); --} -- --void RtcpRemb::preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) { -- -- // Report Count becomes the format here. -- header.header.prepareHeader(206, 15, 0); -- -- // Always zero. -- header.setMediaSourceSSRC(0); -- -- header.setPacketSenderSSRC(senderSSRC); -- -- _id[0] = 'R'; -- _id[1] = 'E'; -- _id[2] = 'M'; -- _id[3] = 'B'; -- -- setBitrate(numSSRC, in_bitrate); --} -- --void RtcpRemb::setBitrate(unsigned int numSSRC, unsigned int in_bitrate) { -- unsigned int exp = 0; -- while (in_bitrate > pow(2, 18) - 1) { -- exp++; -- in_bitrate /= 2; -- } -- -- // "length" in packet is one less than the number of 32 bit words in the packet. -- header.header.setLength(uint16_t((offsetof(RtcpRemb, _ssrc) / sizeof(uint32_t)) - 1 + numSSRC)); -- -- _bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate); --} -- --void RtcpRemb::setSsrc(int iterator, SSRC newSssrc) { _ssrc[iterator] = htonl(newSssrc); } -- --unsigned int RtcpPli::Size() { return sizeof(RtcpFbHeader); } -- --void RtcpPli::preparePacket(SSRC messageSSRC) { -- header.header.prepareHeader(206, 1, 2); -- header.setPacketSenderSSRC(messageSSRC); -- header.setMediaSourceSSRC(messageSSRC); --} -- --void RtcpPli::log() const { header.log(); } -- --unsigned int RtcpFir::Size() { return sizeof(RtcpFbHeader) + sizeof(RtcpFirPart); } -- --void RtcpFir::preparePacket(SSRC messageSSRC, uint8_t seqNo) { -- header.header.prepareHeader(206, 4, 2 + 2 * 1); -- header.setPacketSenderSSRC(messageSSRC); -- header.setMediaSourceSSRC(messageSSRC); -- parts[0].ssrc = htonl(messageSSRC); -- parts[0].seqNo = seqNo; --} -- --void RtcpFir::log() const { header.log(); } -- --uint16_t RtcpNackPart::pid() { return ntohs(_pid); } --uint16_t RtcpNackPart::blp() { return ntohs(_blp); } -- --void RtcpNackPart::setPid(uint16_t pid) { _pid = htons(pid); } --void RtcpNackPart::setBlp(uint16_t blp) { _blp = htons(blp); } -- --std::vector RtcpNackPart::getSequenceNumbers() { -- std::vector result{}; -- result.reserve(17); -- uint16_t p = pid(); -- result.push_back(p); -- uint16_t bitmask = blp(); -- uint16_t i = p + 1; -- while (bitmask > 0) { -- if (bitmask & 0x1) { -- result.push_back(i); -- } -- i += 1; -- bitmask >>= 1; -- } -- return result; --} -- --unsigned int RtcpNack::Size(unsigned int discreteSeqNoCount) { -- return offsetof(RtcpNack, parts) + sizeof(RtcpNackPart) * discreteSeqNoCount; --} -- --unsigned int RtcpNack::getSeqNoCount() { return header.header.length() - 2; } -- --void RtcpNack::preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) { -- header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount)); -- header.setMediaSourceSSRC(ssrc); -- header.setPacketSenderSSRC(ssrc); --} -- --bool RtcpNack::addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket) { -- if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) { -- parts[*fciCount].setPid(missingPacket); -- parts[*fciCount].setBlp(0); -- *fciPID = missingPacket; -- (*fciCount)++; -- return true; -- } else { -- // TODO SPEED! -- uint16_t blp = parts[(*fciCount) - 1].blp(); -- uint16_t newBit = uint16_t(1u << (missingPacket - (1 + *fciPID))); -- parts[(*fciCount) - 1].setBlp(blp | newBit); -- return false; -- } --} -- --uint16_t RtpRtx::getOriginalSeqNo() const { return ntohs(*(uint16_t *)(header.getBody())); } -- --const char *RtpRtx::getBody() const { return header.getBody() + sizeof(uint16_t); } -- --char *RtpRtx::getBody() { return header.getBody() + sizeof(uint16_t); } -- --size_t RtpRtx::getBodySize(size_t totalSize) const { -- return totalSize - (getBody() - reinterpret_cast(this)); --} -- --size_t RtpRtx::getSize() const { return header.getSize() + sizeof(uint16_t); } -- --size_t RtpRtx::normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) { -- header.setSeqNumber(getOriginalSeqNo()); -- header.setSsrc(originalSSRC); -- header.setPayloadType(originalPayloadType); -- // TODO, the -12 is the size of the header (which is variable!) -- memmove(header.getBody(), getBody(), totalSize - getSize()); -- return totalSize - 2; --} -- --size_t RtpRtx::copyTo(RtpHeader *dest, size_t totalSize, uint8_t originalPayloadType) { -- memmove((char *)dest, (char *)this, header.getSize()); -- dest->setSeqNumber(getOriginalSeqNo()); -- dest->setPayloadType(originalPayloadType); -- memmove(dest->getBody(), getBody(), getBodySize(totalSize)); -- return totalSize; --} -- --}; // namespace rtc -diff --git a/thirdparty/libdatachannel/src/track.cpp b/thirdparty/libdatachannel/src/track.cpp -deleted file mode 100644 -index 29ab6d24cf..0000000000 ---- a/thirdparty/libdatachannel/src/track.cpp -+++ /dev/null -@@ -1,59 +0,0 @@ --/** -- * Copyright (c) 2020-2021 Paul-Louis Ageneau -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#include "track.hpp" -- --#include "impl/internals.hpp" --#include "impl/track.hpp" -- --namespace rtc { -- --Track::Track(impl_ptr impl) -- : CheshireCat(impl), Channel(std::dynamic_pointer_cast(impl)) {} -- --Track::~Track() {} -- --string Track::mid() const { return impl()->mid(); } -- --Description::Direction Track::direction() const { return impl()->direction(); } -- --Description::Media Track::description() const { return impl()->description(); } -- --void Track::setDescription(Description::Media description) { -- impl()->setDescription(std::move(description)); --} -- --void Track::close() { impl()->close(); } -- --bool Track::send(message_variant data) { return impl()->outgoing(make_message(std::move(data))); } -- --bool Track::send(const byte *data, size_t size) { return send(binary(data, data + size)); } -- --bool Track::isOpen(void) const { return impl()->isOpen(); } -- --bool Track::isClosed(void) const { return impl()->isClosed(); } -- --size_t Track::maxMessageSize() const { return impl()->maxMessageSize(); } -- --void Track::setMediaHandler(shared_ptr handler) { -- impl()->setMediaHandler(std::move(handler)); --} -- --bool Track::requestKeyframe() { -- // only push PLI for video -- if (description().type() == "video") { -- if (auto handler = impl()->getMediaHandler()) { -- return handler->requestKeyframe(); -- } -- } -- return false; --} -- --shared_ptr Track::getMediaHandler() { return impl()->getMediaHandler(); } -- --} // namespace rtc -diff --git a/thirdparty/libdatachannel/src/websocket.cpp b/thirdparty/libdatachannel/src/websocket.cpp -deleted file mode 100644 -index 32458ec64a..0000000000 ---- a/thirdparty/libdatachannel/src/websocket.cpp -+++ /dev/null -@@ -1,73 +0,0 @@ --/** -- * Copyright (c) 2020-2021 Paul-Louis Ageneau -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_WEBSOCKET -- --#include "websocket.hpp" --#include "common.hpp" -- --#include "impl/internals.hpp" --#include "impl/websocket.hpp" -- --namespace rtc { -- --WebSocket::WebSocket() : WebSocket(Configuration()) {} -- --WebSocket::WebSocket(Configuration config) -- : CheshireCat(std::move(config)), -- Channel(std::dynamic_pointer_cast(CheshireCat::impl())) {} -- --WebSocket::WebSocket(impl_ptr impl) -- : CheshireCat(std::move(impl)), -- Channel(std::dynamic_pointer_cast(CheshireCat::impl())) {} -- --WebSocket::~WebSocket() { -- try { -- impl()->remoteClose(); -- impl()->resetCallbacks(); // not done by impl::WebSocket -- } catch (const std::exception &e) { -- PLOG_ERROR << e.what(); -- } --} -- --WebSocket::State WebSocket::readyState() const { return impl()->state; } -- --bool WebSocket::isOpen() const { return impl()->state.load() == State::Open; } -- --bool WebSocket::isClosed() const { return impl()->state.load() == State::Closed; } -- --size_t WebSocket::maxMessageSize() const { return DEFAULT_MAX_MESSAGE_SIZE; } -- --void WebSocket::open(const string &url) { impl()->open(url); } -- --void WebSocket::close() { impl()->close(); } -- --void WebSocket::forceClose() { impl()->remoteClose(); } -- --bool WebSocket::send(message_variant data) { -- return impl()->outgoing(make_message(std::move(data))); --} -- --bool WebSocket::send(const byte *data, size_t size) { -- return impl()->outgoing(make_message(data, data + size, Message::Binary)); --} -- --optional WebSocket::remoteAddress() const { -- auto tcpTransport = impl()->getTcpTransport(); -- return tcpTransport ? make_optional(tcpTransport->remoteAddress()) : nullopt; --} -- --optional WebSocket::path() const { -- auto state = impl()->state.load(); -- auto handshake = impl()->getWsHandshake(); -- return state != State::Connecting && handshake ? make_optional(handshake->path()) : nullopt; --} -- --} // namespace rtc -- --#endif -diff --git a/thirdparty/libdatachannel/src/websocketserver.cpp b/thirdparty/libdatachannel/src/websocketserver.cpp -deleted file mode 100644 -index 5e1f6340f5..0000000000 ---- a/thirdparty/libdatachannel/src/websocketserver.cpp -+++ /dev/null -@@ -1,36 +0,0 @@ --/** -- * Copyright (c) 2021 Paul-Louis Ageneau -- * -- * This Source Code Form is subject to the terms of the Mozilla Public -- * License, v. 2.0. If a copy of the MPL was not distributed with this -- * file, You can obtain one at https://mozilla.org/MPL/2.0/. -- */ -- --#if RTC_ENABLE_WEBSOCKET -- --#include "websocketserver.hpp" --#include "common.hpp" -- --#include "impl/internals.hpp" --#include "impl/websocketserver.hpp" -- --namespace rtc { -- --WebSocketServer::WebSocketServer() : WebSocketServer(Configuration()) {} -- --WebSocketServer::WebSocketServer(Configuration config) -- : CheshireCat(std::move(config)) {} -- --WebSocketServer::~WebSocketServer() { impl()->stop(); } -- --void WebSocketServer::stop() { impl()->stop(); } -- --uint16_t WebSocketServer::port() const { return impl()->tcpServer->port(); } -- --void WebSocketServer::onClient(std::function)> callback) { -- impl()->clientCallback = callback; --} -- --} // namespace rtc -- --#endif diff --git a/godot/thirdparty/libdatachannel/patches/fix_mingw.patch b/godot/thirdparty/libdatachannel/patches/fix_mingw.patch deleted file mode 100644 index 462f53ee..00000000 --- a/godot/thirdparty/libdatachannel/patches/fix_mingw.patch +++ /dev/null @@ -1,43 +0,0 @@ -commit df6f495677fd09a749f061196e74d57a94621135 -Author: K. S. Ernest (iFire) Lee -Date: Tue Sep 26 20:26:17 2023 -0700 - - Try to fix llvm-mingw. - -diff --git a/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h b/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h -index a545accba0..4aa35201d5 100644 ---- a/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h -+++ b/thirdparty/libdatachannel/deps/usrsctp/usrsctplib/user_environment.h -@@ -62,7 +62,7 @@ extern int ipport_firstauto, ipport_lastauto; - */ - extern int nmbclusters; - --#if !defined(_MSC_VER) && !defined(__MINGW32__) -+#if !defined(_MSC_VER) - #define min(a,b) (((a)>(b))?(b):(a)) - #define max(a,b) (((a)>(b))?(a):(b)) - #endif -diff --git a/thirdparty/libdatachannel/src/impl/certificate.cpp b/thirdparty/libdatachannel/src/impl/certificate.cpp -index eb4c419c86..00b3544943 100644 ---- a/thirdparty/libdatachannel/src/impl/certificate.cpp -+++ b/thirdparty/libdatachannel/src/impl/certificate.cpp -@@ -11,6 +11,7 @@ - - #include - #include -+#include - #include - #include - #include -diff --git a/thirdparty/libdatachannel/src/impl/icetransport.cpp b/thirdparty/libdatachannel/src/impl/icetransport.cpp -index 3a19e92ac6..2057c1b4fc 100644 ---- a/thirdparty/libdatachannel/src/impl/icetransport.cpp -+++ b/thirdparty/libdatachannel/src/impl/icetransport.cpp -@@ -12,6 +12,7 @@ - #include "transport.hpp" - #include "utils.hpp" - -+#include - #include - #include - #include diff --git a/godot/thirdparty/libdatachannel/patches/mbedtls_optional_apis.patch b/godot/thirdparty/libdatachannel/patches/mbedtls_optional_apis.patch deleted file mode 100644 index 2f8c2352..00000000 --- a/godot/thirdparty/libdatachannel/patches/mbedtls_optional_apis.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/thirdparty/libdatachannel/src/impl/tls.cpp b/thirdparty/libdatachannel/src/impl/tls.cpp -index 650f90743b..4ea7d89cc0 100644 ---- a/thirdparty/libdatachannel/src/impl/tls.cpp -+++ b/thirdparty/libdatachannel/src/impl/tls.cpp -@@ -104,10 +104,10 @@ bool check(int ret, const string &message) { - ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) - return false; - -- const size_t bufferSize = 1024; -- char buffer[bufferSize]; -- mbedtls_strerror(ret, reinterpret_cast(buffer), bufferSize); -- throw std::runtime_error(message + ": " + std::string(buffer)); -+ // const size_t bufferSize = 1024; -+ // char buffer[bufferSize]; -+ // mbedtls_strerror(ret, reinterpret_cast(buffer), bufferSize); -+ throw std::runtime_error(message + ": Error " + std::to_string(ret)); - } - return true; - } -diff --git a/thirdparty/libdatachannel/src/impl/dtlstransport.cpp b/thirdparty/libdatachannel/src/impl/dtlstransport.cpp -index 3779c5671e..a0d6e69a64 100644 ---- a/thirdparty/libdatachannel/src/impl/dtlstransport.cpp -+++ b/thirdparty/libdatachannel/src/impl/dtlstransport.cpp -@@ -367,10 +367,12 @@ - - #elif USE_MBEDTLS - -+#if RTC_ENABLE_MEDIA // Godot added - const mbedtls_ssl_srtp_profile srtpSupportedProtectionProfiles[] = { - MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80, - MBEDTLS_TLS_SRTP_UNSET, - }; -+#endif // RTC_ENABLE_MEDIA - - DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate, - optional mtu, verifier_callback verifierCallback, -@@ -409,7 +411,9 @@ - "Failed creating Mbed TLS Context"); - - mbedtls_ssl_conf_dtls_cookies(&mConf, NULL, NULL, NULL); -+#if RTC_ENABLE_MEDIA // Godot added - mbedtls_ssl_conf_dtls_srtp_protection_profiles(&mConf, srtpSupportedProtectionProfiles); -+#endif // RTC_ENABLE_MEDIA - - mbedtls::check(mbedtls_ssl_setup(&mSsl, &mConf), "Failed creating Mbed TLS Context"); - diff --git a/godot/thirdparty/libdatachannel/patches/virtual_destructor.patch b/godot/thirdparty/libdatachannel/patches/virtual_destructor.patch deleted file mode 100644 index c2599cee..00000000 --- a/godot/thirdparty/libdatachannel/patches/virtual_destructor.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff --git a/thirdparty/libdatachannel/include/rtc/mediahandler.hpp b/thirdparty/libdatachannel/include/rtc/mediahandler.hpp -index 4dbc717a08..24c602e11b 100644 ---- a/thirdparty/libdatachannel/include/rtc/mediahandler.hpp -+++ b/thirdparty/libdatachannel/include/rtc/mediahandler.hpp -@@ -21,6 +21,8 @@ protected: - synchronized_callback outgoingCallback; - - public: -+ virtual ~MediaHandler() = default; -+ - // Called when there is traffic coming from the peer - virtual message_ptr incoming(message_ptr ptr) = 0; - -diff --git a/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp b/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp -index bead429e89..600bf23384 100644 ---- a/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp -+++ b/thirdparty/libdatachannel/include/rtc/mediahandlerelement.hpp -@@ -60,6 +60,8 @@ class RTC_CPP_EXPORT MediaHandlerElement - public: - MediaHandlerElement(); - -+ virtual ~MediaHandlerElement() = default; -+ - /// Creates response to incoming message - /// @param messages Current repsonse - /// @returns New response -diff --git a/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp b/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp -index cf096e9d17..f28afd5038 100644 ---- a/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp -+++ b/thirdparty/libdatachannel/include/rtc/rtppacketizer.hpp -@@ -22,6 +22,8 @@ class RTC_CPP_EXPORT RtpPacketizer { - static const auto rtpExtHeaderCvoSize = 8; - - public: -+ virtual ~RtpPacketizer() = default; -+ - // RTP configuration - const shared_ptr rtpConfig; - diff --git a/godot/thirdparty/libdatachannel/src/candidate.cpp b/godot/thirdparty/libdatachannel/src/candidate.cpp deleted file mode 100644 index d5ae9e69..00000000 --- a/godot/thirdparty/libdatachannel/src/candidate.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "candidate.hpp" - -#include "impl/internals.hpp" - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#endif - -#include - -using std::array; -using std::string; - -namespace { - -inline bool match_prefix(const string &str, const string &prefix) { - return str.size() >= prefix.size() && - std::mismatch(prefix.begin(), prefix.end(), str.begin()).first == prefix.end(); -} - -inline void trim_begin(string &str) { - str.erase(str.begin(), - std::find_if(str.begin(), str.end(), [](char c) { return !std::isspace(c); })); -} - -inline void trim_end(string &str) { - str.erase( - std::find_if(str.rbegin(), str.rend(), [](char c) { return !std::isspace(c); }).base(), - str.end()); -} - -} // namespace - -namespace rtc { - -Candidate::Candidate() - : mFoundation("none"), mComponent(0), mPriority(0), mTypeString("unknown"), - mTransportString("unknown"), mType(Type::Unknown), mTransportType(TransportType::Unknown), - mNode("0.0.0.0"), mService("9"), mFamily(Family::Unresolved), mPort(0) {} - -RTC_WRAPPED(Candidate) Candidate::create(string candidate) { - RTC_BEGIN; - Candidate ret; - if (!candidate.empty()) { - RTC_UNWRAP_RETHROW(ret.parse(std::move(candidate))); - } - return ret; -} - -RTC_WRAPPED(Candidate) Candidate::create(string candidate, string mid) { - RTC_BEGIN; - Candidate ret; - if (!candidate.empty()) { - RTC_UNWRAP_RETHROW(ret.parse(std::move(candidate))); - } - if (!mid.empty()) - ret.mMid.emplace(std::move(mid)); - return ret; -} - -RTC_WRAPPED(void) Candidate::parse(string candidate) { - using TypeMap_t = std::unordered_map; - using TcpTypeMap_t = std::unordered_map; - - static const TypeMap_t TypeMap = {{"host", Type::Host}, - {"srflx", Type::ServerReflexive}, - {"prflx", Type::PeerReflexive}, - {"relay", Type::Relayed}}; - - static const TcpTypeMap_t TcpTypeMap = {{"active", TransportType::TcpActive}, - {"passive", TransportType::TcpPassive}, - {"so", TransportType::TcpSo}}; - - const std::array prefixes{"a=", "candidate:"}; - for (string prefix : prefixes) - if (match_prefix(candidate, prefix)) - candidate.erase(0, prefix.size()); - - PLOG_VERBOSE << "Parsing candidate: " << candidate; - - // See RFC 8445 for format - std::istringstream iss(candidate); - string typ_; - if (!(iss >> mFoundation >> mComponent >> mTransportString >> mPriority && - iss >> mNode >> mService >> typ_ >> mTypeString && typ_ == "typ")) { - PLOG_ERROR << "Invalid candidate format"; - mType = Type::Unknown; - RTC_RET; - } - - std::getline(iss, mTail); - trim_begin(mTail); - trim_end(mTail); - - if (auto it = TypeMap.find(mTypeString); it != TypeMap.end()) - mType = it->second; - else - mType = Type::Unknown; - - if (mTransportString == "UDP" || mTransportString == "udp") { - mTransportType = TransportType::Udp; - } else if (mTransportString == "TCP" || mTransportString == "tcp") { - // Peek tail to find TCP type - std::istringstream tiss(mTail); - string tcptype_, tcptype; - if (tiss >> tcptype_ >> tcptype && tcptype_ == "tcptype") { - if (auto it = TcpTypeMap.find(tcptype); it != TcpTypeMap.end()) - mTransportType = it->second; - else - mTransportType = TransportType::TcpUnknown; - - } else { - mTransportType = TransportType::TcpUnknown; - } - } else { - mTransportType = TransportType::Unknown; - } - return RTC_VOID; -} - -void Candidate::hintMid(string mid) { - if (!mMid) - mMid.emplace(std::move(mid)); -} - -RTC_WRAPPED(void) Candidate::changeAddress(string addr) { - RTC_BEGIN; - RTC_UNWRAP_RETHROW(changeAddress(std::move(addr), mService)); - return RTC_VOID; -} - -RTC_WRAPPED(void) Candidate::changeAddress(string addr, uint16_t port) { - RTC_BEGIN; - RTC_UNWRAP_RETHROW(changeAddress(std::move(addr), std::to_string(port))); - return RTC_VOID; -} - -RTC_WRAPPED(void) Candidate::changeAddress(string addr, string service) { - mNode = std::move(addr); - mService = std::move(service); - - mFamily = Family::Unresolved; - mAddress.clear(); - mPort = 0; - - if (!resolve(ResolveMode::Simple)) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid candidate address \"" + addr + ":" + service + "\""); - RTC_RET; -} - -bool Candidate::resolve(ResolveMode mode) { - PLOG_VERBOSE << "Resolving candidate (mode=" - << (mode == ResolveMode::Simple ? "simple" : "lookup") << "): " << mNode << ' ' - << mService; - - // Try to resolve the node and service - struct addrinfo hints = {}; - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_ADDRCONFIG; - if (mTransportType == TransportType::Udp) { - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - } else if (mTransportType != TransportType::Unknown) { - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - } - - if (mode == ResolveMode::Simple) - hints.ai_flags |= AI_NUMERICHOST; - - struct addrinfo *result = nullptr; - if (getaddrinfo(mNode.c_str(), mService.c_str(), &hints, &result) == 0) { - for (auto p = result; p; p = p->ai_next) { - if (p->ai_family == AF_INET || p->ai_family == AF_INET6) { - char nodebuffer[MAX_NUMERICNODE_LEN]; - char servbuffer[MAX_NUMERICSERV_LEN]; - if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer, - MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN, - NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - RTC_TRY { - mPort = uint16_t(std::stoul(servbuffer)); - } RTC_CATCH (...) { - return false; - } - mAddress = nodebuffer; - mFamily = p->ai_family == AF_INET6 ? Family::Ipv6 : Family::Ipv4; - PLOG_VERBOSE << "Resolved candidate: " << mAddress << ' ' << mPort; - break; - } - } - } - - freeaddrinfo(result); - } - - return mFamily != Family::Unresolved; -} - -Candidate::Type Candidate::type() const { return mType; } - -Candidate::TransportType Candidate::transportType() const { return mTransportType; } - -uint32_t Candidate::priority() const { return mPriority; } - -string Candidate::candidate() const { - const char sp{' '}; - std::ostringstream oss; - oss << "candidate:"; - oss << mFoundation << sp << mComponent << sp << mTransportString << sp << mPriority << sp; - if (isResolved()) - oss << mAddress << sp << mPort; - else - oss << mNode << sp << mService; - - oss << sp << "typ" << sp << mTypeString; - - if (!mTail.empty()) - oss << sp << mTail; - - return oss.str(); -} - -string Candidate::mid() const { return mMid.value_or("0"); } - -Candidate::operator string() const { - std::ostringstream line; - line << "a=" << candidate(); - return line.str(); -} - -bool Candidate::operator==(const Candidate &other) const { - return (mFoundation == other.mFoundation && mService == other.mService && mNode == other.mNode); -} - -bool Candidate::operator!=(const Candidate &other) const { - return mFoundation != other.mFoundation; -} - -bool Candidate::isResolved() const { return mFamily != Family::Unresolved; } - -Candidate::Family Candidate::family() const { return mFamily; } - -optional Candidate::address() const { - return isResolved() ? std::make_optional(mAddress) : nullopt; -} - -optional Candidate::port() const { - return isResolved() ? std::make_optional(mPort) : nullopt; -} - -} // namespace rtc - -std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate) { - return out << std::string(candidate); -} - -std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type) { - switch (type) { - case rtc::Candidate::Type::Host: - return out << "host"; - case rtc::Candidate::Type::PeerReflexive: - return out << "prflx"; - case rtc::Candidate::Type::ServerReflexive: - return out << "srflx"; - case rtc::Candidate::Type::Relayed: - return out << "relay"; - default: - return out << "unknown"; - } -} - -std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType) { - switch (transportType) { - case rtc::Candidate::TransportType::Udp: - return out << "UDP"; - case rtc::Candidate::TransportType::TcpActive: - return out << "TCP_active"; - case rtc::Candidate::TransportType::TcpPassive: - return out << "TCP_passive"; - case rtc::Candidate::TransportType::TcpSo: - return out << "TCP_so"; - case rtc::Candidate::TransportType::TcpUnknown: - return out << "TCP_unknown"; - default: - return out << "unknown"; - } -} diff --git a/godot/thirdparty/libdatachannel/src/channel.cpp b/godot/thirdparty/libdatachannel/src/channel.cpp deleted file mode 100644 index 7173b08c..00000000 --- a/godot/thirdparty/libdatachannel/src/channel.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "channel.hpp" - -#include "impl/channel.hpp" -#include "impl/internals.hpp" - -namespace rtc { - -Channel::~Channel() { impl()->resetCallbacks(); } - -Channel::Channel(impl_ptr impl) : CheshireCat(std::move(impl)) {} - -size_t Channel::maxMessageSize() const { return DEFAULT_MAX_MESSAGE_SIZE; } - -size_t Channel::bufferedAmount() const { return impl()->bufferedAmount; } - -void Channel::onOpen(std::function callback) { impl()->openCallback = callback; } - -void Channel::onClosed(std::function callback) { impl()->closedCallback = callback; } - -void Channel::onError(std::function callback) { - impl()->errorCallback = callback; -} - -void Channel::onMessage(std::function callback) { - impl()->messageCallback = callback; - impl()->flushPendingMessages(); -} - -void Channel::onMessage(std::function binaryCallback, - std::function stringCallback) { - onMessage([binaryCallback, stringCallback](variant data) { - std::visit(overloaded{binaryCallback, stringCallback}, std::move(data)); - }); -} - -void Channel::onBufferedAmountLow(std::function callback) { - impl()->bufferedAmountLowCallback = callback; -} - -void Channel::setBufferedAmountLowThreshold(size_t amount) { - impl()->bufferedAmountLowThreshold = amount; -} - -void Channel::resetCallbacks() { impl()->resetCallbacks(); } - -optional Channel::receive() { return impl()->receive(); } - -optional Channel::peek() { return impl()->peek(); } - -size_t Channel::availableAmount() const { return impl()->availableAmount(); } - -void Channel::onAvailable(std::function callback) { impl()->availableCallback = callback; } - -} // namespace rtc diff --git a/godot/thirdparty/libdatachannel/src/configuration.cpp b/godot/thirdparty/libdatachannel/src/configuration.cpp deleted file mode 100644 index 6b576bc1..00000000 --- a/godot/thirdparty/libdatachannel/src/configuration.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "configuration.hpp" -#include "rtp.hpp" - -#include "impl/internals.hpp" -#include "impl/utils.hpp" - -#include -#include -#include - -namespace { - -bool parse_url(const std::string &url, std::vector> &result) { - // Modified regex from RFC 3986, see https://www.rfc-editor.org/rfc/rfc3986.html#appendix-B - static const char *rs = - R"(^(([^:.@/?#]+):)?(/{0,2}((([^:@]*)(:([^@]*))?)@)?(([^:/?#]*)(:([^/?#]*))?))?([^?#]*)(\?([^#]*))?(#(.*))?)"; - static const std::regex r(rs, std::regex::extended); - - std::smatch m; - if (!std::regex_match(url, m, r) || m[10].length() == 0) - return false; - - result.resize(m.size()); - std::transform(m.begin(), m.end(), result.begin(), [](const auto &sm) { - return sm.length() > 0 ? std::make_optional(std::string(sm)) : std::nullopt; - }); - - assert(result.size() == 18); - return true; -} - -} // namespace - -namespace rtc { - -namespace utils = impl::utils; - -IceServer::IceServer(const string &url) { - std::vector> opt; - if (!parse_url(url, opt)) { - PLOG_WARNING << "Invalid ICE server URL: " << url; - return; - } - - string scheme = opt[2].value_or("stun"); - relayType = RelayType::TurnUdp; - if (scheme == "stun" || scheme == "STUN") - type = Type::Stun; - else if (scheme == "turn" || scheme == "TURN") - type = Type::Turn; - else if (scheme == "turns" || scheme == "TURNS") { - type = Type::Turn; - relayType = RelayType::TurnTls; - } else { - type = Type::Turn; - PLOG_WARNING << "Unknown ICE server protocol: " << scheme; - } - - if (auto &query = opt[15]) { - if (query->find("transport=udp") != string::npos) - relayType = RelayType::TurnUdp; - if (query->find("transport=tcp") != string::npos) - relayType = RelayType::TurnTcp; - if (query->find("transport=tls") != string::npos) - relayType = RelayType::TurnTls; - } - - username = utils::url_decode(opt[6].value_or("")); - password = utils::url_decode(opt[8].value_or("")); - - hostname = opt[10].value(); - if (hostname.front() == '[' && hostname.back() == ']') { - // IPv6 literal - hostname.erase(hostname.begin()); - hostname.pop_back(); - } else { - hostname = utils::url_decode(hostname); - } - - string service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478"); - { - port = uint16_t(std::strtoul(service.c_str(), nullptr, 10)); - } - if (port == 0) { - PLOG_WARNING << "Invalid ICE server port in URL: " << service; - } -} - -IceServer::IceServer(string hostname_, uint16_t port_) - : hostname(std::move(hostname_)), port(port_), type(Type::Stun) {} - -IceServer::IceServer(string hostname_, string service_) - : hostname(std::move(hostname_)), type(Type::Stun) { - { - port = uint16_t(std::strtoul(service_.c_str(), nullptr, 10)); - } - if (port == 0) { - PLOG_WARNING << "Invalid ICE server port: " << service_; - } -} - -IceServer::IceServer(string hostname_, uint16_t port_, string username_, string password_, - RelayType relayType_) - : hostname(std::move(hostname_)), port(port_), type(Type::Turn), username(std::move(username_)), - password(std::move(password_)), relayType(relayType_) {} - -IceServer::IceServer(string hostname_, string service_, string username_, string password_, - RelayType relayType_) - : hostname(std::move(hostname_)), type(Type::Turn), username(std::move(username_)), - password(std::move(password_)), relayType(relayType_) { - { - port = uint16_t(std::strtoul(service_.c_str(), nullptr, 10)); - } - if (port == 0) { - PLOG_WARNING << "Invalid ICE server port : " << service_; - } -} - -ProxyServer::ProxyServer(const string &url) { - std::vector> opt; - if (!parse_url(url, opt)) { - PLOG_WARNING << "Invalid proxy server URL: " << url; - return; - } - - string scheme = opt[2].value_or("http"); - if (scheme == "http" || scheme == "HTTP") - type = Type::Http; - else if (scheme == "socks5" || scheme == "SOCKS5") - type = Type::Socks5; - else { - type = Type::Http; - PLOG_WARNING << "Unknown proxy server protocol: " << scheme; - } - - username = opt[6]; - password = opt[8]; - - hostname = opt[10].value(); - while (!hostname.empty() && hostname.front() == '[') - hostname.erase(hostname.begin()); - while (!hostname.empty() && hostname.back() == ']') - hostname.pop_back(); - - string service = opt[12].value_or(type == Type::Socks5 ? "1080" : "3128"); - { - port = uint16_t(std::strtoul(service.c_str(), nullptr, 10)); - } - if (port == 0) { - PLOG_WARNING << "Invalid proxy server port in URL: " << service; - } -} - -ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_) - : type(type_), hostname(std::move(hostname_)), port(port_) {} - -ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_, string username_, - string password_) - : type(type_), hostname(std::move(hostname_)), port(port_), username(std::move(username_)), - password(std::move(password_)) {} - -} // namespace rtc diff --git a/godot/thirdparty/libdatachannel/src/datachannel.cpp b/godot/thirdparty/libdatachannel/src/datachannel.cpp deleted file mode 100644 index a80a5af1..00000000 --- a/godot/thirdparty/libdatachannel/src/datachannel.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "datachannel.hpp" -#include "common.hpp" -#include "peerconnection.hpp" - -#include "impl/datachannel.hpp" -#include "impl/internals.hpp" -#include "impl/peerconnection.hpp" - -#ifdef _WIN32 -#include -#else -#include -#endif - -namespace rtc { - -DataChannel::DataChannel(impl_ptr impl) - : CheshireCat(impl), - Channel(std::dynamic_pointer_cast(impl)) {} - -DataChannel::~DataChannel() {} - -void DataChannel::close() { return impl()->close(); } - -optional DataChannel::stream() const { return impl()->stream(); } - -optional DataChannel::id() const { return impl()->stream(); } - -string DataChannel::label() const { return impl()->label(); } - -string DataChannel::protocol() const { return impl()->protocol(); } - -Reliability DataChannel::reliability() const { return impl()->reliability(); } - -bool DataChannel::isOpen(void) const { return impl()->isOpen(); } - -bool DataChannel::isClosed(void) const { return impl()->isClosed(); } - -size_t DataChannel::maxMessageSize() const { return impl()->maxMessageSize(); } - -RTC_WRAPPED(bool) DataChannel::send(message_variant data) { - return impl()->outgoing(make_message(std::move(data))); -} - -RTC_WRAPPED(bool) DataChannel::send(const byte *data, size_t size) { - return impl()->outgoing(std::make_shared(data, data + size, Message::Binary)); -} - -} // namespace rtc diff --git a/godot/thirdparty/libdatachannel/src/description.cpp b/godot/thirdparty/libdatachannel/src/description.cpp deleted file mode 100644 index 2fbc3312..00000000 --- a/godot/thirdparty/libdatachannel/src/description.cpp +++ /dev/null @@ -1,1345 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * Copyright (c) 2020 Staz Modrzynski - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "description.hpp" - -#include "impl/internals.hpp" -#include "impl/utils.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -using std::chrono::system_clock; - -namespace { - -using std::string; -using std::string_view; - -inline bool match_prefix(string_view str, string_view prefix) { - return str.size() >= prefix.size() && - std::mismatch(prefix.begin(), prefix.end(), str.begin()).first == prefix.end(); -} - -inline void trim_begin(string &str) { - str.erase(str.begin(), - std::find_if(str.begin(), str.end(), [](char c) { return !std::isspace(c); })); -} - -inline void trim_end(string &str) { - str.erase( - std::find_if(str.rbegin(), str.rend(), [](char c) { return !std::isspace(c); }).base(), - str.end()); -} - -inline std::pair parse_pair(string_view attr) { - string_view key, value; - if (size_t separator = attr.find(':'); separator != string::npos) { - key = attr.substr(0, separator); - value = attr.substr(separator + 1); - } else { - key = attr; - } - return std::make_pair(std::move(key), std::move(value)); -} - -template RTC_WRAPPED(T) to_integer(string_view s) { - const string str(s); - char *p; - T ret = std::is_signed::value ? T(strtol(str.c_str(), &p, 10)) : T(strtoul(str.c_str(), &p, 10)); - if (*p == 0) { - RTC_THROW RTC_INVALID_ARGUMENT("Invalid integer \"" + str + "\" in description"); - } - return ret; -} - -inline bool is_sha256_fingerprint(string_view f) { - if (f.size() != 32 * 3 - 1) - return false; - - for (size_t i = 0; i < f.size(); ++i) { - if (i % 3 == 2) { - if (f[i] != ':') - return false; - } else { - if (!std::isxdigit(f[i])) - return false; - } - } - return true; -} - -} // namespace - -namespace rtc { - -namespace utils = impl::utils; - -Description::Description(Type type, Role role) - : mType(Type::Unspec), mRole(role) { -} -RTC_WRAPPED(Description) Description::create(const string &sdp, Type type, Role role) { - RTC_BEGIN; - Description ret(type, role); - ret.hintType(type); - - int index = -1; - shared_ptr current; - std::istringstream ss(sdp); - while (ss) { - string line; - std::getline(ss, line); - trim_end(line); - if (line.empty()) - continue; - - if (match_prefix(line, "m=")) { // Media description line (aka m-line) - current = ret.createEntry(line.substr(2), std::to_string(++index), Direction::Unknown); - - } else if (match_prefix(line, "o=")) { // Origin line - std::istringstream origin(line.substr(2)); - origin >> ret.mUsername >> ret.mSessionId; - - } else if (match_prefix(line, "a=")) { // Attribute line - string attr = line.substr(2); - auto [key, value] = parse_pair(attr); - - if (key == "setup") { - if (value == "active") - ret.mRole = Role::Active; - else if (value == "passive") - ret.mRole = Role::Passive; - else - ret.mRole = Role::ActPass; - - } else if (key == "fingerprint") { - if (match_prefix(value, "sha-256 ") || match_prefix(value, "SHA-256 ")) { - string fingerprint{value.substr(8)}; - trim_begin(fingerprint); - RTC_UNWRAP_RETHROW(ret.setFingerprint(std::move(fingerprint))); - } else { - PLOG_WARNING << "Unknown SDP fingerprint format: " << value; - } - } else if (key == "ice-ufrag") { - ret.mIceUfrag = value; - } else if (key == "ice-pwd") { - ret.mIcePwd = value; - } else if (key == "ice-options") { - ret.mIceOptions = utils::explode(string(value), ','); - } else if (key == "candidate") { - RTC_UNWRAP_RETHROW_DECL(Candidate, tmp, Candidate::create(attr, ret.bundleMid())); - ret.addCandidate(tmp); - } else if (key == "end-of-candidates") { - ret.mEnded = true; - } else if (current) { - RTC_UNWRAP_RETHROW(current->parseSdpLine(std::move(line))); - } else { - ret.mAttributes.emplace_back(attr); - } - - } else if (current) { - RTC_UNWRAP_RETHROW(current->parseSdpLine(std::move(line))); - } - } - - if (ret.mUsername.empty()) - ret.mUsername = "rtc"; - - if (ret.mSessionId.empty()) { - auto uniform = std::bind(std::uniform_int_distribution(), utils::random_engine()); - ret.mSessionId = std::to_string(uniform()); - } - return ret; -} - -RTC_WRAPPED(Description) Description::create(const string &sdp, string typeString) { - return create(sdp, !typeString.empty() ? stringToType(typeString) : Type::Unspec, - Role::ActPass); -} - -Description::Type Description::type() const { return mType; } - -string Description::typeString() const { return typeToString(mType); } - -Description::Role Description::role() const { return mRole; } - -string Description::bundleMid() const { - // Get the mid of the first non-removed media - for (const auto &entry : mEntries) - if (!entry->isRemoved()) - return entry->mid(); - - return "0"; -} - -optional Description::iceUfrag() const { return mIceUfrag; } - -std::vector Description::iceOptions() const { return mIceOptions; } - -optional Description::icePwd() const { return mIcePwd; } - -optional Description::fingerprint() const { return mFingerprint; } - -bool Description::ended() const { return mEnded; } - -void Description::hintType(Type type) { - if (mType == Type::Unspec) - mType = type; -} - -RTC_WRAPPED(void) Description::setFingerprint(string fingerprint) { - if (!is_sha256_fingerprint(fingerprint)) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid SHA256 fingerprint \"" + fingerprint + "\""); - - std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(), - [](char c) { return char(std::toupper(c)); }); - mFingerprint.emplace(std::move(fingerprint)); - RTC_RET; -} - -void Description::addIceOption(string option) { - if (std::find(mIceOptions.begin(), mIceOptions.end(), option) == mIceOptions.end()) - mIceOptions.emplace_back(std::move(option)); -} - -void Description::removeIceOption(const string &option) { - mIceOptions.erase(std::remove(mIceOptions.begin(), mIceOptions.end(), option), - mIceOptions.end()); -} - -std::vector Description::Entry::attributes() const { return mAttributes; } - -void Description::Entry::addAttribute(string attr) { - if (std::find(mAttributes.begin(), mAttributes.end(), attr) == mAttributes.end()) - mAttributes.emplace_back(std::move(attr)); -} - -void Description::Entry::removeAttribute(const string &attr) { - mAttributes.erase( - std::remove_if(mAttributes.begin(), mAttributes.end(), - [&](const auto &a) { return a == attr || parse_pair(a).first == attr; }), - mAttributes.end()); -} - -std::vector Description::candidates() const { return mCandidates; } - -std::vector Description::extractCandidates() { - std::vector result; - std::swap(mCandidates, result); - mEnded = false; - return result; -} - -bool Description::hasCandidate(const Candidate &candidate) const { - return std::find(mCandidates.begin(), mCandidates.end(), candidate) != mCandidates.end(); -} - -void Description::addCandidate(Candidate candidate) { - candidate.hintMid(bundleMid()); - - if (!hasCandidate(candidate)) - mCandidates.emplace_back(std::move(candidate)); -} - -void Description::addCandidates(std::vector candidates) { - for (Candidate candidate : candidates) - addCandidate(std::move(candidate)); -} - -void Description::endCandidates() { mEnded = true; } - -Description::operator string() const { return generateSdp("\r\n"); } - -string Description::generateSdp(string_view eol) const { - std::ostringstream sdp; - - // Header - sdp << "v=0" << eol; - sdp << "o=" << mUsername << " " << mSessionId << " 0 IN IP4 127.0.0.1" << eol; - sdp << "s=-" << eol; - sdp << "t=0 0" << eol; - - // BUNDLE (RFC 8843 Negotiating Media Multiplexing Using the Session Description Protocol) - // https://www.rfc-editor.org/rfc/rfc8843.html - std::ostringstream bundleGroup; - for (const auto &entry : mEntries) - if (!entry->isRemoved()) - bundleGroup << ' ' << entry->mid(); - - if (!bundleGroup.str().empty()) - sdp << "a=group:BUNDLE" << bundleGroup.str() << eol; - - // Lip-sync - std::ostringstream lsGroup; - for (const auto &entry : mEntries) - if (!entry->isRemoved() && entry != mApplication) - lsGroup << ' ' << entry->mid(); - - if (!lsGroup.str().empty()) - sdp << "a=group:LS" << lsGroup.str() << eol; - - // Session-level attributes - sdp << "a=msid-semantic:WMS *" << eol; - sdp << "a=setup:" << mRole << eol; - - if (mIceUfrag) - sdp << "a=ice-ufrag:" << *mIceUfrag << eol; - if (mIcePwd) - sdp << "a=ice-pwd:" << *mIcePwd << eol; - if (!mIceOptions.empty()) - sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol; - if (mFingerprint) - sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol; - - for (const auto &attr : mAttributes) - sdp << "a=" << attr << eol; - - auto cand = defaultCandidate(); - const string addr = cand && cand->isResolved() - ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") + - " " + *cand->address()) - : "IP4 0.0.0.0"; - const uint16_t port = - cand && cand->isResolved() ? *cand->port() : 9; // Port 9 is the discard protocol - - // Entries - bool first = true; - for (const auto &entry : mEntries) { - sdp << entry->generateSdp(eol, addr, port); - - if (!entry->isRemoved() && std::exchange(first, false)) { - // Candidates - for (const auto &candidate : mCandidates) - sdp << string(candidate) << eol; - - if (mEnded) - sdp << "a=end-of-candidates" << eol; - } - } - - return sdp.str(); -} - -string Description::generateApplicationSdp(string_view eol) const { - std::ostringstream sdp; - - // Header - sdp << "v=0" << eol; - sdp << "o=" << mUsername << " " << mSessionId << " 0 IN IP4 127.0.0.1" << eol; - sdp << "s=-" << eol; - sdp << "t=0 0" << eol; - - auto cand = defaultCandidate(); - const string addr = cand && cand->isResolved() - ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") + - " " + *cand->address()) - : "IP4 0.0.0.0"; - const uint16_t port = - cand && cand->isResolved() ? *cand->port() : 9; // Port 9 is the discard protocol - - // Application - auto app = mApplication ? mApplication : std::make_shared(); - sdp << app->generateSdp(eol, addr, port); - - // Session-level attributes - sdp << "a=msid-semantic:WMS *" << eol; - sdp << "a=setup:" << mRole << eol; - - if (mIceUfrag) - sdp << "a=ice-ufrag:" << *mIceUfrag << eol; - if (mIcePwd) - sdp << "a=ice-pwd:" << *mIcePwd << eol; - if (!mIceOptions.empty()) - sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol; - if (mFingerprint) - sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol; - - for (const auto &attr : mAttributes) - sdp << "a=" << attr << eol; - - // Candidates - for (const auto &candidate : mCandidates) - sdp << string(candidate) << eol; - - if (mEnded) - sdp << "a=end-of-candidates" << eol; - - return sdp.str(); -} - -optional Description::defaultCandidate() const { - // Return the first host candidate with highest priority, favoring IPv4 - optional result; - for (const auto &c : mCandidates) { - if (c.type() == Candidate::Type::Host) { - if (!result || - (result->family() == Candidate::Family::Ipv6 && - c.family() == Candidate::Family::Ipv4) || - (result->family() == c.family() && result->priority() < c.priority())) - result.emplace(c); - } - } - return result; -} - -shared_ptr Description::createEntry(string mline, string mid, Direction dir) { - string type = mline.substr(0, mline.find(' ')); - if (type == "application") { - removeApplication(); - mApplication = std::make_shared(mline, std::move(mid)); - mEntries.emplace_back(mApplication); - return mApplication; - } else { - auto media = std::make_shared(std::move(mline), std::move(mid), dir); - mEntries.emplace_back(media); - return media; - } -} - -void Description::removeApplication() { - if (!mApplication) - return; - - auto it = std::find(mEntries.begin(), mEntries.end(), mApplication); - if (it != mEntries.end()) - mEntries.erase(it); - - mApplication.reset(); -} - -bool Description::hasApplication() const { return mApplication && !mApplication->isRemoved(); } - -bool Description::hasAudioOrVideo() const { - for (auto entry : mEntries) - if (entry != mApplication && !entry->isRemoved()) - return true; - - return false; -} - -bool Description::hasMid(string_view mid) const { - for (const auto &entry : mEntries) - if (entry->mid() == mid) - return true; - - return false; -} - -int Description::addMedia(Media media) { - mEntries.emplace_back(std::make_shared(std::move(media))); - return int(mEntries.size()) - 1; -} - -int Description::addMedia(Application application) { - removeApplication(); - mApplication = std::make_shared(std::move(application)); - mEntries.emplace_back(mApplication); - return int(mEntries.size()) - 1; -} - -int Description::addApplication(string mid) { return addMedia(Application(std::move(mid))); } - -const Description::Application *Description::application() const { return mApplication.get(); } - -Description::Application *Description::application() { return mApplication.get(); } - -int Description::addVideo(string mid, Direction dir) { - return addMedia(Video(std::move(mid), dir)); -} - -int Description::addAudio(string mid, Direction dir) { - return addMedia(Audio(std::move(mid), dir)); -} - -void Description::clearMedia() { - mEntries.clear(); - mApplication.reset(); -} - -RTC_WRAPPED(variant) -Description::media(unsigned int index) { - if (index >= mEntries.size()) - RTC_THROW RTC_OUT_OF_RANGE("Media index out of range"); - - const auto &entry = mEntries[index]; - if (entry == mApplication) { - auto result = dynamic_cast(entry.get()); - if (!result) - RTC_THROW RTC_LOGIC_ERROR("Bad type of application in description"); - - return (variant)result; - - } else { - auto result = dynamic_cast(entry.get()); - if (!result) - RTC_THROW RTC_LOGIC_ERROR("Bad type of media in description"); - - return (variant)result; - } -} - -RTC_WRAPPED(variant) -Description::media(unsigned int index) const { - if (index >= mEntries.size()) - RTC_THROW RTC_OUT_OF_RANGE("Media index out of range"); - - const auto &entry = mEntries[index]; - if (entry == mApplication) { - auto result = dynamic_cast(entry.get()); - if (!result) - RTC_THROW RTC_LOGIC_ERROR("Bad type of application in description"); - - return (variant)result; - - } else { - auto result = dynamic_cast(entry.get()); - if (!result) - RTC_THROW RTC_LOGIC_ERROR("Bad type of media in description"); - - return (variant)result; - } -} - -unsigned int Description::mediaCount() const { return unsigned(mEntries.size()); } - -Description::Entry::Entry(const string &mline, string mid, Direction dir) - : mMid(std::move(mid)), mDirection(dir) { - - uint16_t port; - std::istringstream ss(mline); - ss >> mType; - ss >> port; - ss >> mDescription; - - // RFC 3264: Existing media streams are removed by creating a new SDP with the port number for - // that stream set to zero. - // RFC 8843: If the offerer assigns a zero port value to a bundled "m=" section, but does not - // include an SDP 'bundle-only' attribute in the "m=" section, it is an indication that the - // offerer wants to disable the "m=" section. - mIsRemoved = (port == 0); -} - -string Description::Entry::type() const { return mType; } - -string Description::Entry::description() const { return mDescription; } - -string Description::Entry::mid() const { return mMid; } - -Description::Direction Description::Entry::direction() const { return mDirection; } - -void Description::Entry::setDirection(Direction dir) { mDirection = dir; } - -bool Description::Entry::isRemoved() const { return mIsRemoved; } - -void Description::Entry::markRemoved() { mIsRemoved = true; } - -std::vector Description::attributes() const { return mAttributes; } - -void Description::addAttribute(string attr) { - if (std::find(mAttributes.begin(), mAttributes.end(), attr) == mAttributes.end()) - mAttributes.emplace_back(std::move(attr)); -} - -void Description::Entry::addRid(string rid) { mRids.emplace_back(rid); } - -void Description::removeAttribute(const string &attr) { - mAttributes.erase( - std::remove_if(mAttributes.begin(), mAttributes.end(), - [&](const auto &a) { return a == attr || parse_pair(a).first == attr; }), - mAttributes.end()); -} - -std::vector Description::Entry::extIds() { - std::vector result; - for (auto it = mExtMaps.begin(); it != mExtMaps.end(); ++it) - result.push_back(it->first); - - return result; -} - -RTC_WRAPPED(Description::Entry::ExtMap *) Description::Entry::extMap(int id) { - auto it = mExtMaps.find(id); - if (it == mExtMaps.end()) - RTC_THROW RTC_INVALID_ARGUMENT("extmap not found"); - - return &it->second; -} - -void Description::Entry::addExtMap(ExtMap map) { - auto id = map.id; - mExtMaps.emplace(id, std::move(map)); -} - -void Description::Entry::removeExtMap(int id) { mExtMaps.erase(id); } - -Description::Entry::operator string() const { return generateSdp("\r\n", "IP4 0.0.0.0", 9); } - -string Description::Entry::generateSdp(string_view eol, string_view addr, uint16_t port) const { - std::ostringstream sdp; - // RFC 3264: Existing media streams are removed by creating a new SDP with the port number for - // that stream set to zero. [...] A stream that is offered with a port of zero MUST be marked - // with port zero in the answer. - sdp << "m=" << type() << ' ' << (mIsRemoved ? 0 : port) << ' ' << description() << eol; - sdp << "c=IN " << addr << eol; - sdp << generateSdpLines(eol); - - return sdp.str(); -} - -string Description::Entry::generateSdpLines(string_view eol) const { - std::ostringstream sdp; - sdp << "a=mid:" << mMid << eol; - - for (auto it = mExtMaps.begin(); it != mExtMaps.end(); ++it) { - auto &map = it->second; - - sdp << "a=extmap:" << map.id; - if (map.direction != Direction::Unknown) - sdp << '/' << map.direction; - - sdp << ' ' << map.uri; - if (!map.attributes.empty()) - sdp << ' ' << map.attributes; - - sdp << eol; - } - - if (mDirection != Direction::Unknown) - sdp << "a=" << mDirection << eol; - - for (const auto &attr : mAttributes) { - if (mRids.size() != 0 && match_prefix(attr, "ssrc:")) { - continue; - } - - sdp << "a=" << attr << eol; - } - - for (const auto &rid : mRids) { - sdp << "a=rid:" << rid << " send" << eol; - } - - if (mRids.size() != 0) { - sdp << "a=simulcast:send "; - - bool first = true; - for (const auto &rid : mRids) { - if (first) { - first = false; - } else { - sdp << ";"; - } - - sdp << rid; - } - - sdp << eol; - } - - return sdp.str(); -} - -RTC_WRAPPED(void) Description::Entry::parseSdpLine(string_view line) { - RTC_BEGIN; - if (match_prefix(line, "a=")) { - string_view attr = line.substr(2); - auto [key, value] = parse_pair(attr); - - if (key == "mid") { - mMid = value; - } else if (key == "extmap") { - const string_view& value_ = value; - RTC_UNWRAP_RETHROW_DECL(int, id, Description::Media::ExtMap::parseId(value_)); - auto it = mExtMaps.find(id); - if (it == mExtMaps.end()) { - RTC_UNWRAP_RETHROW_DECL(auto, tmp, Description::Media::ExtMap::create(value_)); - it = mExtMaps.insert(std::make_pair(id, tmp)).first; - } else - RTC_UNWRAP_RETHROW(it->second.setDescription(value_)); - - } else if (attr == "sendonly") - mDirection = Direction::SendOnly; - else if (attr == "recvonly") - mDirection = Direction::RecvOnly; - else if (key == "sendrecv") - mDirection = Direction::SendRecv; - else if (key == "inactive") - mDirection = Direction::Inactive; - else if (key == "bundle-only") { - // RFC 8843: When an offerer generates a subsequent offer, in which it wants to disable - // a bundled "m=" section from a BUNDLE group, the offerer [...] MUST NOT assign an SDP - // 'bundle-only' attribute to the "m=" section. - mIsRemoved = false; - } else { - mAttributes.emplace_back(attr); - } - } - RTC_RET; -} - -RTC_WRAPPED(int) Description::Entry::ExtMap::parseId(string_view description) { - size_t p = description.find(' '); - return to_integer(description.substr(0, p)); -} - -Description::Entry::ExtMap::ExtMap(int id, string uri, Direction direction) { - this->id = id; - this->uri = std::move(uri); - this->direction = direction; -} - -RTC_WRAPPED(Description::Entry::ExtMap) Description::Entry::ExtMap::create(string_view description) { - Description::Entry::ExtMap ret; - RTC_BEGIN; - RTC_UNWRAP_RETHROW(ret.setDescription(description)); - return ret; -} - -RTC_WRAPPED(void) -Description::Entry::ExtMap::setDescription(string_view description) { - RTC_BEGIN; - const size_t uriStart = description.find(' '); - if (uriStart == string::npos) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid description for extmap"); - - const string_view idAndDirection = description.substr(0, uriStart); - const size_t idSplit = idAndDirection.find('/'); - if (idSplit == string::npos) - RTC_UNWRAP_RETHROW_VAR(this->id, to_integer(idAndDirection)); - else { - RTC_UNWRAP_RETHROW_VAR(this->id, (to_integer(idAndDirection.substr(0, idSplit)))); - - const string_view directionStr = idAndDirection.substr(idSplit + 1); - if (directionStr == "sendonly") - this->direction = Direction::SendOnly; - else if (directionStr == "recvonly") - this->direction = Direction::RecvOnly; - else if (directionStr == "sendrecv") - this->direction = Direction::SendRecv; - else if (directionStr == "inactive") - this->direction = Direction::Inactive; - else - RTC_THROW RTC_INVALID_ARGUMENT("Invalid direction for extmap"); - } - - const string_view uriAndAttributes = description.substr(uriStart + 1); - const size_t attributeSplit = uriAndAttributes.find(' '); - - if (attributeSplit == string::npos) - this->uri = uriAndAttributes; - else { - this->uri = uriAndAttributes.substr(0, attributeSplit); - this->attributes = uriAndAttributes.substr(attributeSplit + 1); - } - RTC_RET; -} - -void Description::Media::addSSRC(uint32_t ssrc, optional name, optional msid, - optional trackId) { - if (name) { - mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + *name); - mCNameMap.emplace(ssrc, *name); - } else { - mAttributes.emplace_back("ssrc:" + std::to_string(ssrc)); - } - - if (msid) { - mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " msid:" + *msid + " " + - trackId.value_or(*msid)); - mAttributes.emplace_back("msid:" + *msid + " " + trackId.value_or(*msid)); - } - - mSsrcs.emplace_back(ssrc); -} - -void Description::Media::removeSSRC(uint32_t ssrc) { - string prefix = "ssrc:" + std::to_string(ssrc); - mAttributes.erase(std::remove_if(mAttributes.begin(), mAttributes.end(), - [&](const auto &a) { return match_prefix(a, prefix); }), - mAttributes.end()); - - mSsrcs.erase(std::remove(mSsrcs.begin(), mSsrcs.end(), ssrc), mSsrcs.end()); -} - -void Description::Media::replaceSSRC(uint32_t old, uint32_t ssrc, optional name, - optional msid, optional trackID) { - removeSSRC(old); - addSSRC(ssrc, std::move(name), std::move(msid), std::move(trackID)); -} - -bool Description::Media::hasSSRC(uint32_t ssrc) const { - return std::find(mSsrcs.begin(), mSsrcs.end(), ssrc) != mSsrcs.end(); -} - -void Description::Media::clearSSRCs() { - auto it = mAttributes.begin(); - while (it != mAttributes.end()) { - if (match_prefix(*it, "ssrc:")) - it = mAttributes.erase(it); - else - ++it; - } - - mSsrcs.clear(); - mCNameMap.clear(); -} - -std::vector Description::Media::getSSRCs() const { return mSsrcs; } - -optional Description::Media::getCNameForSsrc(uint32_t ssrc) const { - auto it = mCNameMap.find(ssrc); - if (it != mCNameMap.end()) { - return it->second; - } - return nullopt; -} - -Description::Application::Application(string mid) - : Entry("application 9 UDP/DTLS/SCTP", std::move(mid), Direction::SendRecv) {} - -Description::Application::Application(const string &mline, string mid) - : Entry(mline, std::move(mid), Direction::SendRecv) {} - -string Description::Application::description() const { - return Entry::description() + " webrtc-datachannel"; -} - -Description::Application Description::Application::reciprocate() const { - Application reciprocated(*this); - - reciprocated.mMaxMessageSize.reset(); - - return reciprocated; -} - -void Description::Application::setSctpPort(uint16_t port) { mSctpPort = port; } - -void Description::Application::hintSctpPort(uint16_t port) { mSctpPort = mSctpPort.value_or(port); } - -void Description::Application::setMaxMessageSize(size_t size) { mMaxMessageSize = size; } - -optional Description::Application::sctpPort() const { return mSctpPort; } - -optional Description::Application::maxMessageSize() const { return mMaxMessageSize; } - -string Description::Application::generateSdpLines(string_view eol) const { - std::ostringstream sdp; - sdp << Entry::generateSdpLines(eol); - - if (mSctpPort) - sdp << "a=sctp-port:" << *mSctpPort << eol; - - if (mMaxMessageSize) - sdp << "a=max-message-size:" << *mMaxMessageSize << eol; - - return sdp.str(); -} - -RTC_WRAPPED(void) Description::Application::parseSdpLine(string_view line) { - RTC_BEGIN; - if (match_prefix(line, "a=")) { - string_view attr = line.substr(2); - auto [key, value] = parse_pair(attr); - const string_view &value_ = value; - - if (key == "sctp-port") { - RTC_UNWRAP_RETHROW_VAR(mSctpPort, to_integer(value_)); - } else if (key == "max-message-size") { - RTC_UNWRAP_RETHROW_VAR(mMaxMessageSize, to_integer(value_)); - } else { - RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } - } else { - RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } - RTC_RET; -} - -Description::Media::Media(const string& sdp) : - Entry(sdp, "", Direction::Unknown) { -} - -RTC_WRAPPED(Description::Media) Description::Media::create(const string &sdp) { - RTC_BEGIN; - Media ret = sdp; - std::istringstream ss(sdp); - while (ss) { - string line; - std::getline(ss, line); - trim_end(line); - if (line.empty()) - continue; - - RTC_UNWRAP_RETHROW(ret.parseSdpLine(line)); - } - - if (ret.mid().empty()) - PLOG_WARNING << "Missing mid in media description"; - return ret; -} - -Description::Media::Media(const string &mline, string mid, Direction dir) - : Entry(mline, std::move(mid), dir) {} - -string Description::Media::description() const { - std::ostringstream desc; - desc << Entry::description(); - for (auto it = mRtpMaps.begin(); it != mRtpMaps.end(); ++it) - desc << ' ' << it->first; - - return desc.str(); -} - -Description::Media Description::Media::reciprocate() const { - Media reciprocated(*this); - - // Invert direction - switch (reciprocated.direction()) { - case Direction::RecvOnly: - reciprocated.setDirection(Direction::SendOnly); - break; - case Direction::SendOnly: - reciprocated.setDirection(Direction::RecvOnly); - break; - default: - // We are good - break; - } - - // Invert directions of extmap - auto &extMaps = reciprocated.mExtMaps; - for (auto it = extMaps.begin(); it != extMaps.end(); ++it) { - auto &map = it->second; - switch (map.direction) { - case Direction::RecvOnly: - map.direction = Direction::SendOnly; - break; - case Direction::SendOnly: - map.direction = Direction::RecvOnly; - break; - default: - // We are good - break; - } - } - - // Clear sent SSRCs - reciprocated.clearSSRCs(); - - // Remove rtcp-rsize attribute as Reduced-Size RTCP is not supported (see RFC 5506) - reciprocated.removeAttribute("rtcp-rsize"); - - return reciprocated; -} - -int Description::Media::bitrate() const { return mBas; } - -void Description::Media::setBitrate(int bitrate) { mBas = bitrate; } - -bool Description::Media::hasPayloadType(int payloadType) const { - return mRtpMaps.find(payloadType) != mRtpMaps.end(); -} - -std::vector Description::Media::payloadTypes() const { - std::vector result; - result.reserve(mRtpMaps.size()); - for (auto it = mRtpMaps.begin(); it != mRtpMaps.end(); ++it) - result.push_back(it->first); - - return result; -} - -RTC_WRAPPED(Description::Media::RtpMap *) Description::Media::rtpMap(int payloadType) { - auto it = mRtpMaps.find(payloadType); - if (it == mRtpMaps.end()) - RTC_THROW RTC_INVALID_ARGUMENT("rtpmap not found"); - - return &it->second; -} - -void Description::Media::addRtpMap(RtpMap map) { - auto payloadType = map.payloadType; - mRtpMaps.emplace(payloadType, std::move(map)); -} - -void Description::Media::removeRtpMap(int payloadType) { - // Remove the actual format - mRtpMaps.erase(payloadType); - - // Remove any other rtpmaps that depend on the format we just removed - auto it = mRtpMaps.begin(); - while (it != mRtpMaps.end()) { - const auto &fmtps = it->second.fmtps; - if (std::find(fmtps.begin(), fmtps.end(), "apt=" + std::to_string(payloadType)) != - fmtps.end()) - it = mRtpMaps.erase(it); - else - ++it; - } -} - -void Description::Media::removeFormat(const string &format) { - std::vector payloadTypes; - for (const auto &it : mRtpMaps) { - if (it.second.format == format) - payloadTypes.push_back(it.first); - } - for (int pt : payloadTypes) - removeRtpMap(pt); -} - -RTC_WRAPPED(void) Description::Media::addRtxCodec(int payloadType, int origPayloadType, unsigned int clockRate) { - RTC_BEGIN; - RTC_UNWRAP_RETHROW_DECL(RtpMap, rtp, RtpMap::create(std::to_string(payloadType) + " RTX/" + std::to_string(clockRate))); - rtp.fmtps.emplace_back("apt=" + std::to_string(origPayloadType)); - addRtpMap(rtp); - RTC_RET; -} - -string Description::Media::generateSdpLines(string_view eol) const { - std::ostringstream sdp; - if (mBas >= 0) - sdp << "b=AS:" << mBas << eol; - - sdp << Entry::generateSdpLines(eol); - sdp << "a=rtcp-mux" << eol; - - for (auto it = mRtpMaps.begin(); it != mRtpMaps.end(); ++it) { - auto &map = it->second; - - // Create the a=rtpmap - sdp << "a=rtpmap:" << map.payloadType << ' ' << map.format << '/' << map.clockRate; - if (!map.encParams.empty()) - sdp << '/' << map.encParams; - - sdp << eol; - - for (const auto &val : map.rtcpFbs) - sdp << "a=rtcp-fb:" << map.payloadType << ' ' << val << eol; - - for (const auto &val : map.fmtps) - sdp << "a=fmtp:" << map.payloadType << ' ' << val << eol; - } - - return sdp.str(); -} - -RTC_WRAPPED(void) Description::Media::parseSdpLine(string_view line) { - RTC_BEGIN; - if (match_prefix(line, "a=")) { - string_view attr = line.substr(2); - auto [key, value] = parse_pair(attr); - const string_view &value_ = value; - - if (key == "rtpmap") { - RTC_UNWRAP_RETHROW_DECL(auto, pt, Description::Media::RtpMap::parsePayloadType(value_)); - auto it = mRtpMaps.find(pt); - if (it == mRtpMaps.end()) { - RTC_UNWRAP_RETHROW_DECL(Description::Media::RtpMap, tmp, Description::Media::RtpMap::create(value_)); - it = mRtpMaps.insert(std::make_pair(pt, tmp)).first; - } else - RTC_UNWRAP_RETHROW(it->second.setDescription(value_)); - - } else if (key == "rtcp-fb") { - size_t p = value.find(' '); - RTC_UNWRAP_RETHROW_DECL(int, pt, to_integer(value_.substr(0, p))); - auto it = mRtpMaps.find(pt); - if (it == mRtpMaps.end()) - it = mRtpMaps.insert(std::make_pair(pt, Description::Media::RtpMap(pt))).first; - - it->second.rtcpFbs.emplace_back(value.substr(p + 1)); - - } else if (key == "fmtp") { - size_t p = value.find(' '); - RTC_UNWRAP_RETHROW_DECL(int, pt, to_integer(value_.substr(0, p))); - auto it = mRtpMaps.find(pt); - if (it == mRtpMaps.end()) - it = mRtpMaps.insert(std::make_pair(pt, Description::Media::RtpMap(pt))).first; - - it->second.fmtps.emplace_back(value.substr(p + 1)); - - } else if (key == "rtcp-mux") { - // always added - - } else if (key == "ssrc") { - RTC_UNWRAP_RETHROW_DECL(auto, ssrc, to_integer(value_)); - if (!hasSSRC(ssrc)) - mSsrcs.emplace_back(ssrc); - - auto cnamePos = value.find("cname:"); - if (cnamePos != string::npos) { - auto cname = value.substr(cnamePos + 6); - mCNameMap.emplace(ssrc, cname); - } - mAttributes.emplace_back(attr); - - } else { - RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } - - } else if (match_prefix(line, "b=AS")) { - RTC_UNWRAP_RETHROW_VAR(mBas, to_integer(line.substr(line.find(':') + 1))); - } else { - RTC_UNWRAP_RETHROW(Entry::parseSdpLine(line)); - } - RTC_RET; -} - -Description::Media::RtpMap::RtpMap(int payloadType) { - this->payloadType = payloadType; - this->clockRate = 0; -} - -RTC_WRAPPED(Description::Media::RtpMap) Description::Media::RtpMap::create(string_view description) { - RTC_BEGIN; - RtpMap ret = RtpMap(0); - RTC_UNWRAP_RETHROW(ret.setDescription(description)); - return ret; -} - - -RTC_WRAPPED(int) Description::Media::RtpMap::parsePayloadType(string_view mline) { - size_t p = mline.find(' '); - return to_integer(mline.substr(0, p)); -} - -RTC_WRAPPED(void) Description::Media::RtpMap::setDescription(string_view description) { - RTC_BEGIN; - size_t p = description.find(' '); - if (p == string::npos) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid format description for rtpmap"); - - RTC_UNWRAP_RETHROW_VAR(this->payloadType, to_integer(description.substr(0, p))); - - string_view line = description.substr(p + 1); - size_t spl = line.find('/'); - if (spl == string::npos) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid format description for rtpmap"); - - this->format = line.substr(0, spl); - - line = line.substr(spl + 1); - spl = line.find('/'); - if (spl == string::npos) { - spl = line.find(' '); - } - if (spl == string::npos) - RTC_UNWRAP_RETHROW_VAR(this->clockRate, to_integer(line)); - else { - RTC_UNWRAP_RETHROW_VAR(this->clockRate, (to_integer(line.substr(0, spl)))); - this->encParams = line.substr(spl + 1); - } - RTC_RET; -} - -void Description::Media::RtpMap::addFeedback(string fb) { - if (std::find(rtcpFbs.begin(), rtcpFbs.end(), fb) == rtcpFbs.end()) - rtcpFbs.emplace_back(std::move(fb)); -} - -void Description::Media::RtpMap::removeFeedback(const string &str) { - auto it = rtcpFbs.begin(); - while (it != rtcpFbs.end()) { - if (it->find(str) != string::npos) - it = rtcpFbs.erase(it); - else - it++; - } -} - -void Description::Media::RtpMap::addParameter(string p) { - if (std::find(fmtps.begin(), fmtps.end(), p) == fmtps.end()) - fmtps.emplace_back(std::move(p)); -} - -void Description::Media::RtpMap::removeParameter(const string &str) { - fmtps.erase(std::remove_if(fmtps.begin(), fmtps.end(), - [&](const auto &p) { return p.find(str) != string::npos; }), - fmtps.end()); -} - -Description::Audio::Audio(string mid, Direction dir) - : Media("audio 9 UDP/TLS/RTP/SAVPF", std::move(mid), dir) {} - -RTC_WRAPPED(void) Description::Audio::addAudioCodec(int payloadType, string codec, optional profile) { - RTC_BEGIN; - if (codec.find('/') == string::npos) { - if (codec == "PCMA" || codec == "PCMU") - codec += "/8000/1"; - else - codec += "/48000/2"; - } - - RTC_UNWRAP_RETHROW_DECL(RtpMap, map, RtpMap::create(std::to_string(payloadType) + ' ' + codec)); - - if (profile) - map.fmtps.emplace_back(*profile); - - addRtpMap(map); - RTC_RET; -} - -RTC_WRAPPED(void) Description::Audio::addOpusCodec(int payloadType, optional profile) { - return addAudioCodec(payloadType, "opus", profile); -} - -RTC_WRAPPED(void) Description::Audio::addPCMACodec(int payloadType, optional profile) { - return addAudioCodec(payloadType, "PCMA", profile); -} - -RTC_WRAPPED(void) Description::Audio::addPCMUCodec(int payloadType, optional profile) { - return addAudioCodec(payloadType, "PCMU", profile); -} - -RTC_WRAPPED(void) Description::Audio::addAacCodec(int payloadType, optional profile) { - if (profile) { - return addAudioCodec(payloadType, "MP4A-LATM", profile); - } else { - return addAudioCodec(payloadType, "MP4A-LATM", "cpresent=1"); - } -} - -Description::Video::Video(string mid, Direction dir) - : Media("video 9 UDP/TLS/RTP/SAVPF", std::move(mid), dir) {} - -RTC_WRAPPED(void) Description::Video::addVideoCodec(int payloadType, string codec, optional profile) { - RTC_BEGIN; - if (codec.find('/') == string::npos) - codec += "/90000"; - - RTC_UNWRAP_RETHROW_DECL(RtpMap, map, RtpMap::create(std::to_string(payloadType) + ' ' + codec)); - - map.addFeedback("nack"); - map.addFeedback("nack pli"); - // map.addFB("ccm fir"); - map.addFeedback("goog-remb"); - - if (profile) - map.fmtps.emplace_back(*profile); - - addRtpMap(map); - - /* TODO - * TIL that Firefox does not properly support the negotiation of RTX! It works, but doesn't - * negotiate the SSRC so we have no idea what SSRC is RTX going to be. Three solutions: One) we - * don't negotitate it and (maybe) break RTX support with Edge. Two) we do negotiate it and - * rebuild the original packet before we send it distribute it to each track. Three) we complain - * to mozilla. This one probably won't do much. - */ - // RTX Packets - // Format rtx(std::to_string(payloadType+1) + " rtx/90000"); - // // TODO rtx-time is how long can a request be stashed for before needing to resend it. - // Needs to be parameterized rtx.addAttribute("apt=" + std::to_string(payloadType) + - // ";rtx-time=3000"); addFormat(rtx); - RTC_RET; -} - -RTC_WRAPPED(void) Description::Video::addH264Codec(int payloadType, optional profile) { - return addVideoCodec(payloadType, "H264", profile); -} - -RTC_WRAPPED(void) Description::Video::addH265Codec(int payloadType, optional profile) { - return addVideoCodec(payloadType, "H265", profile); -} - -RTC_WRAPPED(void) Description::Video::addVP8Codec(int payloadType, optional profile) { - return addVideoCodec(payloadType, "VP8", profile); -} - -RTC_WRAPPED(void) Description::Video::addVP9Codec(int payloadType, optional profile) { - return addVideoCodec(payloadType, "VP9", profile); -} - -RTC_WRAPPED(void) Description::Video::addAV1Codec(int payloadType, optional profile) { - return addVideoCodec(payloadType, "AV1", profile); -} - -Description::Type Description::stringToType(const string &typeString) { - using TypeMap_t = std::unordered_map; - static const TypeMap_t TypeMap = {{"unspec", Type::Unspec}, - {"offer", Type::Offer}, - {"answer", Type::Answer}, - {"pranswer", Type::Pranswer}, - {"rollback", Type::Rollback}}; - auto it = TypeMap.find(typeString); - return it != TypeMap.end() ? it->second : Type::Unspec; -} - -string Description::typeToString(Type type) { - switch (type) { - case Type::Unspec: - return "unspec"; - case Type::Offer: - return "offer"; - case Type::Answer: - return "answer"; - case Type::Pranswer: - return "pranswer"; - case Type::Rollback: - return "rollback"; - default: - return "unknown"; - } -} - -} // namespace rtc - -std::ostream &operator<<(std::ostream &out, const rtc::Description &description) { - return out << std::string(description); -} - -std::ostream &operator<<(std::ostream &out, rtc::Description::Type type) { - return out << rtc::Description::typeToString(type); -} - -std::ostream &operator<<(std::ostream &out, rtc::Description::Role role) { - using Role = rtc::Description::Role; - // Used for SDP generation, do not change - switch (role) { - case Role::Active: - out << "active"; - break; - case Role::Passive: - out << "passive"; - break; - default: - out << "actpass"; - break; - } - return out; -} - -std::ostream &operator<<(std::ostream &out, const rtc::Description::Direction &direction) { - // Used for SDP generation, do not change - switch (direction) { - case rtc::Description::Direction::RecvOnly: - out << "recvonly"; - break; - case rtc::Description::Direction::SendOnly: - out << "sendonly"; - break; - case rtc::Description::Direction::SendRecv: - out << "sendrecv"; - break; - case rtc::Description::Direction::Inactive: - out << "inactive"; - break; - case rtc::Description::Direction::Unknown: - default: - out << "unknown"; - break; - } - return out; -} diff --git a/godot/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp b/godot/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp deleted file mode 100644 index 1c8c366b..00000000 --- a/godot/thirdparty/libdatachannel/src/exception_wrapper_godot.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "rtc/rtc.hpp" -#include "rtc/exception_wrapper_godot.hpp" - -void LibDataChannelExceptionWrapper::close_data_channel(std::shared_ptr p_channel) { - RTC_TRY { - if (p_channel) { - p_channel->close(); - } - } RTC_CATCH (...) { - } -} - - -void LibDataChannelExceptionWrapper::close_peer_connection(std::shared_ptr p_peer_connection) { -RTC_TRY { - if (p_peer_connection) { - p_peer_connection->close(); - } -} RTC_CATCH (...) { -} -} - - -bool LibDataChannelExceptionWrapper::put_packet(std::shared_ptr p_channel, const uint8_t *p_buffer, int32_t p_len, bool p_is_text, std::string &r_error) { -RTC_TRY { - if (p_is_text) { - std::string str((const char *)p_buffer, (size_t)p_len); - RTC_UNWRAP_CATCH(p_channel->send(str)); - } else { - RTC_UNWRAP_CATCH(p_channel->send(reinterpret_cast(p_buffer), p_len)); - } - return true; -} RTC_CATCH (const RTC_EXCEPTION &e) { - r_error = e.RTC_WHAT(); - return false; -} -} - - -std::shared_ptr LibDataChannelExceptionWrapper::create_data_channel(std::shared_ptr p_peer_connection, const char *p_label, rtc::DataChannelInit p_config, std::string &r_error) { -RTC_TRY { - RTC_UNWRAP_CATCH_DECL(std::shared_ptr, ret, p_peer_connection->createDataChannel(p_label, p_config)); - return ret; -} RTC_CATCH (const RTC_EXCEPTION &e) { - r_error = e.RTC_WHAT(); - return std::shared_ptr(); -} -} - -std::shared_ptr LibDataChannelExceptionWrapper::create_peer_connection(const rtc::Configuration &p_config, std::string &r_error) { -RTC_TRY { - return std::make_shared(p_config); -} RTC_CATCH (const RTC_EXCEPTION &e) { - r_error = e.RTC_WHAT(); - return std::shared_ptr(); -} -} - -bool LibDataChannelExceptionWrapper::create_offer(std::shared_ptr p_peer_connection, std::string &r_error) { -RTC_TRY { - RTC_UNWRAP_CATCH(p_peer_connection->setLocalDescription(rtc::Description::Type::Offer)); - return true; -} RTC_CATCH (const RTC_EXCEPTION &e) { - r_error = e.RTC_WHAT(); - return false; -} -} - -bool LibDataChannelExceptionWrapper::set_remote_description(std::shared_ptr p_peer_connection, const char *p_type, const char *p_sdp, std::string &r_error) { -RTC_TRY { - std::string sdp(p_sdp); - std::string type(p_type); - RTC_UNWRAP_CATCH_DECL(rtc::Description, desc, rtc::Description::create(sdp, type)); - RTC_UNWRAP_CATCH(p_peer_connection->setRemoteDescription(desc)); - // Automatically create the answer. - if (type == "offer") { - RTC_UNWRAP_CATCH(p_peer_connection->setLocalDescription(rtc::Description::Type::Answer)); - } - return true; -} RTC_CATCH (const RTC_EXCEPTION &e) { - r_error = e.RTC_WHAT(); - return false; -} -} - -bool LibDataChannelExceptionWrapper::add_ice_candidate(std::shared_ptr p_peer_connection, const char *p_sdp_mid_name, const char *p_sdp_name, std::string &r_error) { -RTC_TRY { - RTC_UNWRAP_CATCH_DECL(rtc::Candidate, candidate, rtc::Candidate::create(p_sdp_name, p_sdp_mid_name)); - RTC_UNWRAP_CATCH(p_peer_connection->addRemoteCandidate(candidate)); - return true; -} RTC_CATCH (const RTC_EXCEPTION &e) { - r_error = e.RTC_WHAT(); - return false; -} -} diff --git a/godot/thirdparty/libdatachannel/src/global.cpp b/godot/thirdparty/libdatachannel/src/global.cpp deleted file mode 100644 index 89f6d4c7..00000000 --- a/godot/thirdparty/libdatachannel/src/global.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if !defined(GODOT_PLOG_DISABLE_LOG) -#include "plog/Appenders/ColorConsoleAppender.h" -#include "plog/Converters/UTF8Converter.h" -#include "plog/Formatters/FuncMessageFormatter.h" -#include "plog/Formatters/TxtFormatter.h" -#include "plog/Init.h" -#include "plog/Log.h" -#include "plog/Logger.h" -#endif // !defined(GODOT_PLOG_DISABLE_LOG) -// -#include "global.hpp" - -#include "impl/init.hpp" - -#include - -namespace { - -#if !defined(GODOT_PLOG_DISABLE_LOG) -void plogInit(plog::Severity severity, plog::IAppender *appender) { - using Logger = plog::Logger; - static Logger *logger = nullptr; - if (!logger) { - PLOG_DEBUG << "Initializing logger"; - logger = new Logger(severity); - if (appender) { - logger->addAppender(appender); - } else { - using ConsoleAppender = plog::ColorConsoleAppender; - static ConsoleAppender *consoleAppender = new ConsoleAppender(); - logger->addAppender(consoleAppender); - } - } else { - logger->setMaxSeverity(severity); - if (appender) - logger->addAppender(appender); - } -} -#endif // !defined(GODOT_PLOG_DISABLE_LOG) - -} // namespace - -namespace rtc { - -#if !defined(GODOT_PLOG_DISABLE_LOG) -struct LogAppender : public plog::IAppender { - synchronized_callback callback; - - void write(const plog::Record &record) override { - const auto severity = record.getSeverity(); - auto formatted = plog::FuncMessageFormatter::format(record); - formatted.pop_back(); // remove newline - - const auto &converted = - plog::UTF8Converter::convert(formatted); // does nothing on non-Windows systems - - if (!callback(static_cast(severity), converted)) - std::cout << plog::severityToString(severity) << " " << converted << std::endl; - } -}; - -void InitLogger(LogLevel level, LogCallback callback) { - const auto severity = static_cast(level); - static LogAppender *appender = nullptr; - static std::mutex mutex; - std::lock_guard lock(mutex); - if (appender) { - appender->callback = std::move(callback); - plogInit(severity, nullptr); // change the severity - } else if (callback) { - appender = new LogAppender(); - appender->callback = std::move(callback); - plogInit(severity, appender); - } else { - plogInit(severity, nullptr); // log to cout - } -} - -void InitLogger(plog::Severity severity, plog::IAppender *appender) { - plogInit(severity, appender); -} -#else // !defined(GODOT_PLOG_DISABLE_LOG) - -void InitLogger(LogLevel level, LogCallback callback) { -} - -#endif // defined(GODOT_PLOG_DISABLE_LOG) - -void Preload() { impl::Init::Instance().preload(); } -std::shared_future Cleanup() { return impl::Init::Instance().cleanup(); } - -RTC_WRAPPED(void) SetSctpSettings(SctpSettings s) { - return impl::Init::Instance().setSctpSettings(std::move(s)); -} - -} // namespace rtc - -RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level) { - switch (level) { - case rtc::LogLevel::Fatal: - out << "fatal"; - break; - case rtc::LogLevel::Error: - out << "error"; - break; - case rtc::LogLevel::Warning: - out << "warning"; - break; - case rtc::LogLevel::Info: - out << "info"; - break; - case rtc::LogLevel::Debug: - out << "debug"; - break; - case rtc::LogLevel::Verbose: - out << "verbose"; - break; - default: - out << "none"; - break; - } - return out; -} diff --git a/godot/thirdparty/libdatachannel/src/impl/certificate.cpp b/godot/thirdparty/libdatachannel/src/impl/certificate.cpp deleted file mode 100644 index bef4018b..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/certificate.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "certificate.hpp" -#include "threadpool.hpp" - -#include -#include -#include -#include -#include -#include -#include - -namespace rtc::impl { - -#if USE_GNUTLS - -Certificate Certificate::FromString(string crt_pem, string key_pem) { - PLOG_DEBUG << "Importing certificate from PEM string (GnuTLS)"; - - shared_ptr creds(gnutls::new_credentials(), - gnutls::free_credentials); - gnutls_datum_t crt_datum = gnutls::make_datum(crt_pem.data(), crt_pem.size()); - gnutls_datum_t key_datum = gnutls::make_datum(key_pem.data(), key_pem.size()); - gnutls::check( - gnutls_certificate_set_x509_key_mem(*creds, &crt_datum, &key_datum, GNUTLS_X509_FMT_PEM), - "Unable to import PEM certificate and key"); - - return Certificate(std::move(creds)); -} - -Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass) { - PLOG_DEBUG << "Importing certificate from PEM file (GnuTLS): " << crt_pem_file; - - shared_ptr creds(gnutls::new_credentials(), - gnutls::free_credentials); - gnutls::check(gnutls_certificate_set_x509_key_file2(*creds, crt_pem_file.c_str(), - key_pem_file.c_str(), GNUTLS_X509_FMT_PEM, - pass.c_str(), 0), - "Unable to import PEM certificate and key from file"); - - return Certificate(std::move(creds)); -} - -RTC_WRAPPED(Certificate) Certificate::Generate(CertificateType type, const string &commonName) { - PLOG_DEBUG << "Generating certificate (GnuTLS)"; - - using namespace gnutls; - unique_ptr crt(new_crt(), free_crt); - unique_ptr privkey(new_privkey(), free_privkey); - - switch (type) { - // RFC 8827 WebRTC Security Architecture 6.5. Communications Security - // All implementations MUST support DTLS 1.2 with the TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - // cipher suite and the P-256 curve - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - case CertificateType::Default: - case CertificateType::Ecdsa: { - gnutls::check(gnutls_x509_privkey_generate(*privkey, GNUTLS_PK_ECDSA, - GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1), - 0), - "Unable to generate ECDSA P-256 key pair"); - break; - } - case CertificateType::Rsa: { - const unsigned int bits = 2048; - gnutls::check(gnutls_x509_privkey_generate(*privkey, GNUTLS_PK_RSA, bits, 0), - "Unable to generate RSA key pair"); - break; - } - default: - RTC_THROW RTC_INVALID_ARGUMENT("Unknown certificate type"); - } - - using namespace std::chrono; - auto now = time_point_cast(system_clock::now()); - gnutls_x509_crt_set_activation_time(*crt, (now - hours(1)).time_since_epoch().count()); - gnutls_x509_crt_set_expiration_time(*crt, (now + hours(24 * 365)).time_since_epoch().count()); - gnutls_x509_crt_set_version(*crt, 1); - gnutls_x509_crt_set_key(*crt, *privkey); - gnutls_x509_crt_set_dn_by_oid(*crt, GNUTLS_OID_X520_COMMON_NAME, 0, commonName.data(), - commonName.size()); - - const size_t serialSize = 16; - char serial[serialSize]; - gnutls_rnd(GNUTLS_RND_NONCE, serial, serialSize); - gnutls_x509_crt_set_serial(*crt, serial, serialSize); - - gnutls::check(gnutls_x509_crt_sign2(*crt, *crt, *privkey, GNUTLS_DIG_SHA256, 0), - "Unable to auto-sign certificate"); - - return Certificate(*crt, *privkey); -} - -Certificate::Certificate(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey) - : mCredentials(gnutls::new_credentials(), gnutls::free_credentials), - mFingerprint(make_fingerprint(crt)) { - - gnutls::check(gnutls_certificate_set_x509_key(*mCredentials, &crt, 1, privkey), - "Unable to set certificate and key pair in credentials"); -} - -Certificate::Certificate(shared_ptr creds) - : mCredentials(std::move(creds)), mFingerprint(make_fingerprint(*mCredentials)) {} - -gnutls_certificate_credentials_t Certificate::credentials() const { return *mCredentials; } - -string make_fingerprint(gnutls_certificate_credentials_t credentials) { - auto new_crt_list = [credentials]() -> gnutls_x509_crt_t * { - gnutls_x509_crt_t *crt_list = nullptr; - unsigned int crt_list_size = 0; - gnutls::check(gnutls_certificate_get_x509_crt(credentials, 0, &crt_list, &crt_list_size)); - assert(crt_list_size == 1); - return crt_list; - }; - - auto free_crt_list = [](gnutls_x509_crt_t *crt_list) { - gnutls_x509_crt_deinit(crt_list[0]); - gnutls_free(crt_list); - }; - - unique_ptr crt_list(new_crt_list(), free_crt_list); - - return make_fingerprint(*crt_list); -} - -string make_fingerprint(gnutls_x509_crt_t crt) { - const size_t size = 32; - unsigned char buffer[size]; - size_t len = size; - gnutls::check(gnutls_x509_crt_get_fingerprint(crt, GNUTLS_DIG_SHA256, buffer, &len), - "X509 fingerprint error"); - - std::ostringstream oss; - oss << std::hex << std::uppercase << std::setfill('0'); - for (size_t i = 0; i < len; ++i) { - if (i) - oss << std::setw(1) << ':'; - oss << std::setw(2) << unsigned(buffer[i]); - } - return oss.str(); -} - -#elif USE_MBEDTLS -string make_fingerprint(mbedtls_x509_crt *crt) { - const int size = 32; - uint8_t buffer[size]; - std::stringstream fingerprint; - - (void)mbedtls::check( - mbedtls_sha256(crt->raw.p, crt->raw.len, reinterpret_cast(buffer), 0), - "Failed to generate certificate fingerprint"); - - for (auto i = 0; i < size; i++) { - fingerprint << std::setfill('0') << std::setw(2) << std::hex << static_cast(buffer[i]); - if (i != (size - 1)) { - fingerprint << ":"; - } - } - - return fingerprint.str(); -} - -Certificate::Certificate(shared_ptr crt, shared_ptr pk) - : mCrt(crt), mPk(pk), mFingerprint(make_fingerprint(crt.get())) {} - -RTC_WRAPPED(Certificate) Certificate::FromString(string crt_pem, string key_pem) { - RTC_BEGIN; - PLOG_DEBUG << "Importing certificate from PEM string (MbedTLS)"; - - auto crt = mbedtls::new_x509_crt(); - auto pk = mbedtls::new_pk_context(); - - RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_x509_crt_parse(crt.get(), - reinterpret_cast(crt_pem.c_str()), - crt_pem.length()), - "Failed to parse certificate")); - RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_pk_parse_key(pk.get(), - reinterpret_cast(key_pem.c_str()), - key_pem.size(), NULL, 0, NULL, 0), - "Failed to parse key")); - - return Certificate(std::move(crt), std::move(pk)); -} - -RTC_WRAPPED(Certificate) Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass) { - RTC_BEGIN; - PLOG_DEBUG << "Importing certificate from PEM file (MbedTLS): " << crt_pem_file; - - auto crt = mbedtls::new_x509_crt(); - auto pk = mbedtls::new_pk_context(); - - RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_x509_crt_parse_file(crt.get(), crt_pem_file.c_str()), - "Failed to parse certificate")); - RTC_UNWRAP_RETHROW(mbedtls::check(mbedtls_pk_parse_keyfile(pk.get(), key_pem_file.c_str(), pass.c_str(), 0, NULL), - "Failed to parse key")); - - return Certificate(std::move(crt), std::move(pk)); -} - -RTC_WRAPPED(Certificate) Certificate::Generate(CertificateType type, const string &commonName) { - PLOG_DEBUG << "Generating certificate (MbedTLS)"; - - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context drbg; - mbedtls_x509write_cert wcrt; - mbedtls_mpi serial; - auto crt = mbedtls::new_x509_crt(); - auto pk = mbedtls::new_pk_context(); - - mbedtls_entropy_init(&entropy); - mbedtls_ctr_drbg_init(&drbg); - mbedtls_ctr_drbg_set_prediction_resistance(&drbg, MBEDTLS_CTR_DRBG_PR_ON); - mbedtls_x509write_crt_init(&wcrt); - mbedtls_mpi_init(&serial); - - RTC_TRY { - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ctr_drbg_seed( - &drbg, mbedtls_entropy_func, &entropy, - reinterpret_cast(commonName.data()), commonName.size()))); - - switch (type) { - // RFC 8827 WebRTC Security Architecture 6.5. Communications Security - // All implementations MUST support DTLS 1.2 with the - // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 cipher suite and the P-256 curve - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - case CertificateType::Default: - case CertificateType::Ecdsa: { - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)))); - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*pk.get()), - mbedtls_ctr_drbg_random, &drbg), - "Unable to generate ECDSA P-256 key pair")); - break; - } - case CertificateType::Rsa: { - const unsigned int nbits = 2048; - const int exponent = 65537; - - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_pk_setup(pk.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)))); - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_rsa_gen_key(mbedtls_pk_rsa(*pk.get()), mbedtls_ctr_drbg_random, - &drbg, nbits, exponent), - "Unable to generate RSA key pair")); - break; - } - default: - RTC_THROW_WITHIN(RTC_INVALID_ARGUMENT("Unknown certificate type")); - } - - auto now = std::chrono::system_clock::now(); - RTC_UNWRAP_CATCH_DECL(string, notBefore, mbedtls::format_time(now - std::chrono::hours(1))); - RTC_UNWRAP_CATCH_DECL(string, notAfter, mbedtls::format_time(now + std::chrono::hours(24 * 365))); - - const size_t serialBufferSize = 16; - unsigned char serialBuffer[serialBufferSize]; - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ctr_drbg_random(&drbg, serialBuffer, serialBufferSize), - "Failed to generate certificate")); - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_mpi_read_binary(&serial, serialBuffer, serialBufferSize), - "Failed to generate certificate")); - - std::string name = std::string("O=" + commonName + ",CN=" + commonName); - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509write_crt_set_serial_raw(&wcrt, serialBuffer, serialBufferSize), - "Failed to generate certificate")); - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509write_crt_set_subject_name(&wcrt, name.c_str()), - "Failed to generate certificate")); - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509write_crt_set_issuer_name(&wcrt, name.c_str()), - "Failed to generate certificate")); - RTC_UNWRAP_CATCH(mbedtls::check( - mbedtls_x509write_crt_set_validity(&wcrt, notBefore.c_str(), notAfter.c_str()), - "Failed to generate certificate")); - - mbedtls_x509write_crt_set_version(&wcrt, MBEDTLS_X509_CRT_VERSION_3); - mbedtls_x509write_crt_set_subject_key(&wcrt, pk.get()); - mbedtls_x509write_crt_set_issuer_key(&wcrt, pk.get()); - mbedtls_x509write_crt_set_md_alg(&wcrt, MBEDTLS_MD_SHA256); - - const size_t certificateBufferSize = 4096; - unsigned char certificateBuffer[certificateBufferSize]; - std::memset(certificateBuffer, 0, certificateBufferSize); - - auto certificateLen = mbedtls_x509write_crt_der( - &wcrt, certificateBuffer, certificateBufferSize, mbedtls_ctr_drbg_random, &drbg); - if (certificateLen <= 0) { - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Certificate generation failed")); - } - - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_x509_crt_parse_der( - crt.get(), (certificateBuffer + certificateBufferSize - certificateLen), - certificateLen), - "Failed to generate certificate")); - } RTC_CATCH (...) { - mbedtls_entropy_free(&entropy); - mbedtls_ctr_drbg_free(&drbg); - mbedtls_x509write_crt_free(&wcrt); - mbedtls_mpi_free(&serial); - RTC_RETHROW; - } - - mbedtls_entropy_free(&entropy); - mbedtls_ctr_drbg_free(&drbg); - mbedtls_x509write_crt_free(&wcrt); - mbedtls_mpi_free(&serial); - return Certificate(std::move(crt), std::move(pk)); -} - -std::tuple, shared_ptr> -Certificate::credentials() const { - return {mCrt, mPk}; -} - -#else // OPENSSL - -#include -#include -#include - -namespace { - -// Dummy password callback that copies the password from user data -int dummy_pass_cb(char *buf, int size, int /*rwflag*/, void *u) { - const char *pass = static_cast(u); - return snprintf(buf, size, "%s", pass); -} - -} // namespace - -RTC_WRAPPED(Certificate) Certificate::FromString(string crt_pem, string key_pem) { - PLOG_DEBUG << "Importing certificate from PEM string (OpenSSL)"; - - BIO *bio = BIO_new(BIO_s_mem()); - BIO_write(bio, crt_pem.data(), int(crt_pem.size())); - auto x509 = shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free); - BIO_free(bio); - if (!x509) - RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM certificate"); - - bio = BIO_new(BIO_s_mem()); - BIO_write(bio, key_pem.data(), int(key_pem.size())); - auto pkey = shared_ptr(PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr), - EVP_PKEY_free); - BIO_free(bio); - if (!pkey) - RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM key"); - - return Certificate(x509, pkey); -} - -RTC_WRAPPED(Certificate) Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass) { - PLOG_DEBUG << "Importing certificate from PEM file (OpenSSL): " << crt_pem_file; - - BIO *bio = openssl::BIO_new_from_file(crt_pem_file); - if (!bio) - RTC_THROW RTC_INVALID_ARGUMENT("Unable to open PEM certificate file"); - - auto x509 = shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free); - BIO_free(bio); - if (!x509) - RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM certificate from file"); - - bio = openssl::BIO_new_from_file(key_pem_file); - if (!bio) - RTC_THROW RTC_INVALID_ARGUMENT("Unable to open PEM key file"); - - auto pkey = shared_ptr( - PEM_read_bio_PrivateKey(bio, nullptr, dummy_pass_cb, const_cast(pass.c_str())), - EVP_PKEY_free); - BIO_free(bio); - if (!pkey) - RTC_THROW RTC_INVALID_ARGUMENT("Unable to import PEM key from file"); - - return Certificate(x509, pkey); -} - -RTC_WRAPPED(Certificate) Certificate::Generate(CertificateType type, const string &commonName) { - PLOG_DEBUG << "Generating certificate (OpenSSL)"; - - shared_ptr x509(X509_new(), X509_free); - unique_ptr serial_number(BN_new(), BN_free); - unique_ptr name(X509_NAME_new(), X509_NAME_free); - if (!x509 || !serial_number || !name) - RTC_THROW RTC_RUNTIME_ERROR("Unable to allocate structures for certificate generation"); - - shared_ptr pkey; - switch (type) { - // RFC 8827 WebRTC Security Architecture 6.5. Communications Security - // All implementations MUST support DTLS 1.2 with the TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - // cipher suite and the P-256 curve - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - case CertificateType::Default: - case CertificateType::Ecdsa: { - PLOG_VERBOSE << "Generating ECDSA P-256 key pair"; -#if OPENSSL_VERSION_NUMBER >= 0x30000000 - pkey = shared_ptr(EVP_EC_gen("P-256"), EVP_PKEY_free); -#else - pkey = shared_ptr(EVP_PKEY_new(), EVP_PKEY_free); - unique_ptr ecc( - EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), EC_KEY_free); - if (!pkey || !ecc) - RTC_THROW RTC_RUNTIME_ERROR("Unable to allocate structure for ECDSA P-256 key pair"); - - EC_KEY_set_asn1_flag(ecc.get(), OPENSSL_EC_NAMED_CURVE); // Set ASN1 OID - if (!EC_KEY_generate_key(ecc.get()) || - !EVP_PKEY_assign_EC_KEY(pkey.get(), - ecc.release())) // the key will be freed when pkey is freed -#endif - if (!pkey) - RTC_THROW RTC_RUNTIME_ERROR("Unable to generate ECDSA P-256 key pair"); - - break; - } - case CertificateType::Rsa: { - PLOG_VERBOSE << "Generating RSA key pair"; - const unsigned int bits = 2048; -#if OPENSSL_VERSION_NUMBER >= 0x30000000 - pkey = shared_ptr(EVP_RSA_gen(bits), EVP_PKEY_free); -#else - pkey = shared_ptr(EVP_PKEY_new(), EVP_PKEY_free); - unique_ptr rsa(RSA_new(), RSA_free); - unique_ptr exponent(BN_new(), BN_free); - if (!pkey || !rsa || !exponent) - RTC_THROW RTC_RUNTIME_ERROR("Unable to allocate structures for RSA key pair"); - - const unsigned int e = 65537; // 2^16 + 1 - if (!BN_set_word(exponent.get(), e) || - !RSA_generate_key_ex(rsa.get(), bits, exponent.get(), NULL) || - !EVP_PKEY_assign_RSA(pkey.get(), - rsa.release())) // the key will be freed when pkey is freed -#endif - if (!pkey) - RTC_THROW RTC_RUNTIME_ERROR("Unable to generate RSA key pair"); - - break; - } - default: - RTC_THROW RTC_INVALID_ARGUMENT("Unknown certificate type"); - } - - const size_t serialSize = 16; - auto *commonNameBytes = - reinterpret_cast(const_cast(commonName.c_str())); - - if (!X509_set_pubkey(x509.get(), pkey.get())) - RTC_THROW RTC_RUNTIME_ERROR("Unable to set certificate public key"); - - if (!X509_gmtime_adj(X509_getm_notBefore(x509.get()), 3600 * -1) || - !X509_gmtime_adj(X509_getm_notAfter(x509.get()), 3600 * 24 * 365) || - !X509_set_version(x509.get(), 1) || !BN_rand(serial_number.get(), serialSize, 0, 0) || - !BN_to_ASN1_INTEGER(serial_number.get(), X509_get_serialNumber(x509.get())) || - !X509_NAME_add_entry_by_NID(name.get(), NID_commonName, MBSTRING_UTF8, commonNameBytes, -1, - -1, 0) || - !X509_set_subject_name(x509.get(), name.get()) || - !X509_set_issuer_name(x509.get(), name.get())) - RTC_THROW RTC_RUNTIME_ERROR("Unable to set certificate properties"); - - if (!X509_sign(x509.get(), pkey.get(), EVP_sha256())) - RTC_THROW RTC_RUNTIME_ERROR("Unable to auto-sign certificate"); - - return Certificate(x509, pkey); -} - -Certificate::Certificate(shared_ptr x509, shared_ptr pkey) - : mX509(std::move(x509)), mPKey(std::move(pkey)), mFingerprint(make_fingerprint(mX509.get())) {} - -std::tuple Certificate::credentials() const { - return {mX509.get(), mPKey.get()}; -} - -RTC_WRAPPED(string) make_fingerprint(X509 *x509) { - const size_t size = 32; - unsigned char buffer[size]; - unsigned int len = size; - if (!X509_digest(x509, EVP_sha256(), buffer, &len)) - RTC_THROW RTC_RUNTIME_ERROR("X509 fingerprint error"); - - std::ostringstream oss; - oss << std::hex << std::uppercase << std::setfill('0'); - for (size_t i = 0; i < len; ++i) { - if (i) - oss << std::setw(1) << ':'; - oss << std::setw(2) << unsigned(buffer[i]); - } - return oss.str(); -} - -#endif - -// Common for GnuTLS, Mbed TLS, and OpenSSL - -future_certificate_ptr make_certificate(CertificateType type) { - return ThreadPool::Instance().enqueue([type, token = Init::Instance().token()]() -> RTC_WRAPPED(certificate_ptr) { - RTC_BEGIN; - RTC_UNWRAP_RETHROW_DECL(auto, tmp, Certificate::Generate(type, "libdatachannel")); - return std::make_shared(tmp); - }); -} - -string Certificate::fingerprint() const { return mFingerprint; } - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/certificate.hpp b/godot/thirdparty/libdatachannel/src/impl/certificate.hpp deleted file mode 100644 index c25093a2..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/certificate.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_CERTIFICATE_H -#define RTC_IMPL_CERTIFICATE_H - -#include "common.hpp" -#include "configuration.hpp" // for CertificateType -#include "init.hpp" -#include "tls.hpp" - -#include -#include - -namespace rtc::impl { - -class Certificate { - RTC_WRAPPED_DEFAULT_CONSTRUCTABLE(Certificate); - Certificate() {} -public: - static RTC_WRAPPED(Certificate) FromString(string crt_pem, string key_pem); - static RTC_WRAPPED(Certificate) FromFile(const string &crt_pem_file, const string &key_pem_file, - const string &pass = ""); - static RTC_WRAPPED(Certificate) Generate(CertificateType type, const string &commonName); - -#if USE_GNUTLS - Certificate(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey); - gnutls_certificate_credentials_t credentials() const; -#elif USE_MBEDTLS - Certificate(shared_ptr crt, shared_ptr pk); - std::tuple, shared_ptr> credentials() const; -#else // OPENSSL - Certificate(shared_ptr x509, shared_ptr pkey); - std::tuple credentials() const; -#endif - - string fingerprint() const; - -private: - const init_token mInitToken = Init::Instance().token(); - -#if USE_GNUTLS - Certificate(shared_ptr creds); - const shared_ptr mCredentials; -#elif USE_MBEDTLS - const shared_ptr mCrt; - const shared_ptr mPk; -#else - const shared_ptr mX509; - const shared_ptr mPKey; -#endif - - const string mFingerprint; -}; - -#if USE_GNUTLS -string make_fingerprint(gnutls_certificate_credentials_t credentials); -string make_fingerprint(gnutls_x509_crt_t crt); -#elif USE_MBEDTLS -string make_fingerprint(mbedtls_x509_crt *crt); -#else -string make_fingerprint(X509 *x509); -#endif - -using certificate_ptr = shared_ptr; -using future_certificate_ptr = std::shared_future; - -future_certificate_ptr make_certificate(CertificateType type = CertificateType::Default); - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/channel.cpp b/godot/thirdparty/libdatachannel/src/impl/channel.cpp deleted file mode 100644 index 061d1cf1..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/channel.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "channel.hpp" -#include "internals.hpp" - -namespace rtc::impl { - -void Channel::triggerOpen() { - mOpenTriggered = true; - RTC_TRY { - openCallback(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - flushPendingMessages(); -} - -void Channel::triggerClosed() { - RTC_TRY { - closedCallback(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } -} - -void Channel::triggerError(string error) { - RTC_TRY { - errorCallback(std::move(error)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } -} - -void Channel::triggerAvailable(size_t count) { - if (count == 1) { - RTC_TRY { - availableCallback(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } - - flushPendingMessages(); -} - -void Channel::triggerBufferedAmount(size_t amount) { - size_t previous = bufferedAmount.exchange(amount); - size_t threshold = bufferedAmountLowThreshold.load(); - if (previous > threshold && amount <= threshold) { - RTC_TRY { - bufferedAmountLowCallback(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } -} - -void Channel::flushPendingMessages() { - if (!mOpenTriggered) - return; - - while (messageCallback) { - auto next = receive(); - if (!next) - break; - - RTC_TRY { - messageCallback(*next); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - } -} - -void Channel::resetOpenCallback() { - mOpenTriggered = false; - openCallback = nullptr; -} - -void Channel::resetCallbacks() { - mOpenTriggered = false; - openCallback = nullptr; - closedCallback = nullptr; - errorCallback = nullptr; - availableCallback = nullptr; - bufferedAmountLowCallback = nullptr; - messageCallback = nullptr; -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/channel.hpp b/godot/thirdparty/libdatachannel/src/impl/channel.hpp deleted file mode 100644 index 85093b8d..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/channel.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_CHANNEL_H -#define RTC_IMPL_CHANNEL_H - -#include "common.hpp" -#include "message.hpp" - -#include -#include - -namespace rtc::impl { - -struct Channel { - virtual optional receive() = 0; - virtual optional peek() = 0; - virtual size_t availableAmount() const = 0; - - virtual void triggerOpen(); - virtual void triggerClosed(); - virtual void triggerError(string error); - virtual void triggerAvailable(size_t count); - virtual void triggerBufferedAmount(size_t amount); - - void flushPendingMessages(); - void resetOpenCallback(); - void resetCallbacks(); - - synchronized_stored_callback<> openCallback; - synchronized_stored_callback<> closedCallback; - synchronized_stored_callback errorCallback; - synchronized_stored_callback<> availableCallback; - synchronized_stored_callback<> bufferedAmountLowCallback; - - synchronized_callback messageCallback; - - std::atomic bufferedAmount = 0; - std::atomic bufferedAmountLowThreshold = 0; - -private: - std::atomic mOpenTriggered = false; -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/datachannel.cpp b/godot/thirdparty/libdatachannel/src/impl/datachannel.cpp deleted file mode 100644 index 46fef553..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/datachannel.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "datachannel.hpp" -#include "common.hpp" -#include "internals.hpp" -#include "logcounter.hpp" -#include "peerconnection.hpp" -#include "sctptransport.hpp" - -#include "rtc/datachannel.hpp" -#include "rtc/track.hpp" - -#include - -#ifdef _WIN32 -#include -#else -#include -#endif - -using std::chrono::milliseconds; - -namespace rtc::impl { - -// Messages for the DataChannel establishment protocol (RFC 8832) -// See https://www.rfc-editor.org/rfc/rfc8832.html - -enum MessageType : uint8_t { - MESSAGE_OPEN_REQUEST = 0x00, - MESSAGE_OPEN_RESPONSE = 0x01, - MESSAGE_ACK = 0x02, - MESSAGE_OPEN = 0x03 -}; - -enum ChannelType : uint8_t { - CHANNEL_RELIABLE = 0x00, - CHANNEL_PARTIAL_RELIABLE_REXMIT = 0x01, - CHANNEL_PARTIAL_RELIABLE_TIMED = 0x02 -}; - -#pragma pack(push, 1) -struct OpenMessage { - uint8_t type = MESSAGE_OPEN; - uint8_t channelType; - uint16_t priority; - uint32_t reliabilityParameter; - uint16_t labelLength; - uint16_t protocolLength; - // The following fields are: - // uint8_t[labelLength] label - // uint8_t[protocolLength] protocol -}; - -struct AckMessage { - uint8_t type = MESSAGE_ACK; -}; - -#pragma pack(pop) - -bool DataChannel::IsOpenMessage(message_ptr message) { - if (message->type != Message::Control) - return false; - - auto raw = reinterpret_cast(message->data()); - return !message->empty() && raw[0] == MESSAGE_OPEN; -} - -DataChannel::DataChannel(weak_ptr pc, string label, string protocol, - Reliability reliability) - : mPeerConnection(pc), mLabel(std::move(label)), mProtocol(std::move(protocol)), - mReliability(std::make_shared(std::move(reliability))), - mRecvQueue(RECV_QUEUE_LIMIT, message_size_func) {} - -DataChannel::~DataChannel() { - PLOG_VERBOSE << "Destroying DataChannel"; - RTC_TRY { - close(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << e.RTC_WHAT(); - } -} - -void DataChannel::close() { - PLOG_VERBOSE << "Closing DataChannel"; - - shared_ptr transport; - { - std::shared_lock lock(mMutex); - transport = mSctpTransport.lock(); - } - - if (!mIsClosed.exchange(true)) { - if (transport && mStream.has_value()) - transport->closeStream(mStream.value()); - - triggerClosed(); - } - - resetCallbacks(); -} - -void DataChannel::remoteClose() { close(); } - -optional DataChannel::receive() { - auto next = mRecvQueue.pop(); - return next ? std::make_optional(to_variant(std::move(**next))) : nullopt; -} - -optional DataChannel::peek() { - auto next = mRecvQueue.peek(); - return next ? std::make_optional(to_variant(**next)) : nullopt; -} - -size_t DataChannel::availableAmount() const { return mRecvQueue.amount(); } - -optional DataChannel::stream() const { - std::shared_lock lock(mMutex); - return mStream; -} - -string DataChannel::label() const { - std::shared_lock lock(mMutex); - return mLabel; -} - -string DataChannel::protocol() const { - std::shared_lock lock(mMutex); - return mProtocol; -} - -Reliability DataChannel::reliability() const { - std::shared_lock lock(mMutex); - return *mReliability; -} - -bool DataChannel::isOpen(void) const { return !mIsClosed && mIsOpen; } - -bool DataChannel::isClosed(void) const { return mIsClosed; } - -size_t DataChannel::maxMessageSize() const { - auto pc = mPeerConnection.lock(); - return pc ? pc->remoteMaxMessageSize() : DEFAULT_MAX_MESSAGE_SIZE; -} - -RTC_WRAPPED(void) DataChannel::assignStream(uint16_t stream) { - std::unique_lock lock(mMutex); - - if (mStream.has_value()) - RTC_THROW RTC_LOGIC_ERROR("DataChannel already has a stream assigned"); - - mStream = stream; - RTC_RET; -} - -RTC_WRAPPED(void) DataChannel::open(shared_ptr transport) { - { - std::unique_lock lock(mMutex); - mSctpTransport = transport; - } - - if (!mIsClosed && !mIsOpen.exchange(true)) - triggerOpen(); - RTC_RET; -} - -RTC_WRAPPED(void) DataChannel::processOpenMessage(message_ptr) { - PLOG_WARNING << "Received an open message for a user-negotiated DataChannel, ignoring"; - RTC_RET; -} - -RTC_WRAPPED(bool) DataChannel::outgoing(message_ptr message) { - shared_ptr transport; - { - std::shared_lock lock(mMutex); - transport = mSctpTransport.lock(); - - if (!transport || mIsClosed) - RTC_THROW RTC_RUNTIME_ERROR("DataChannel is closed"); - - if (!mStream.has_value()) - RTC_THROW RTC_LOGIC_ERROR("DataChannel has no stream assigned"); - - if (message->size() > maxMessageSize()) - RTC_THROW RTC_INVALID_ARGUMENT("Message size exceeds limit"); - - // Before the ACK has been received on a DataChannel, all messages must be sent ordered - message->reliability = mIsOpen ? mReliability : nullptr; - message->stream = mStream.value(); - } - - return transport->send(message); -} - -RTC_WRAPPED(void) DataChannel::incoming(message_ptr message) { - RTC_BEGIN; - if (!message || mIsClosed) - RTC_RET; - - switch (message->type) { - case Message::Control: { - if (message->size() == 0) - break; // Ignore - auto raw = reinterpret_cast(message->data()); - switch (raw[0]) { - case MESSAGE_OPEN: - RTC_UNWRAP_RETHROW(processOpenMessage(message)); - break; - case MESSAGE_ACK: - if (!mIsOpen.exchange(true)) { - triggerOpen(); - } - break; - default: - // Ignore - break; - } - break; - } - case Message::Reset: - remoteClose(); - break; - case Message::String: - case Message::Binary: - mRecvQueue.push(message); - triggerAvailable(mRecvQueue.size()); - break; - default: - // Ignore - break; - } - RTC_RET; -} - -OutgoingDataChannel::OutgoingDataChannel(weak_ptr pc, string label, string protocol, - Reliability reliability) - : DataChannel(pc, std::move(label), std::move(protocol), std::move(reliability)) {} - -OutgoingDataChannel::~OutgoingDataChannel() {} - -RTC_WRAPPED(void) OutgoingDataChannel::open(shared_ptr transport) { - RTC_BEGIN; - std::unique_lock lock(mMutex); - mSctpTransport = transport; - - if (!mStream.has_value()) - RTC_THROW RTC_RUNTIME_ERROR("DataChannel has no stream assigned"); - - uint8_t channelType; - uint32_t reliabilityParameter; - switch (mReliability->type) { - case Reliability::Type::Rexmit: - channelType = CHANNEL_PARTIAL_RELIABLE_REXMIT; - reliabilityParameter = uint32_t(std::max(std::get(mReliability->rexmit), 0)); - break; - - case Reliability::Type::Timed: - channelType = CHANNEL_PARTIAL_RELIABLE_TIMED; - reliabilityParameter = uint32_t(std::get(mReliability->rexmit).count()); - break; - - default: - channelType = CHANNEL_RELIABLE; - reliabilityParameter = 0; - break; - } - - if (mReliability->unordered) - channelType |= 0x80; - - const size_t len = sizeof(OpenMessage) + mLabel.size() + mProtocol.size(); - binary buffer(len, byte(0)); - auto &open = *reinterpret_cast(buffer.data()); - open.type = MESSAGE_OPEN; - open.channelType = channelType; - open.priority = htons(0); - open.reliabilityParameter = htonl(reliabilityParameter); - open.labelLength = htons(uint16_t(mLabel.size())); - open.protocolLength = htons(uint16_t(mProtocol.size())); - - auto end = reinterpret_cast(buffer.data() + sizeof(OpenMessage)); - std::copy(mLabel.begin(), mLabel.end(), end); - std::copy(mProtocol.begin(), mProtocol.end(), end + mLabel.size()); - - lock.unlock(); - - RTC_UNWRAP_RETHROW(transport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream.value()))); - RTC_RET; -} - -RTC_WRAPPED(void) OutgoingDataChannel::processOpenMessage(message_ptr) { - PLOG_WARNING << "Received an open message for a locally-created DataChannel, ignoring"; - RTC_RET; -} - -IncomingDataChannel::IncomingDataChannel(weak_ptr pc, - weak_ptr transport) - : DataChannel(pc, "", "", {}) { - - mSctpTransport = transport; -} - -IncomingDataChannel::~IncomingDataChannel() {} - -RTC_WRAPPED(void) IncomingDataChannel::open(shared_ptr) { - // Ignore - RTC_RET; -} - -RTC_WRAPPED(void) IncomingDataChannel::processOpenMessage(message_ptr message) { - RTC_BEGIN; - std::unique_lock lock(mMutex); - auto transport = mSctpTransport.lock(); - if (!transport) - RTC_THROW RTC_LOGIC_ERROR("DataChannel has no transport"); - - if (!mStream.has_value()) - RTC_THROW RTC_LOGIC_ERROR("DataChannel has no stream assigned"); - - if (message->size() < sizeof(OpenMessage)) - RTC_THROW RTC_INVALID_ARGUMENT("DataChannel open message too small"); - - OpenMessage open = *reinterpret_cast(message->data()); - open.priority = ntohs(open.priority); - open.reliabilityParameter = ntohl(open.reliabilityParameter); - open.labelLength = ntohs(open.labelLength); - open.protocolLength = ntohs(open.protocolLength); - - if (message->size() < sizeof(OpenMessage) + size_t(open.labelLength + open.protocolLength)) - RTC_THROW RTC_INVALID_ARGUMENT("DataChannel open message truncated"); - - auto end = reinterpret_cast(message->data() + sizeof(OpenMessage)); - mLabel.assign(end, open.labelLength); - mProtocol.assign(end + open.labelLength, open.protocolLength); - - mReliability->unordered = (open.channelType & 0x80) != 0; - switch (open.channelType & 0x7F) { - case CHANNEL_PARTIAL_RELIABLE_REXMIT: - mReliability->type = Reliability::Type::Rexmit; - mReliability->rexmit = int(open.reliabilityParameter); - break; - case CHANNEL_PARTIAL_RELIABLE_TIMED: - mReliability->type = Reliability::Type::Timed; - mReliability->rexmit = milliseconds(open.reliabilityParameter); - break; - default: - mReliability->type = Reliability::Type::Reliable; - mReliability->rexmit = int(0); - } - - lock.unlock(); - - binary buffer(sizeof(AckMessage), byte(0)); - auto &ack = *reinterpret_cast(buffer.data()); - ack.type = MESSAGE_ACK; - - RTC_UNWRAP_RETHROW(transport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream.value()))); - - if (!mIsOpen.exchange(true)) - triggerOpen(); - RTC_RET; -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/datachannel.hpp b/godot/thirdparty/libdatachannel/src/impl/datachannel.hpp deleted file mode 100644 index 0080bb24..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/datachannel.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_DATA_CHANNEL_H -#define RTC_IMPL_DATA_CHANNEL_H - -#include "channel.hpp" -#include "common.hpp" -#include "message.hpp" -#include "peerconnection.hpp" -#include "queue.hpp" -#include "reliability.hpp" -#include "sctptransport.hpp" - -#include -#include - -namespace rtc::impl { - -struct PeerConnection; - -struct DataChannel : Channel, std::enable_shared_from_this { - static bool IsOpenMessage(message_ptr message); - - DataChannel(weak_ptr pc, string label, string protocol, - Reliability reliability); - virtual ~DataChannel(); - - void close(); - void remoteClose(); - RTC_WRAPPED(bool) outgoing(message_ptr message); - RTC_WRAPPED(void) incoming(message_ptr message); - - optional receive() override; - optional peek() override; - size_t availableAmount() const override; - - optional stream() const; - string label() const; - string protocol() const; - Reliability reliability() const; - - bool isOpen(void) const; - bool isClosed(void) const; - size_t maxMessageSize() const; - - virtual RTC_WRAPPED(void) assignStream(uint16_t stream); - virtual RTC_WRAPPED(void) open(shared_ptr transport); - virtual RTC_WRAPPED(void) processOpenMessage(message_ptr); - -protected: - const weak_ptr mPeerConnection; - weak_ptr mSctpTransport; - - optional mStream; - string mLabel; - string mProtocol; - shared_ptr mReliability; - - mutable std::shared_mutex mMutex; - - std::atomic mIsOpen = false; - std::atomic mIsClosed = false; - -private: - Queue mRecvQueue; -}; - -struct OutgoingDataChannel final : public DataChannel { - OutgoingDataChannel(weak_ptr pc, string label, string protocol, - Reliability reliability); - ~OutgoingDataChannel(); - - RTC_WRAPPED(void) open(shared_ptr transport) override; - RTC_WRAPPED(void) processOpenMessage(message_ptr message) override; -}; - -struct IncomingDataChannel final : public DataChannel { - IncomingDataChannel(weak_ptr pc, weak_ptr transport); - ~IncomingDataChannel(); - - RTC_WRAPPED(void) open(shared_ptr transport) override; - RTC_WRAPPED(void) processOpenMessage(message_ptr message) override; -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/dtlstransport.cpp b/godot/thirdparty/libdatachannel/src/impl/dtlstransport.cpp deleted file mode 100644 index ded4f680..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/dtlstransport.cpp +++ /dev/null @@ -1,1113 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "dtlstransport.hpp" -#include "icetransport.hpp" -#include "internals.hpp" -#include "threadpool.hpp" - -#include -#include -#include -#include - -#if !USE_GNUTLS -#ifdef _WIN32 -#include // for timeval -#else -#include // for timeval -#endif -#endif - -using namespace std::chrono; - -namespace rtc::impl { - -void DtlsTransport::enqueueRecv() { - if (mPendingRecvCount > 0) - return; - - if (auto shared_this = weak_from_this().lock()) { - ++mPendingRecvCount; - ThreadPool::Instance().enqueue(&DtlsTransport::doRecv, std::move(shared_this)); - } -} - -#if USE_GNUTLS - -void DtlsTransport::Init() { - gnutls_global_init(); // optional -} - -void DtlsTransport::Cleanup() { gnutls_global_deinit(); } - -DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate - optional mtu, verifier_callback verifierCallback, - state_callback stateChangeCallback) - : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate), - mVerifierCallback(std::move(verifierCallback)), - mIsClient(lower->role() == Description::Role::Active) { -} - -RTC_WRAPPED(void) DtlsTransport::construct() { - PLOG_DEBUG << "Initializing DTLS transport (GnuTLS)"; - - if (!mCertificate) - RTC_THROW RTC_INVALID_ARGUMENT("DTLS certificate is null"); - - gnutls_certificate_credentials_t creds = mCertificate->credentials(); - gnutls_certificate_set_verify_function(creds, CertificateCallback); - - unsigned int flags = - GNUTLS_DATAGRAM | GNUTLS_NONBLOCK | (mIsClient ? GNUTLS_CLIENT : GNUTLS_SERVER); - gnutls::check(gnutls_init(&mSession, flags)); - - RTC_TRY { - // RFC 8261: SCTP performs segmentation and reassembly based on the path MTU. - // Therefore, the DTLS layer MUST NOT use any compression algorithm. - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 - const char *priorities = "SECURE128:-VERS-SSL3.0:-ARCFOUR-128:-COMP-ALL:+COMP-NULL"; - const char *err_pos = NULL; - gnutls::check(gnutls_priority_set_direct(mSession, priorities, &err_pos), - "Failed to set TLS priorities"); - - // RFC 8827: The DTLS-SRTP protection profile SRTP_AES128_CM_HMAC_SHA1_80 MUST be supported - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - gnutls::check(gnutls_srtp_set_profile(mSession, GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80), - "Failed to set SRTP profile"); - - gnutls::check(gnutls_credentials_set(mSession, GNUTLS_CRD_CERTIFICATE, creds)); - - gnutls_dtls_set_timeouts(mSession, - 1000, // 1s retransmission timeout recommended by RFC 6347 - 30000); // 30s total timeout - gnutls_handshake_set_timeout(mSession, 30000); - - gnutls_session_set_ptr(mSession, this); - gnutls_transport_set_ptr(mSession, this); - gnutls_transport_set_push_function(mSession, WriteCallback); - gnutls_transport_set_pull_function(mSession, ReadCallback); - gnutls_transport_set_pull_timeout_function(mSession, TimeoutCallback); - - } RTC_CATCH (...) { - gnutls_deinit(mSession); - RTC_RETHROW; - } - - // Set recommended medium-priority DSCP value for handshake - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability - RTC_RET; -} - -DtlsTransport::~DtlsTransport() { - stop(); - - PLOG_DEBUG << "Destroying DTLS transport"; - gnutls_deinit(mSession); -} - -RTC_WRAPPED(void) DtlsTransport::start() { - PLOG_DEBUG << "Starting DTLS transport"; - registerIncoming(); - changeState(State::Connecting); - - size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6 - gnutls_dtls_set_mtu(mSession, static_cast(mtu)); - PLOG_VERBOSE << "DTLS MTU set to " << mtu; - - enqueueRecv(); // to initiate the handshake -} - -void DtlsTransport::stop() { - PLOG_DEBUG << "Stopping DTLS transport"; - unregisterIncoming(); - mIncomingQueue.stop(); - enqueueRecv(); -} - -bool DtlsTransport::send(message_ptr message) { - if (!message || state() != State::Connected) - return false; - - PLOG_VERBOSE << "Send size=" << message->size(); - - ssize_t ret; - do { - std::lock_guard lock(mSendMutex); - mCurrentDscp = message->dscp; - ret = gnutls_record_send(mSession, message->data(), message->size()); - } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - - if (ret == GNUTLS_E_LARGE_PACKET) - return false; - - if (!gnutls::check(ret)) - return false; - - return mOutgoingResult; -} - -void DtlsTransport::incoming(message_ptr message) { - if (!message) { - mIncomingQueue.stop(); - return; - } - - PLOG_VERBOSE << "Incoming size=" << message->size(); - mIncomingQueue.push(message); - enqueueRecv(); -} - -bool DtlsTransport::outgoing(message_ptr message) { - message->dscp = mCurrentDscp; - - bool result = Transport::outgoing(std::move(message)); - mOutgoingResult = result; - return result; -} - -bool DtlsTransport::demuxMessage(message_ptr) { - // Dummy - return false; -} - -void DtlsTransport::postHandshake() { - // Dummy -} - -void DtlsTransport::doRecv() { - std::lock_guard lock(mRecvMutex); - --mPendingRecvCount; - - if (state() != State::Connecting && state() != State::Connected) - return; - - RTC_TRY { - const size_t bufferSize = 4096; - char buffer[bufferSize]; - - // Handle handshake if connecting - if (state() == State::Connecting) { - int ret; - do { - ret = gnutls_handshake(mSession); - - if (ret == GNUTLS_E_AGAIN) { - // Schedule next call on timeout and return - auto timeout = milliseconds(gnutls_dtls_get_timeout(mSession)); - ThreadPool::Instance().schedule(timeout, [weak_this = weak_from_this()]() { - if (auto locked = weak_this.lock()) - locked->doRecv(); - }); - return; - } - - if (ret == GNUTLS_E_LARGE_PACKET) { - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("MTU is too low")); - } - - } while (!gnutls::check(ret, "Handshake failed")); // Re-call on non-fatal error - - // RFC 8261: DTLS MUST support sending messages larger than the current path MTU - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 - gnutls_dtls_set_mtu(mSession, bufferSize + 1); - - PLOG_INFO << "DTLS handshake finished"; - changeState(State::Connected); - postHandshake(); - } - - if (state() == State::Connected) { - while (true) { - ssize_t ret = gnutls_record_recv(mSession, buffer, bufferSize); - - if (ret == GNUTLS_E_AGAIN) { - return; - } - - // RFC 8827: Implementations MUST NOT implement DTLS renegotiation and MUST reject - // it with a "no_renegotiation" alert if offered. See - // https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - if (ret == GNUTLS_E_REHANDSHAKE) { - do { - std::lock_guard lock(mSendMutex); - ret = gnutls_alert_send(mSession, GNUTLS_AL_WARNING, - GNUTLS_A_NO_RENEGOTIATION); - } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - continue; - } - - // Consider premature termination as remote closing - if (ret == GNUTLS_E_PREMATURE_TERMINATION) { - PLOG_DEBUG << "DTLS connection terminated"; - break; - } - - if (gnutls::check(ret)) { - if (ret == 0) { - // Closed - PLOG_DEBUG << "DTLS connection cleanly closed"; - break; - } - auto *b = reinterpret_cast(buffer); - recv(make_message(b, b + ret)); - } - } - } - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << "DTLS recv: " << e.RTC_WHAT(); - } - - gnutls_bye(mSession, GNUTLS_SHUT_WR); - - if (state() == State::Connected) { - PLOG_INFO << "DTLS closed"; - changeState(State::Disconnected); - recv(nullptr); - } else { - PLOG_ERROR << "DTLS handshake failed"; - changeState(State::Failed); - } -} - -int DtlsTransport::CertificateCallback(gnutls_session_t session) { - DtlsTransport *t = static_cast(gnutls_session_get_ptr(session)); - RTC_TRY { - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { - return GNUTLS_E_CERTIFICATE_ERROR; - } - - unsigned int count = 0; - const gnutls_datum_t *array = gnutls_certificate_get_peers(session, &count); - if (!array || count == 0) { - return GNUTLS_E_CERTIFICATE_ERROR; - } - - gnutls_x509_crt_t crt; - gnutls::check(gnutls_x509_crt_init(&crt)); - int ret = gnutls_x509_crt_import(crt, &array[0], GNUTLS_X509_FMT_DER); - if (ret != GNUTLS_E_SUCCESS) { - gnutls_x509_crt_deinit(crt); - return GNUTLS_E_CERTIFICATE_ERROR; - } - - string fingerprint = make_fingerprint(crt); - gnutls_x509_crt_deinit(crt); - - bool success = t->mVerifierCallback(fingerprint); - return success ? GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR; - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - return GNUTLS_E_CERTIFICATE_ERROR; - } -} - -ssize_t DtlsTransport::WriteCallback(gnutls_transport_ptr_t ptr, const void *data, size_t len) { - DtlsTransport *t = static_cast(ptr); - RTC_TRY { - if (len > 0) { - auto b = reinterpret_cast(data); - t->outgoing(make_message(b, b + len)); - } - gnutls_transport_set_errno(t->mSession, 0); - return ssize_t(len); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - gnutls_transport_set_errno(t->mSession, ECONNRESET); - return -1; - } -} - -ssize_t DtlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_t maxlen) { - DtlsTransport *t = static_cast(ptr); - RTC_TRY { - while (t->mIncomingQueue.running()) { - auto next = t->mIncomingQueue.pop(); - if (!next) { - gnutls_transport_set_errno(t->mSession, EAGAIN); - return -1; - } - - message_ptr message = std::move(*next); - if (t->demuxMessage(message)) - continue; - - ssize_t len = std::min(maxlen, message->size()); - std::memcpy(data, message->data(), len); - gnutls_transport_set_errno(t->mSession, 0); - return len; - } - - // Closed - gnutls_transport_set_errno(t->mSession, 0); - return 0; - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - gnutls_transport_set_errno(t->mSession, ECONNRESET); - return -1; - } -} - -int DtlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int /* ms */) { - DtlsTransport *t = static_cast(ptr); - RTC_TRY { - return !t->mIncomingQueue.empty() ? 1 : 0; - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - return 1; - } -} - -#elif USE_MBEDTLS - -#if RTC_ENABLE_MEDIA // Godot added -const mbedtls_ssl_srtp_profile srtpSupportedProtectionProfiles[] = { - MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80, - MBEDTLS_TLS_SRTP_UNSET, -}; -#endif // RTC_ENABLE_MEDIA - -DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate, - optional mtu, verifier_callback verifierCallback, - state_callback stateChangeCallback) - : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), - mVerifierCallback(std::move(verifierCallback)), - mIsClient(lower->role() == Description::Role::Active) { -} - -RTC_WRAPPED(void) DtlsTransport::construct() { - PLOG_DEBUG << "Initializing DTLS transport (MbedTLS)"; - - if (!mCertificate) - RTC_THROW RTC_INVALID_ARGUMENT("DTLS certificate is null"); - - mbedtls_entropy_init(&mEntropy); - mbedtls_ctr_drbg_init(&mDrbg); - mbedtls_ssl_init(&mSsl); - mbedtls_ssl_config_init(&mConf); - mbedtls_ctr_drbg_set_prediction_resistance(&mDrbg, MBEDTLS_CTR_DRBG_PR_ON); - - RTC_TRY { - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ctr_drbg_seed(&mDrbg, mbedtls_entropy_func, &mEntropy, NULL, 0), - "Failed creating Mbed TLS Context")); - - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ssl_config_defaults( - &mConf, mIsClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT), - "Failed creating Mbed TLS Context")); - - mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_verify(&mConf, DtlsTransport::CertificateCallback, this); - - mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mDrbg); - - auto [crt, pk] = mCertificate->credentials(); - auto crt_ = crt; - auto pk_ = pk; - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ssl_conf_own_cert(&mConf, crt_.get(), pk_.get()), - "Failed creating Mbed TLS Context")); - - mbedtls_ssl_conf_dtls_cookies(&mConf, NULL, NULL, NULL); -#if RTC_ENABLE_MEDIA // Godot added - mbedtls_ssl_conf_dtls_srtp_protection_profiles(&mConf, srtpSupportedProtectionProfiles); -#endif // RTC_ENABLE_MEDIA - - RTC_UNWRAP_CATCH(mbedtls::check(mbedtls_ssl_setup(&mSsl, &mConf), "Failed creating Mbed TLS Context")); - - mbedtls_ssl_set_export_keys_cb(&mSsl, DtlsTransport::ExportKeysCallback, this); - mbedtls_ssl_set_bio(&mSsl, this, WriteCallback, ReadCallback, NULL); - mbedtls_ssl_set_timer_cb(&mSsl, this, SetTimerCallback, GetTimerCallback); - - } RTC_CATCH (...) { - mbedtls_entropy_free(&mEntropy); - mbedtls_ctr_drbg_free(&mDrbg); - mbedtls_ssl_free(&mSsl); - mbedtls_ssl_config_free(&mConf); - RTC_RETHROW; - } - - // Set recommended medium-priority DSCP value for handshake - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability - RTC_RET; -} - -DtlsTransport::~DtlsTransport() { - stop(); - - PLOG_DEBUG << "Destroying DTLS transport"; - mbedtls_entropy_free(&mEntropy); - mbedtls_ctr_drbg_free(&mDrbg); - mbedtls_ssl_free(&mSsl); - mbedtls_ssl_config_free(&mConf); -} - -void DtlsTransport::Init() { - // Nothing to do -} - -void DtlsTransport::Cleanup() { - // Nothing to do -} - -RTC_WRAPPED(void) DtlsTransport::start() { - PLOG_DEBUG << "Starting DTLS transport"; - registerIncoming(); - changeState(State::Connecting); - - { - std::lock_guard lock(mSslMutex); - size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6 - mbedtls_ssl_set_mtu(&mSsl, static_cast(mtu)); - PLOG_VERBOSE << "DTLS MTU set to " << mtu; - } - - enqueueRecv(); // to initiate the handshake - RTC_RET; -} - -void DtlsTransport::stop() { - PLOG_DEBUG << "Stopping DTLS transport"; - unregisterIncoming(); - mIncomingQueue.stop(); - enqueueRecv(); -} - -RTC_WRAPPED(bool) DtlsTransport::send(message_ptr message) { - if (!message || state() != State::Connected) - return false; - - PLOG_VERBOSE << "Send size=" << message->size(); - - int ret; - do { - std::lock_guard lock(mSslMutex); - if (message->size() > size_t(mbedtls_ssl_get_max_out_record_payload(&mSsl))) - return false; - - mCurrentDscp = message->dscp; - ret = mbedtls_ssl_write(&mSsl, reinterpret_cast(message->data()), - message->size()); - RTC_BEGIN; - RTC_UNWRAP_RETHROW_DECL(bool, cond, mbedtls::check(ret)); - if (cond) { - break; - } - } while (1); - - return (bool)mOutgoingResult; -} - -void DtlsTransport::incoming(message_ptr message) { - if (!message) { - mIncomingQueue.stop(); - return; - } - - PLOG_VERBOSE << "Incoming size=" << message->size(); - mIncomingQueue.push(message); - enqueueRecv(); -} - -RTC_WRAPPED(bool) DtlsTransport::outgoing(message_ptr message) { - RTC_BEGIN; - message->dscp = mCurrentDscp; - - RTC_UNWRAP_RETHROW_DECL(bool, result, Transport::outgoing(std::move(message))); - mOutgoingResult = result; - return result; -} - -bool DtlsTransport::demuxMessage(message_ptr) { - // Dummy - return false; -} - -void DtlsTransport::postHandshake() { - // Dummy -} - -void DtlsTransport::doRecv() { - std::lock_guard lock(mRecvMutex); - --mPendingRecvCount; - - if (state() != State::Connecting && state() != State::Connected) - return; - - RTC_TRY { - const size_t bufferSize = 4096; - char buffer[bufferSize]; - - // Handle handshake if connecting - if (state() == State::Connecting) { - while (true) { - int ret; - { - std::lock_guard lock(mSslMutex); - ret = mbedtls_ssl_handshake(&mSsl); - } - - if (ret == MBEDTLS_ERR_SSL_WANT_READ) { - ThreadPool::Instance().schedule(mTimerSetAt + milliseconds(mFinMs), - [weak_this = weak_from_this()]() { - if (auto locked = weak_this.lock()) - locked->doRecv(); - }); - return; - } - - RTC_UNWRAP_CATCH_DECL(bool, res, mbedtls::check(ret, "Handshake failed")); - if (res) { - // RFC 8261: DTLS MUST support sending messages larger than the current path MTU - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 - { - std::lock_guard lock(mSslMutex); - mbedtls_ssl_set_mtu(&mSsl, static_cast(bufferSize + 1)); - } - - PLOG_INFO << "DTLS handshake finished"; - changeState(State::Connected); - postHandshake(); - break; - } - } - } - - if (state() == State::Connected) { - while (true) { - int ret; - { - std::lock_guard lock(mSslMutex); - ret = mbedtls_ssl_read(&mSsl, reinterpret_cast(buffer), - bufferSize); - } - - if (ret == MBEDTLS_ERR_SSL_WANT_READ) { - return; - } - - if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - PLOG_DEBUG << "DTLS connection cleanly closed"; - break; - } - - RTC_UNWRAP_CATCH_DECL(bool, res, mbedtls::check(ret, "Handshake failed")); - if (res) { - if (ret == 0) { - PLOG_DEBUG << "DTLS connection terminated"; - break; - } - auto *b = reinterpret_cast(buffer); - recv(make_message(b, b + ret)); - } - } - } - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << "DTLS recv: " << e.RTC_WHAT(); - } - - if (state() == State::Connected) { - PLOG_INFO << "DTLS closed"; - changeState(State::Disconnected); - recv(nullptr); - } else { - PLOG_ERROR << "DTLS handshake failed"; - changeState(State::Failed); - } -} - -int DtlsTransport::CertificateCallback(void *ctx, mbedtls_x509_crt *crt, int /*depth*/, - uint32_t * /*flags*/) { - auto this_ = static_cast(ctx); - string fingerprint = make_fingerprint(crt); - std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(), - [](char c) { return char(std::toupper(c)); }); - return this_->mVerifierCallback(fingerprint) ? 0 : 1; -} - -void DtlsTransport::ExportKeysCallback(void *ctx, mbedtls_ssl_key_export_type /*type*/, - const unsigned char *secret, size_t secret_len, - const unsigned char client_random[32], - const unsigned char server_random[32], - mbedtls_tls_prf_types tls_prf_type) { - auto dtlsTransport = static_cast(ctx); - std::memcpy(dtlsTransport->mMasterSecret, secret, secret_len); - std::memcpy(dtlsTransport->mRandBytes, client_random, 32); - std::memcpy(dtlsTransport->mRandBytes + 32, server_random, 32); - dtlsTransport->mTlsProfile = tls_prf_type; -} - -int DtlsTransport::WriteCallback(void *ctx, const unsigned char *buf, size_t len) { - auto *t = static_cast(ctx); - RTC_TRY { - if (len > 0) { - auto b = reinterpret_cast(buf); - RTC_UNWRAP_CATCH(t->outgoing(make_message(b, b + len))); - } - return int(len); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - return MBEDTLS_ERR_SSL_INTERNAL_ERROR; - } -} - -int DtlsTransport::ReadCallback(void *ctx, unsigned char *buf, size_t len) { - auto *t = static_cast(ctx); - RTC_TRY { - while (t->mIncomingQueue.running()) { - auto next = t->mIncomingQueue.pop(); - if (!next) { - return MBEDTLS_ERR_SSL_WANT_READ; - } - - message_ptr message = std::move(*next); - if (t->demuxMessage(message)) - continue; - - auto bufMin = std::min(len, size_t(message->size())); - std::memcpy(buf, message->data(), bufMin); - return int(len); - } - - // Closed - return 0; - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - return MBEDTLS_ERR_SSL_INTERNAL_ERROR; - ; - } -} - -void DtlsTransport::SetTimerCallback(void *ctx, uint32_t int_ms, uint32_t fin_ms) { - auto dtlsTransport = static_cast(ctx); - dtlsTransport->mIntMs = int_ms; - dtlsTransport->mFinMs = fin_ms; - - if (fin_ms != 0) { - dtlsTransport->mTimerSetAt = std::chrono::steady_clock::now(); - } -} - -int DtlsTransport::GetTimerCallback(void *ctx) { - auto dtlsTransport = static_cast(ctx); - auto now = std::chrono::steady_clock::now(); - - if (dtlsTransport->mFinMs == 0) { - return -1; - } else if (now >= dtlsTransport->mTimerSetAt + milliseconds(dtlsTransport->mFinMs)) { - return 2; - } else if (now >= dtlsTransport->mTimerSetAt + milliseconds(dtlsTransport->mIntMs)) { - return 1; - } else { - return 0; - } -} - -#else // OPENSSL - -BIO_METHOD *DtlsTransport::BioMethods = NULL; -int DtlsTransport::TransportExIndex = -1; -std::mutex DtlsTransport::GlobalMutex; - -void DtlsTransport::Init() { - std::lock_guard lock(GlobalMutex); - - openssl::init(); - - if (!BioMethods) { - BioMethods = BIO_meth_new(BIO_TYPE_BIO, "DTLS writer"); - if (!BioMethods) - PLOG_ERROR << "Failed to create BIO methods for DTLS writer"; - BIO_meth_set_create(BioMethods, BioMethodNew); - BIO_meth_set_destroy(BioMethods, BioMethodFree); - BIO_meth_set_write(BioMethods, BioMethodWrite); - BIO_meth_set_ctrl(BioMethods, BioMethodCtrl); - } - if (TransportExIndex < 0) { - TransportExIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - } -} - -void DtlsTransport::Cleanup() { - // Nothing to do -} - -DtlsTransport::DtlsTransport(shared_ptr lower, certificate_ptr certificate, - optional mtu, verifier_callback verifierCallback, - state_callback stateChangeCallback) - : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate), - mVerifierCallback(std::move(verifierCallback)), - mIsClient(lower->role() == Description::Role::Active) { -} - -RTC_WRAPPED(void) DtlsTransport::construct() { - PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)"; - - if (!mCertificate) - RTC_THROW RTC_INVALID_ARGUMENT("DTLS certificate is null"); - - RTC_TRY { - mCtx = SSL_CTX_new(DTLS_method()); - if (!mCtx) - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to create SSL context")); - - // RFC 8261: SCTP performs segmentation and reassembly based on the path MTU. - // Therefore, the DTLS layer MUST NOT use any compression algorithm. - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 - // RFC 8827: Implementations MUST NOT implement DTLS renegotiation - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 - SSL_CTX_set_options(mCtx, SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_NO_QUERY_MTU | - SSL_OP_NO_RENEGOTIATION); - - SSL_CTX_set_min_proto_version(mCtx, DTLS1_VERSION); - SSL_CTX_set_read_ahead(mCtx, 1); - SSL_CTX_set_quiet_shutdown(mCtx, 0); // send the close_notify alert - SSL_CTX_set_info_callback(mCtx, InfoCallback); - - SSL_CTX_set_verify(mCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - CertificateCallback); - SSL_CTX_set_verify_depth(mCtx, 1); - - openssl::check(SSL_CTX_set_cipher_list(mCtx, "ALL:!LOW:!EXP:!RC4:!MD5:@STRENGTH"), - "Failed to set SSL priorities"); - -#if OPENSSL_VERSION_NUMBER >= 0x30000000 - openssl::check(SSL_CTX_set1_groups_list(mCtx, "P-256"), "Failed to set SSL groups"); -#else - auto ecdh = unique_ptr( - EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), EC_KEY_free); - SSL_CTX_set_tmp_ecdh(mCtx, ecdh.get()); - SSL_CTX_set_options(mCtx, SSL_OP_SINGLE_ECDH_USE); -#endif - - auto [x509, pkey] = mCertificate->credentials(); - SSL_CTX_use_certificate(mCtx, x509); - SSL_CTX_use_PrivateKey(mCtx, pkey); - openssl::check(SSL_CTX_check_private_key(mCtx), "SSL local private key check failed"); - - mSsl = SSL_new(mCtx); - if (!mSsl) - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to create SSL instance")); - - SSL_set_ex_data(mSsl, TransportExIndex, this); - - if (mIsClient) - SSL_set_connect_state(mSsl); - else - SSL_set_accept_state(mSsl); - - mInBio = BIO_new(BIO_s_mem()); - mOutBio = BIO_new(BioMethods); - if (!mInBio || !mOutBio) - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to create BIO")); - - BIO_set_mem_eof_return(mInBio, BIO_EOF); - BIO_set_data(mOutBio, this); - SSL_set_bio(mSsl, mInBio, mOutBio); - - // RFC 8827: The DTLS-SRTP protection profile SRTP_AES128_CM_HMAC_SHA1_80 MUST be supported - // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 Warning: - // SSL_set_tlsext_use_srtp() returns 0 on success and 1 on error - // Try to use GCM suite - if (SSL_set_tlsext_use_srtp( - mSsl, "SRTP_AEAD_AES_256_GCM:SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80")) { - if (SSL_set_tlsext_use_srtp(mSsl, "SRTP_AES128_CM_SHA1_80")) - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Failed to set SRTP profile: " + - openssl::error_string(ERR_get_error()))); - } - - } RTC_CATCH (...) { - if (mSsl) - SSL_free(mSsl); - if (mCtx) - SSL_CTX_free(mCtx); - RTC_RETHROW; - } - - // Set recommended medium-priority DSCP value for handshake - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability - RTC_RET; -} - -DtlsTransport::~DtlsTransport() { - stop(); - - PLOG_DEBUG << "Destroying DTLS transport"; - SSL_free(mSsl); - SSL_CTX_free(mCtx); -} - -void DtlsTransport::start() { - PLOG_DEBUG << "Starting DTLS transport"; - registerIncoming(); - changeState(State::Connecting); - - int ret, err; - { - std::lock_guard lock(mSslMutex); - - size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6 - SSL_set_mtu(mSsl, static_cast(mtu)); - PLOG_VERBOSE << "DTLS MTU set to " << mtu; - - // Initiate the handshake - ret = SSL_do_handshake(mSsl); - err = SSL_get_error(mSsl, ret); - } - - openssl::check_error(err, "Handshake failed"); - - handleTimeout(); -} - -void DtlsTransport::stop() { - PLOG_DEBUG << "Stopping DTLS transport"; - unregisterIncoming(); - mIncomingQueue.stop(); - enqueueRecv(); -} - -bool DtlsTransport::send(message_ptr message) { - if (!message || state() != State::Connected) - return false; - - PLOG_VERBOSE << "Send size=" << message->size(); - - int ret, err; - { - std::lock_guard lock(mSslMutex); - mCurrentDscp = message->dscp; - ret = SSL_write(mSsl, message->data(), int(message->size())); - err = SSL_get_error(mSsl, ret); - } - - if (!openssl::check_error(err)) - return false; - - return mOutgoingResult; -} - -void DtlsTransport::incoming(message_ptr message) { - if (!message) { - mIncomingQueue.stop(); - enqueueRecv(); - return; - } - - PLOG_VERBOSE << "Incoming size=" << message->size(); - mIncomingQueue.push(message); - enqueueRecv(); -} - -bool DtlsTransport::outgoing(message_ptr message) { - message->dscp = mCurrentDscp; - - bool result = Transport::outgoing(std::move(message)); - mOutgoingResult = result; - return result; -} - -bool DtlsTransport::demuxMessage(message_ptr) { - // Dummy - return false; -} - -void DtlsTransport::postHandshake() { - // Dummy -} - -void DtlsTransport::doRecv() { - std::lock_guard lock(mRecvMutex); - --mPendingRecvCount; - - if (state() != State::Connecting && state() != State::Connected) - return; - - RTC_TRY { - const size_t bufferSize = 4096; - byte buffer[bufferSize]; - - // Process pending messages - while (mIncomingQueue.running()) { - auto next = mIncomingQueue.pop(); - if (!next) { - // No more messages pending, handle timeout if connecting - if (state() == State::Connecting) - handleTimeout(); - - return; - } - - message_ptr message = std::move(*next); - if (demuxMessage(message)) - continue; - - BIO_write(mInBio, message->data(), int(message->size())); - - if (state() == State::Connecting) { - // Continue the handshake - int ret, err; - { - std::lock_guard lock(mSslMutex); - ret = SSL_do_handshake(mSsl); - err = SSL_get_error(mSsl, ret); - } - - if (openssl::check_error(err, "Handshake failed")) { - // RFC 8261: DTLS MUST support sending messages larger than the current path MTU - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 - { - std::lock_guard lock(mSslMutex); - SSL_set_mtu(mSsl, bufferSize + 1); - } - - PLOG_INFO << "DTLS handshake finished"; - postHandshake(); - changeState(State::Connected); - } - } - - if (state() == State::Connected) { - int ret, err; - { - std::lock_guard lock(mSslMutex); - ret = SSL_read(mSsl, buffer, bufferSize); - err = SSL_get_error(mSsl, ret); - } - - if (err == SSL_ERROR_ZERO_RETURN) { - PLOG_DEBUG << "TLS connection cleanly closed"; - break; - } - - if (openssl::check_error(err)) - recv(make_message(buffer, buffer + ret)); - } - } - - std::lock_guard lock(mSslMutex); - SSL_shutdown(mSsl); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << "DTLS recv: " << e.RTC_WHAT(); - } - - if (state() == State::Connected) { - PLOG_INFO << "DTLS closed"; - changeState(State::Disconnected); - recv(nullptr); - } else { - PLOG_ERROR << "DTLS handshake failed"; - changeState(State::Failed); - } -} - -RTC_WRAPPED(void) DtlsTransport::handleTimeout() { - std::lock_guard lock(mSslMutex); - - // Warning: This function breaks the usual return value convention - int ret = DTLSv1_handle_timeout(mSsl); - if (ret < 0) { - RTC_THROW RTC_RUNTIME_ERROR("Handshake timeout"); // write BIO can't fail - } else if (ret > 0) { - LOG_VERBOSE << "DTLS retransmit done"; - } - - struct timeval tv = {}; - if (DTLSv1_get_timeout(mSsl, &tv)) { - auto timeout = milliseconds(tv.tv_sec * 1000 + tv.tv_usec / 1000); - // Also handle handshake timeout manually because OpenSSL actually - // doesn't... OpenSSL backs off exponentially in base 2 starting from the - // recommended 1s so this allows for 5 retransmissions and fails after - // roughly 30s. - if (timeout > 30s) - RTC_THROW RTC_RUNTIME_ERROR("Handshake timeout"); - - LOG_VERBOSE << "DTLS retransmit timeout is " << timeout.count() << "ms"; - ThreadPool::Instance().schedule(timeout, [weak_this = weak_from_this()]() { - if (auto locked = weak_this.lock()) - locked->doRecv(); - }); - } -} - -int DtlsTransport::CertificateCallback(int /*preverify_ok*/, X509_STORE_CTX *ctx) { - SSL *ssl = - static_cast(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); - DtlsTransport *t = - static_cast(SSL_get_ex_data(ssl, DtlsTransport::TransportExIndex)); - - X509 *crt = X509_STORE_CTX_get_current_cert(ctx); - string fingerprint = make_fingerprint(crt); - - return t->mVerifierCallback(fingerprint) ? 1 : 0; -} - -void DtlsTransport::InfoCallback(const SSL *ssl, int where, int ret) { - DtlsTransport *t = - static_cast(SSL_get_ex_data(ssl, DtlsTransport::TransportExIndex)); - - if (where & SSL_CB_ALERT) { - if (ret != 256) { // Close Notify - PLOG_ERROR << "DTLS alert: " << SSL_alert_desc_string_long(ret); - } - t->mIncomingQueue.stop(); // Close the connection - } -} - -int DtlsTransport::BioMethodNew(BIO *bio) { - BIO_set_init(bio, 1); - BIO_set_data(bio, NULL); - BIO_set_shutdown(bio, 0); - return 1; -} - -int DtlsTransport::BioMethodFree(BIO *bio) { - if (!bio) - return 0; - BIO_set_data(bio, NULL); - return 1; -} - -int DtlsTransport::BioMethodWrite(BIO *bio, const char *in, int inl) { - if (inl <= 0) - return inl; - auto transport = reinterpret_cast(BIO_get_data(bio)); - if (!transport) - return -1; - auto b = reinterpret_cast(in); - transport->outgoing(make_message(b, b + inl)); - return inl; // can't fail -} - -long DtlsTransport::BioMethodCtrl(BIO * /*bio*/, int cmd, long /*num*/, void * /*ptr*/) { - switch (cmd) { - case BIO_CTRL_FLUSH: - return 1; - case BIO_CTRL_DGRAM_QUERY_MTU: - return 0; // SSL_OP_NO_QUERY_MTU must be set - case BIO_CTRL_WPENDING: - case BIO_CTRL_PENDING: - return 0; - default: - break; - } - return 0; -} - -#endif - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/dtlstransport.hpp b/godot/thirdparty/libdatachannel/src/impl/dtlstransport.hpp deleted file mode 100644 index 3e70de01..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/dtlstransport.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_DTLS_TRANSPORT_H -#define RTC_IMPL_DTLS_TRANSPORT_H - -#include "certificate.hpp" -#include "common.hpp" -#include "queue.hpp" -#include "tls.hpp" -#include "transport.hpp" - -#include -#include -#include -#include - -namespace rtc::impl { - -class IceTransport; - -class DtlsTransport : public Transport, public std::enable_shared_from_this { -public: - static void Init(); - static void Cleanup(); - - using verifier_callback = std::function; - - DtlsTransport(shared_ptr lower, certificate_ptr certificate, optional mtu, - verifier_callback verifierCallback, state_callback stateChangeCallback); - ~DtlsTransport(); - - RTC_WRAPPED(void) construct(); - virtual RTC_WRAPPED(void) start() override; - virtual void stop() override; - virtual RTC_WRAPPED(bool) send(message_ptr message) override; // false if dropped - - bool isClient() const { return mIsClient; } - -protected: - virtual void incoming(message_ptr message) override; - virtual RTC_WRAPPED(bool) outgoing(message_ptr message) override; - virtual bool demuxMessage(message_ptr message); - virtual void postHandshake(); - - void enqueueRecv(); - void doRecv(); - - const optional mMtu; - const certificate_ptr mCertificate; - const verifier_callback mVerifierCallback; - const bool mIsClient; - - Queue mIncomingQueue; - std::atomic mPendingRecvCount = 0; - std::mutex mRecvMutex; - std::atomic mCurrentDscp = 0; - std::atomic mOutgoingResult = true; - -#if USE_GNUTLS - gnutls_session_t mSession; - std::mutex mSendMutex; - - static int CertificateCallback(gnutls_session_t session); - static ssize_t WriteCallback(gnutls_transport_ptr_t ptr, const void *data, size_t len); - static ssize_t ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_t maxlen); - static int TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int ms); - -#elif USE_MBEDTLS - mbedtls_entropy_context mEntropy; - mbedtls_ctr_drbg_context mDrbg; - mbedtls_ssl_config mConf; - mbedtls_ssl_context mSsl; - - std::mutex mSslMutex; - - uint32_t mFinMs = 0, mIntMs = 0; - std::chrono::time_point mTimerSetAt; - - char mMasterSecret[48]; - char mRandBytes[64]; - mbedtls_tls_prf_types mTlsProfile = MBEDTLS_SSL_TLS_PRF_NONE; - - static int CertificateCallback(void *ctx, mbedtls_x509_crt *crt, int depth, uint32_t *flags); - static int WriteCallback(void *ctx, const unsigned char *buf, size_t len); - static int ReadCallback(void *ctx, unsigned char *buf, size_t len); - static void ExportKeysCallback(void *ctx, mbedtls_ssl_key_export_type type, - const unsigned char *secret, size_t secret_len, - const unsigned char client_random[32], - const unsigned char server_random[32], - mbedtls_tls_prf_types tls_prf_type); - static void SetTimerCallback(void *ctx, uint32_t int_ms, uint32_t fin_ms); - static int GetTimerCallback(void *ctx); - -#else // OPENSSL - SSL_CTX *mCtx = NULL; - SSL *mSsl = NULL; - BIO *mInBio, *mOutBio; - std::mutex mSslMutex; - - void handleTimeout(); - - static BIO_METHOD *BioMethods; - static int TransportExIndex; - static std::mutex GlobalMutex; - - static int CertificateCallback(int preverify_ok, X509_STORE_CTX *ctx); - static void InfoCallback(const SSL *ssl, int where, int ret); - - static int BioMethodNew(BIO *bio); - static int BioMethodFree(BIO *bio); - static int BioMethodWrite(BIO *bio, const char *in, int inl); - static long BioMethodCtrl(BIO *bio, int cmd, long num, void *ptr); -#endif -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/http.hpp b/godot/thirdparty/libdatachannel/src/impl/http.hpp deleted file mode 100644 index c78869f7..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/http.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2020-2023 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_HTTP_H -#define RTC_IMPL_HTTP_H - -#include "common.hpp" - -#include -#include - -namespace rtc::impl { - -// Check the buffer contains the beginning of an HTTP request -bool isHttpRequest(const byte *buffer, size_t size); - -// Parse an http message into lines -size_t parseHttpLines(const byte *buffer, size_t size, std::list &lines); - -// Parse headers of a http message -std::multimap parseHttpHeaders(const std::list &lines); - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/httpproxytransport.hpp b/godot/thirdparty/libdatachannel/src/impl/httpproxytransport.hpp deleted file mode 100644 index d99cf7c2..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/httpproxytransport.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * Copyright (c) 2023 Eric Gressman - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_TCP_PROXY_TRANSPORT_H -#define RTC_IMPL_TCP_PROXY_TRANSPORT_H - -#include "common.hpp" -#include "transport.hpp" - -#if RTC_ENABLE_WEBSOCKET - -namespace rtc::impl { - -class TcpTransport; - -class HttpProxyTransport final : public Transport, - public std::enable_shared_from_this { -public: - HttpProxyTransport(shared_ptr lower, std::string hostname, std::string service, - state_callback stateCallback); - ~HttpProxyTransport(); - - void start() override; - void stop() override; - bool send(message_ptr message) override; - - bool isActive() const; - -private: - void incoming(message_ptr message) override; - bool sendHttpRequest(); - string generateHttpRequest(); - size_t parseHttpResponse(std::byte *buffer, size_t size); - - string mHostname; - string mService; - binary mBuffer; -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/icetransport.cpp b/godot/thirdparty/libdatachannel/src/impl/icetransport.cpp deleted file mode 100644 index f023a4cc..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/icetransport.cpp +++ /dev/null @@ -1,909 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "icetransport.hpp" -#include "configuration.hpp" -#include "internals.hpp" -#include "transport.hpp" -#include "utils.hpp" - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#endif - -#include - -using namespace std::chrono_literals; -using std::chrono::system_clock; - -namespace rtc::impl { - -#if !USE_NICE // libjuice - -const int MAX_TURN_SERVERS_COUNT = 2; - -void IceTransport::Init() { - // Dummy -} - -void IceTransport::Cleanup() { - // Dummy -} - -IceTransport::IceTransport(candidate_callback candidateCallback, - state_callback stateChangeCallback, - gathering_state_callback gatheringStateChangeCallback) - : Transport(nullptr, std::move(stateChangeCallback)), mRole(Description::Role::ActPass), - mMid("0"), mGatheringState(GatheringState::New), - mCandidateCallback(std::move(candidateCallback)), - mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)), - mAgent(nullptr, nullptr) { -} - -RTC_WRAPPED(void) IceTransport::construct(const Configuration &config) { - PLOG_DEBUG << "Initializing ICE transport (libjuice)"; - - juice_log_level_t level; - auto logger = plog::get(); - switch (logger ? logger->getMaxSeverity() : plog::none) { - case plog::none: - level = JUICE_LOG_LEVEL_NONE; - break; - case plog::fatal: - level = JUICE_LOG_LEVEL_FATAL; - break; - case plog::error: - level = JUICE_LOG_LEVEL_ERROR; - break; - case plog::warning: - level = JUICE_LOG_LEVEL_WARN; - break; - case plog::info: - case plog::debug: // juice debug is output as verbose - level = JUICE_LOG_LEVEL_INFO; - break; - default: - level = JUICE_LOG_LEVEL_VERBOSE; - break; - } - juice_set_log_handler(IceTransport::LogCallback); - juice_set_log_level(level); - - juice_config_t jconfig = {}; - jconfig.cb_state_changed = IceTransport::StateChangeCallback; - jconfig.cb_candidate = IceTransport::CandidateCallback; - jconfig.cb_gathering_done = IceTransport::GatheringDoneCallback; - jconfig.cb_recv = IceTransport::RecvCallback; - jconfig.user_ptr = this; - - if (config.enableIceTcp) { - PLOG_WARNING << "ICE-TCP is not supported with libjuice"; - } - - if (config.enableIceUdpMux) { - PLOG_DEBUG << "Enabling ICE UDP mux"; - jconfig.concurrency_mode = JUICE_CONCURRENCY_MODE_MUX; - } else { - jconfig.concurrency_mode = JUICE_CONCURRENCY_MODE_POLL; - } - - // Randomize servers order - std::vector servers = config.iceServers; - std::shuffle(servers.begin(), servers.end(), utils::random_engine()); - - // Pick a STUN server - for (auto &server : servers) { - if (!server.hostname.empty() && server.type == IceServer::Type::Stun) { - if (server.port == 0) - server.port = 3478; // STUN UDP port - PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port << "\""; - jconfig.stun_server_host = server.hostname.c_str(); - jconfig.stun_server_port = server.port; - break; - } - } - - juice_turn_server_t turn_servers[MAX_TURN_SERVERS_COUNT]; - std::memset(turn_servers, 0, sizeof(turn_servers)); - - // Add TURN servers - int k = 0; - for (auto &server : servers) { - if (!server.hostname.empty() && server.type == IceServer::Type::Turn) { - if (server.port == 0) - server.port = 3478; // TURN UDP port - PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\""; - turn_servers[k].host = server.hostname.c_str(); - turn_servers[k].username = server.username.c_str(); - turn_servers[k].password = server.password.c_str(); - turn_servers[k].port = server.port; - if (++k >= MAX_TURN_SERVERS_COUNT) - break; - } - } - jconfig.turn_servers = k > 0 ? turn_servers : nullptr; - jconfig.turn_servers_count = k; - - // Bind address - if (config.bindAddress) { - jconfig.bind_address = config.bindAddress->c_str(); - } - - // Port range - if (config.portRangeBegin > 1024 || - (config.portRangeEnd != 0 && config.portRangeEnd != 65535)) { - jconfig.local_port_range_begin = config.portRangeBegin; - jconfig.local_port_range_end = config.portRangeEnd; - } - - // Create agent - mAgent = decltype(mAgent)(juice_create(&jconfig), juice_destroy); - if (!mAgent) - RTC_THROW RTC_RUNTIME_ERROR("Failed to create the ICE agent"); - RTC_RET; -} - -IceTransport::~IceTransport() { - PLOG_DEBUG << "Destroying ICE transport"; - mAgent.reset(); -} - -Description::Role IceTransport::role() const { return mRole; } - -RTC_WRAPPED(Description) IceTransport::getLocalDescription(Description::Type type) const { - RTC_BEGIN; - char sdp[JUICE_MAX_SDP_STRING_LEN]; - if (juice_get_local_description(mAgent.get(), sdp, JUICE_MAX_SDP_STRING_LEN) < 0) - RTC_THROW RTC_RUNTIME_ERROR("Failed to generate local SDP"); - - // RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of - // setup:actpass. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 - RTC_UNWRAP_RETHROW_DECL(Description, desc, Description::create(string(sdp), type, - type == Description::Type::Offer ? Description::Role::ActPass : mRole)); - desc.addIceOption("trickle"); - return desc; -} - -RTC_WRAPPED(void) IceTransport::setRemoteDescription(const Description &description) { - // RFC 5763: The answerer MUST use either a setup attribute value of setup:active or - // setup:passive. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 - if (description.type() == Description::Type::Answer && - description.role() == Description::Role::ActPass) - RTC_THROW RTC_INVALID_ARGUMENT("Illegal role actpass in remote answer description"); - - // RFC 5763: Note that if the answerer uses setup:passive, then the DTLS handshake - // will not begin until the answerer is received, which adds additional latency. - // setup:active allows the answer and the DTLS handshake to occur in parallel. Thus, - // setup:active is RECOMMENDED. - if (mRole == Description::Role::ActPass) - mRole = description.role() == Description::Role::Active ? Description::Role::Passive - : Description::Role::Active; - - if (mRole == description.role()) - RTC_THROW RTC_INVALID_ARGUMENT("Incompatible roles with remote description"); - - mMid = description.bundleMid(); - if (juice_set_remote_description(mAgent.get(), - description.generateApplicationSdp("\r\n").c_str()) < 0) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid ICE settings from remote SDP"); - RTC_RET; -} - -bool IceTransport::addRemoteCandidate(const Candidate &candidate) { - // Don't RTC_TRY to pass unresolved candidates for more safety - if (!candidate.isResolved()) - return false; - - return juice_add_remote_candidate(mAgent.get(), string(candidate).c_str()) >= 0; -} - -RTC_WRAPPED(void) IceTransport::gatherLocalCandidates(string mid) { - mMid = std::move(mid); - - // Change state now as candidates calls can be synchronous - changeGatheringState(GatheringState::InProgress); - - if (juice_gather_candidates(mAgent.get()) < 0) { - RTC_THROW RTC_RUNTIME_ERROR("Failed to gather local ICE candidates"); - } - RTC_RET; -} - -optional IceTransport::getLocalAddress() const { - char str[JUICE_MAX_ADDRESS_STRING_LEN]; - if (juice_get_selected_addresses(mAgent.get(), str, JUICE_MAX_ADDRESS_STRING_LEN, NULL, 0) == - 0) { - return std::make_optional(string(str)); - } - return nullopt; -} -optional IceTransport::getRemoteAddress() const { - char str[JUICE_MAX_ADDRESS_STRING_LEN]; - if (juice_get_selected_addresses(mAgent.get(), NULL, 0, str, JUICE_MAX_ADDRESS_STRING_LEN) == - 0) { - return std::make_optional(string(str)); - } - return nullopt; -} - -RTC_WRAPPED(bool) IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) { - RTC_BEGIN; - char sdpLocal[JUICE_MAX_CANDIDATE_SDP_STRING_LEN]; - char sdpRemote[JUICE_MAX_CANDIDATE_SDP_STRING_LEN]; - if (juice_get_selected_candidates(mAgent.get(), sdpLocal, JUICE_MAX_CANDIDATE_SDP_STRING_LEN, - sdpRemote, JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0) { - if (local) { - RTC_UNWRAP_RETHROW_VAR(*local, Candidate::create(sdpLocal, mMid)); - local->resolve(Candidate::ResolveMode::Simple); - } - if (remote) { - RTC_UNWRAP_RETHROW_VAR(*remote, Candidate::create(sdpRemote, mMid)); - remote->resolve(Candidate::ResolveMode::Simple); - } - return true; - } - return false; -} - -RTC_WRAPPED(bool) IceTransport::send(message_ptr message) { - auto s = state(); - if (!message || (s != State::Connected && s != State::Completed)) - return false; - - PLOG_VERBOSE << "Send size=" << message->size(); - return outgoing(message); -} - -RTC_WRAPPED(bool) IceTransport::outgoing(message_ptr message) { - // Explicit Congestion Notification takes the least-significant 2 bits of the DS field - int ds = int(message->dscp << 2); - return juice_send_diffserv(mAgent.get(), reinterpret_cast(message->data()), - message->size(), ds) >= 0; -} - -void IceTransport::changeGatheringState(GatheringState state) { - if (mGatheringState.exchange(state) != state) - mGatheringStateChangeCallback(mGatheringState); -} - -void IceTransport::processStateChange(unsigned int state) { - switch (state) { - case JUICE_STATE_DISCONNECTED: - changeState(State::Disconnected); - break; - case JUICE_STATE_CONNECTING: - changeState(State::Connecting); - break; - case JUICE_STATE_CONNECTED: - changeState(State::Connected); - break; - case JUICE_STATE_COMPLETED: - changeState(State::Completed); - break; - case JUICE_STATE_FAILED: - changeState(State::Failed); - break; - }; -} - -RTC_WRAPPED(void) IceTransport::processCandidate(const string &candidate) { - RTC_BEGIN; - RTC_UNWRAP_RETHROW_DECL(Candidate, tmp, Candidate::create(candidate, mMid)); - RTC_UNWRAP_RETHROW(mCandidateCallback(tmp)); - RTC_RET; -} - -void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); } - -void IceTransport::StateChangeCallback(juice_agent_t *, juice_state_t state, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); - RTC_TRY { - iceTransport->processStateChange(static_cast(state)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void IceTransport::CandidateCallback(juice_agent_t *, const char *sdp, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); - RTC_TRY { - RTC_UNWRAP_CATCH(iceTransport->processCandidate(sdp)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void IceTransport::GatheringDoneCallback(juice_agent_t *, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); - RTC_TRY { - iceTransport->processGatheringDone(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void IceTransport::RecvCallback(juice_agent_t *, const char *data, size_t size, void *user_ptr) { - auto iceTransport = static_cast(user_ptr); - RTC_TRY { - PLOG_VERBOSE << "Incoming size=" << size; - auto b = reinterpret_cast(data); - iceTransport->incoming(make_message(b, b + size)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void IceTransport::LogCallback(juice_log_level_t level, const char *message) { - plog::Severity severity; - switch (level) { - case JUICE_LOG_LEVEL_FATAL: - severity = plog::fatal; - break; - case JUICE_LOG_LEVEL_ERROR: - severity = plog::error; - break; - case JUICE_LOG_LEVEL_WARN: - severity = plog::warning; - break; - case JUICE_LOG_LEVEL_INFO: - severity = plog::info; - break; - default: - severity = plog::verbose; // libjuice debug as verbose - break; - } - PLOG(severity) << "juice: " << message; -} - -#else // USE_NICE == 1 - -unique_ptr IceTransport::MainLoop(nullptr, nullptr); -std::thread IceTransport::MainLoopThread; - -void IceTransport::Init() { - g_log_set_handler("libnice", G_LOG_LEVEL_MASK, LogCallback, nullptr); - - IF_PLOG(plog::verbose) { - nice_debug_enable(false); // do not output STUN debug messages - } - - MainLoop = decltype(MainLoop)(g_main_loop_new(nullptr, FALSE), g_main_loop_unref); - if (!MainLoop) - PLOG_ERROR << "Failed to create the main loop"; - - MainLoopThread = std::thread(g_main_loop_run, MainLoop.get()); -} - -void IceTransport::Cleanup() { - g_main_loop_quit(MainLoop.get()); - MainLoopThread.join(); - MainLoop.reset(); -} - -static void closeNiceAgentCallback(GObject *niceAgent, GAsyncResult *, gpointer) { - g_object_unref(niceAgent); -} - -static void closeNiceAgent(NiceAgent *niceAgent) { - // close the agent to prune alive TURN refreshes, before releasing it - nice_agent_close_async(niceAgent, closeNiceAgentCallback, nullptr); -} - -IceTransport::IceTransport(candidate_callback candidateCallback, - state_callback stateChangeCallback, - gathering_state_callback gatheringStateChangeCallback) - : Transport(nullptr, std::move(stateChangeCallback)), mRole(Description::Role::ActPass), - mMid("0"), mGatheringState(GatheringState::New), - mCandidateCallback(std::move(candidateCallback)), - mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)), - mNiceAgent(nullptr, nullptr), mOutgoingDscp(0) { -} - -RTC_WRAPPED(void) IceTransport::construct(const Configuration &config) { - PLOG_DEBUG << "Initializing ICE transport (libnice)"; - - if (!MainLoop) - RTC_THROW RTC_LOGIC_ERROR("Main loop for nice agent is not created"); - - // RFC 8445: The nomination process that was referred to as "aggressive nomination" in RFC 5245 - // has been deprecated in this specification. - // libnice defaults to aggressive nomation therefore we change to regular nomination. - // See https://gitlab.freedesktop.org/libnice/libnice/-/merge_requests/125 - NiceAgentOption flags = NICE_AGENT_OPTION_REGULAR_NOMINATION; - - // Create agent - mNiceAgent = decltype(mNiceAgent)( - nice_agent_new_full( - g_main_loop_get_context(MainLoop.get()), - NICE_COMPATIBILITY_RFC5245, // RFC 5245 was obsoleted by RFC 8445 but this should be OK - flags), - closeNiceAgent); - - if (!mNiceAgent) - RTC_THROW RTC_RUNTIME_ERROR("Failed to create the nice agent"); - - mStreamId = nice_agent_add_stream(mNiceAgent.get(), 1); - if (!mStreamId) - RTC_THROW RTC_RUNTIME_ERROR("Failed to add a stream"); - - g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", TRUE, nullptr); // decided later - g_object_set(G_OBJECT(mNiceAgent.get()), "ice-udp", TRUE, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "ice-tcp", config.enableIceTcp ? TRUE : FALSE, - nullptr); - - // RFC 8445: Agents MUST NOT use an RTO value smaller than 500 ms. - g_object_set(G_OBJECT(mNiceAgent.get()), "stun-initial-timeout", 500, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "stun-max-retransmissions", 3, nullptr); - - // RFC 8445: ICE agents SHOULD use a default Ta value, 50 ms, but MAY use another value based on - // the characteristics of the associated data. - g_object_set(G_OBJECT(mNiceAgent.get()), "stun-pacing-timer", 25, nullptr); - - g_object_set(G_OBJECT(mNiceAgent.get()), "upnp", FALSE, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "upnp-timeout", 200, nullptr); - - // Proxy - if (config.proxyServer) { - const auto &proxyServer = *config.proxyServer; - - NiceProxyType type; - switch (proxyServer.type) { - case ProxyServer::Type::Http: - type = NICE_PROXY_TYPE_HTTP; - break; - case ProxyServer::Type::Socks5: - type = NICE_PROXY_TYPE_SOCKS5; - break; - default: - PLOG_WARNING << "Proxy server type is not supported"; - type = NICE_PROXY_TYPE_NONE; - break; - } - - g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-type", type, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.hostname.c_str(), nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-port", guint(proxyServer.port), nullptr); - - if (proxyServer.username) - g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-username", - proxyServer.username->c_str(), nullptr); - - if (proxyServer.password) - g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-password", - proxyServer.password->c_str(), nullptr); - } - - if (config.enableIceUdpMux) { - PLOG_WARNING << "ICE UDP mux is not available with libnice"; - } - - // Randomize order - std::vector servers = config.iceServers; - std::shuffle(servers.begin(), servers.end(), utils::random_engine()); - - // Add one STUN server - bool success = false; - for (auto &server : servers) { - if (server.hostname.empty()) - continue; - if (server.type != IceServer::Type::Stun) - continue; - if (server.port == 0) - server.port = 3478; // STUN UDP port - - struct addrinfo hints = {}; - hints.ai_family = AF_INET; // IPv4 - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_ADDRCONFIG; - struct addrinfo *result = nullptr; - if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints, - &result) != 0) { - PLOG_WARNING << "Unable to resolve STUN server address: " << server.hostname << ':' - << server.port; - continue; - } - - for (auto p = result; p; p = p->ai_next) { - if (p->ai_family == AF_INET) { - char nodebuffer[MAX_NUMERICNODE_LEN]; - char servbuffer[MAX_NUMERICSERV_LEN]; - if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, - servbuffer, MAX_NUMERICSERV_LEN, - NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port - << "\""; - g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port", - std::stoul(servbuffer), nullptr); - success = true; - break; - } - } - } - - freeaddrinfo(result); - if (success) - break; - } - - // Add TURN servers - for (auto &server : servers) { - if (server.hostname.empty()) - continue; - if (server.type != IceServer::Type::Turn) - continue; - if (server.port == 0) - server.port = server.relayType == IceServer::RelayType::TurnTls ? 5349 : 3478; - - struct addrinfo hints = {}; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = - server.relayType == IceServer::RelayType::TurnUdp ? SOCK_DGRAM : SOCK_STREAM; - hints.ai_protocol = - server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP; - hints.ai_flags = AI_ADDRCONFIG; - struct addrinfo *result = nullptr; - if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints, - &result) != 0) { - PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':' - << server.port; - continue; - } - - for (auto p = result; p; p = p->ai_next) { - if (p->ai_family == AF_INET || p->ai_family == AF_INET6) { - char nodebuffer[MAX_NUMERICNODE_LEN]; - char servbuffer[MAX_NUMERICSERV_LEN]; - if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, - servbuffer, MAX_NUMERICSERV_LEN, - NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port - << "\""; - NiceRelayType niceRelayType; - switch (server.relayType) { - case IceServer::RelayType::TurnTcp: - niceRelayType = NICE_RELAY_TYPE_TURN_TCP; - break; - case IceServer::RelayType::TurnTls: - niceRelayType = NICE_RELAY_TYPE_TURN_TLS; - break; - default: - niceRelayType = NICE_RELAY_TYPE_TURN_UDP; - break; - } - nice_agent_set_relay_info(mNiceAgent.get(), mStreamId, 1, nodebuffer, - std::stoul(servbuffer), server.username.c_str(), - server.password.c_str(), niceRelayType); - } - } - } - - freeaddrinfo(result); - } - - g_signal_connect(G_OBJECT(mNiceAgent.get()), "component-state-changed", - G_CALLBACK(StateChangeCallback), this); - g_signal_connect(G_OBJECT(mNiceAgent.get()), "new-candidate-full", - G_CALLBACK(CandidateCallback), this); - g_signal_connect(G_OBJECT(mNiceAgent.get()), "candidate-gathering-done", - G_CALLBACK(GatheringDoneCallback), this); - - nice_agent_set_stream_name(mNiceAgent.get(), mStreamId, "application"); - nice_agent_set_port_range(mNiceAgent.get(), mStreamId, 1, config.portRangeBegin, - config.portRangeEnd); - - nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(MainLoop.get()), - RecvCallback, this); -} - -IceTransport::~IceTransport() { - if (mTimeoutId) { - g_source_remove(mTimeoutId); - mTimeoutId = 0; - } - - PLOG_DEBUG << "Destroying ICE transport"; - nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(MainLoop.get()), - NULL, NULL); - nice_agent_remove_stream(mNiceAgent.get(), mStreamId); - mNiceAgent.reset(); -} - -Description::Role IceTransport::role() const { return mRole; } - -RTC_WRAPPED(Description) IceTransport::getLocalDescription(Description::Type type) const { - // RFC 8445: The initiating agent that started the ICE processing MUST take the controlling - // role, and the other MUST take the controlled role. - g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", - type == Description::Type::Offer ? TRUE : FALSE, nullptr); - - unique_ptr sdp(nice_agent_generate_local_sdp(mNiceAgent.get()), - g_free); - - // RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of - // setup:actpass. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 - Description desc(string(sdp.get()), type, - type == Description::Type::Offer ? Description::Role::ActPass : mRole); - desc.addIceOption("trickle"); - return desc; -} - -RTC_WRAPPED(void) IceTransport::setRemoteDescription(const Description &description) { - // RFC 5763: The answerer MUST use either a setup attribute value of setup:active or - // setup:passive. - // See https://www.rfc-editor.org/rfc/rfc5763.html#section-5 - if (description.type() == Description::Type::Answer && - description.role() == Description::Role::ActPass) - RTC_THROW RTC_INVALID_ARGUMENT("Illegal role actpass in remote answer description"); - - // RFC 5763: Note that if the answerer uses setup:passive, then the DTLS handshake - // will not begin until the answerer is received, which adds additional latency. - // setup:active allows the answer and the DTLS handshake to occur in parallel. Thus, - // setup:active is RECOMMENDED. - if (mRole == Description::Role::ActPass) - mRole = description.role() == Description::Role::Active ? Description::Role::Passive - : Description::Role::Active; - - if (mRole == description.role()) - RTC_THROW RTC_INVALID_ARGUMENT("Incompatible roles with remote description"); - RTC_THROW RTC_INVALID_ARGUMENT("Incompatible roles with remote description"); - - mMid = description.bundleMid(); - mTrickleTimeout = !description.ended() ? 30s : 0s; - - // Warning: libnice expects "\n" as end of line - if (nice_agent_parse_remote_sdp(mNiceAgent.get(), - description.generateApplicationSdp("\n").c_str()) < 0) - RTC_THROW RTC_INVALID_ARGUMENT("Invalid ICE settings from remote SDP"); -} - -bool IceTransport::addRemoteCandidate(const Candidate &candidate) { - // Don't RTC_TRY to pass unresolved candidates to libnice for more safety - if (!candidate.isResolved()) - return false; - - // Warning: the candidate string must start with "a=candidate:" and it must not end with a - // newline or whitespace, else libnice will reject it. - string sdp(candidate); - NiceCandidate *cand = - nice_agent_parse_remote_candidate_sdp(mNiceAgent.get(), mStreamId, sdp.c_str()); - if (!cand) { - PLOG_WARNING << "Rejected ICE candidate: " << sdp; - return false; - } - - GSList *list = g_slist_append(nullptr, cand); - int ret = nice_agent_set_remote_candidates(mNiceAgent.get(), mStreamId, 1, list); - - g_slist_free_full(list, reinterpret_cast(nice_candidate_free)); - return ret > 0; -} - -RTC_WRAPPED(void) IceTransport::gatherLocalCandidates(string mid) { - mMid = std::move(mid); - - // Change state now as candidates calls can be synchronous - changeGatheringState(GatheringState::InProgress); - - if (!nice_agent_gather_candidates(mNiceAgent.get(), mStreamId)) { - RTC_THROW RTC_RUNTIME_ERROR("Failed to gather local ICE candidates"); - } -} - -optional IceTransport::getLocalAddress() const { - NiceCandidate *local = nullptr; - NiceCandidate *remote = nullptr; - if (nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote)) { - return std::make_optional(AddressToString(local->addr)); - } - return nullopt; -} - -optional IceTransport::getRemoteAddress() const { - NiceCandidate *local = nullptr; - NiceCandidate *remote = nullptr; - if (nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote)) { - return std::make_optional(AddressToString(remote->addr)); - } - return nullopt; -} - -bool IceTransport::send(message_ptr message) { - auto s = state(); - if (!message || (s != State::Connected && s != State::Completed)) - return false; - - PLOG_VERBOSE << "Send size=" << message->size(); - return outgoing(message); -} - -bool IceTransport::outgoing(message_ptr message) { - std::lock_guard lock(mOutgoingMutex); - if (mOutgoingDscp != message->dscp) { - mOutgoingDscp = message->dscp; - // Explicit Congestion Notification takes the least-significant 2 bits of the DS field - int ds = int(message->dscp << 2); - nice_agent_set_stream_tos(mNiceAgent.get(), mStreamId, ds); // ToS is the legacy name for DS - } - return nice_agent_send(mNiceAgent.get(), mStreamId, 1, message->size(), - reinterpret_cast(message->data())) >= 0; -} - -void IceTransport::changeGatheringState(GatheringState state) { - if (mGatheringState.exchange(state) != state) - mGatheringStateChangeCallback(mGatheringState); -} - -void IceTransport::processTimeout() { - PLOG_WARNING << "ICE timeout"; - mTimeoutId = 0; - changeState(State::Failed); -} - -void IceTransport::processCandidate(const string &candidate) { - mCandidateCallback(Candidate(candidate, mMid)); -} - -void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); } - -void IceTransport::processStateChange(unsigned int state) { - if (state == NICE_COMPONENT_STATE_FAILED && mTrickleTimeout.count() > 0) { - if (mTimeoutId) - g_source_remove(mTimeoutId); - mTimeoutId = g_timeout_add(mTrickleTimeout.count() /* ms */, TimeoutCallback, this); - return; - } - - if (state == NICE_COMPONENT_STATE_CONNECTED && mTimeoutId) { - g_source_remove(mTimeoutId); - mTimeoutId = 0; - } - - switch (state) { - case NICE_COMPONENT_STATE_DISCONNECTED: - changeState(State::Disconnected); - break; - case NICE_COMPONENT_STATE_CONNECTING: - changeState(State::Connecting); - break; - case NICE_COMPONENT_STATE_CONNECTED: - changeState(State::Connected); - break; - case NICE_COMPONENT_STATE_READY: - changeState(State::Completed); - break; - case NICE_COMPONENT_STATE_FAILED: - changeState(State::Failed); - break; - }; -} - -string IceTransport::AddressToString(const NiceAddress &addr) { - char buffer[NICE_ADDRESS_STRING_LEN]; - nice_address_to_string(&addr, buffer); - unsigned int port = nice_address_get_port(&addr); - std::ostringstream ss; - ss << buffer << ":" << port; - return ss.str(); -} - -void IceTransport::CandidateCallback(NiceAgent *agent, NiceCandidate *candidate, - gpointer userData) { - auto iceTransport = static_cast(userData); - gchar *cand = nice_agent_generate_local_candidate_sdp(agent, candidate); - RTC_TRY { - iceTransport->processCandidate(cand); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } - g_free(cand); -} - -void IceTransport::GatheringDoneCallback(NiceAgent * /*agent*/, guint /*streamId*/, - gpointer userData) { - auto iceTransport = static_cast(userData); - RTC_TRY { - iceTransport->processGatheringDone(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void IceTransport::StateChangeCallback(NiceAgent * /*agent*/, guint /*streamId*/, - guint /*componentId*/, guint state, gpointer userData) { - auto iceTransport = static_cast(userData); - RTC_TRY { - iceTransport->processStateChange(state); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void IceTransport::RecvCallback(NiceAgent * /*agent*/, guint /*streamId*/, guint /*componentId*/, - guint len, gchar *buf, gpointer userData) { - auto iceTransport = static_cast(userData); - RTC_TRY { - PLOG_VERBOSE << "Incoming size=" << len; - auto b = reinterpret_cast(buf); - iceTransport->incoming(make_message(b, b + len)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -gboolean IceTransport::TimeoutCallback(gpointer userData) { - auto iceTransport = static_cast(userData); - RTC_TRY { - iceTransport->processTimeout(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } - return FALSE; -} - -void IceTransport::LogCallback(const gchar * /*logDomain*/, GLogLevelFlags logLevel, - const gchar *message, gpointer /*userData*/) { - plog::Severity severity; - unsigned int flags = logLevel & G_LOG_LEVEL_MASK; - if (flags & G_LOG_LEVEL_ERROR) - severity = plog::fatal; - else if (flags & G_LOG_LEVEL_CRITICAL) - severity = plog::error; - else if (flags & G_LOG_LEVEL_WARNING) - severity = plog::warning; - else if (flags & G_LOG_LEVEL_MESSAGE) - severity = plog::info; - else if (flags & G_LOG_LEVEL_INFO) - severity = plog::info; - else - severity = plog::verbose; // libnice debug as verbose - - PLOG(severity) << "nice: " << message; -} - -bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) { - NiceCandidate *niceLocal, *niceRemote; - if (!nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &niceLocal, &niceRemote)) - return false; - - gchar *sdpLocal = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceLocal); - if (local) - *local = Candidate(sdpLocal, mMid); - g_free(sdpLocal); - - gchar *sdpRemote = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceRemote); - if (remote) - *remote = Candidate(sdpRemote, mMid); - g_free(sdpRemote); - - if (local) - local->resolve(Candidate::ResolveMode::Simple); - if (remote) - remote->resolve(Candidate::ResolveMode::Simple); - return true; -} - -#endif - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/icetransport.hpp b/godot/thirdparty/libdatachannel/src/impl/icetransport.hpp deleted file mode 100644 index 8f590cc4..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/icetransport.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_ICE_TRANSPORT_H -#define RTC_IMPL_ICE_TRANSPORT_H - -#include "candidate.hpp" -#include "common.hpp" -#include "configuration.hpp" -#include "description.hpp" -#include "global.hpp" -#include "peerconnection.hpp" -#include "transport.hpp" - -#if !USE_NICE -#include -#else -#include -#endif - -#include -#include -#include -#include - -namespace rtc::impl { - -class IceTransport : public Transport { -public: - static void Init(); - static void Cleanup(); - - enum class GatheringState { New = 0, InProgress = 1, Complete = 2 }; - - using candidate_callback = std::function; - using gathering_state_callback = std::function; - - IceTransport(candidate_callback candidateCallback, - state_callback stateChangeCallback, - gathering_state_callback gatheringStateChangeCallback); - ~IceTransport(); - - RTC_WRAPPED(void) construct(const Configuration &config); - Description::Role role() const; - GatheringState gatheringState() const; - RTC_WRAPPED(Description) getLocalDescription(Description::Type type) const; - RTC_WRAPPED(void) setRemoteDescription(const Description &description); - bool addRemoteCandidate(const Candidate &candidate); - RTC_WRAPPED(void) gatherLocalCandidates(string mid); - - optional getLocalAddress() const; - optional getRemoteAddress() const; - - RTC_WRAPPED(bool) send(message_ptr message) override; // false if dropped - - RTC_WRAPPED(bool) getSelectedCandidatePair(Candidate *local, Candidate *remote); - -private: - RTC_WRAPPED(bool) outgoing(message_ptr message) override; - - void changeGatheringState(GatheringState state); - - void processStateChange(unsigned int state); - RTC_WRAPPED(void) processCandidate(const string &candidate); - void processGatheringDone(); - void processTimeout(); - - Description::Role mRole; - string mMid; - std::chrono::milliseconds mTrickleTimeout; - std::atomic mGatheringState; - - candidate_callback mCandidateCallback; - gathering_state_callback mGatheringStateChangeCallback; - -#if !USE_NICE - unique_ptr mAgent; - - static void StateChangeCallback(juice_agent_t *agent, juice_state_t state, void *user_ptr); - static void CandidateCallback(juice_agent_t *agent, const char *sdp, void *user_ptr); - static void GatheringDoneCallback(juice_agent_t *agent, void *user_ptr); - static void RecvCallback(juice_agent_t *agent, const char *data, size_t size, void *user_ptr); - static void LogCallback(juice_log_level_t level, const char *message); -#else - static unique_ptr MainLoop; - static std::thread MainLoopThread; - - unique_ptr mNiceAgent; - uint32_t mStreamId = 0; - guint mTimeoutId = 0; - std::mutex mOutgoingMutex; - unsigned int mOutgoingDscp; - - static string AddressToString(const NiceAddress &addr); - - static void CandidateCallback(NiceAgent *agent, NiceCandidate *candidate, gpointer userData); - static void GatheringDoneCallback(NiceAgent *agent, guint streamId, gpointer userData); - static void StateChangeCallback(NiceAgent *agent, guint streamId, guint componentId, - guint state, gpointer userData); - static void RecvCallback(NiceAgent *agent, guint stream_id, guint component_id, guint len, - gchar *buf, gpointer userData); - static gboolean TimeoutCallback(gpointer userData); - static void LogCallback(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, - gpointer user_data); -#endif -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/init.cpp b/godot/thirdparty/libdatachannel/src/impl/init.cpp deleted file mode 100644 index 609bb536..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/init.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Copyright (c) 2020-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "init.hpp" -#include "certificate.hpp" -#include "dtlstransport.hpp" -#include "icetransport.hpp" -#include "internals.hpp" -#include "pollservice.hpp" -#include "sctptransport.hpp" -#include "threadpool.hpp" -#include "tls.hpp" -#include "utils.hpp" - -#if RTC_ENABLE_WEBSOCKET -#include "tlstransport.hpp" -#endif - -#if RTC_ENABLE_MEDIA -#include "dtlssrtptransport.hpp" -#endif - -#ifdef _WIN32 -#include -#endif - -#include - -namespace rtc::impl { - -struct Init::TokenPayload { - TokenPayload(std::shared_future *cleanupFuture) { - Init::Instance().doInit(); - if (cleanupFuture) - *cleanupFuture = cleanupPromise.get_future().share(); - } - - ~TokenPayload() { - std::thread t( - [](std::promise promise) { - utils::this_thread::set_name("RTC cleanup"); - RTC_TRY { - Init::Instance().doCleanup(); - promise.set_value(); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - promise.set_exception(std::make_exception_ptr(e)); - } - }, - std::move(cleanupPromise)); - t.detach(); - } - - std::promise cleanupPromise; -}; - -Init &Init::Instance() { - static Init *instance = new Init; - return *instance; -} - -Init::Init() { - std::promise p; - p.set_value(); - mCleanupFuture = p.get_future(); // make it ready -} - -Init::~Init() {} - -init_token Init::token() { - std::lock_guard lock(mMutex); - if (auto locked = mWeak.lock()) - return locked; - - mGlobal = std::make_shared(&mCleanupFuture); - mWeak = *mGlobal; - return *mGlobal; -} - -void Init::preload() { - std::lock_guard lock(mMutex); - if (!mGlobal) { - mGlobal = std::make_shared(&mCleanupFuture); - mWeak = *mGlobal; - } -} - -std::shared_future Init::cleanup() { - std::lock_guard lock(mMutex); - mGlobal.reset(); - return mCleanupFuture; -} - -RTC_WRAPPED(void) Init::setSctpSettings(SctpSettings s) { - RTC_BEGIN; - std::lock_guard lock(mMutex); - if (mGlobal) - RTC_UNWRAP_RETHROW(SctpTransport::SetSettings(s)); - - mCurrentSctpSettings = std::move(s); // store for next init - RTC_RET; -} - -void Init::doInit() { - // mMutex needs to be locked - - if (std::exchange(mInitialized, true)) - return; - - PLOG_DEBUG << "Global initialization"; - -#ifdef _WIN32 - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData)) - PLOG_ERROR << ("WSAStartup failed, error=" + std::to_string(WSAGetLastError())); -#endif - - int concurrency = std::thread::hardware_concurrency(); - int count = std::max(concurrency, MIN_THREADPOOL_SIZE); - PLOG_DEBUG << "Spawning " << count << " threads"; - ThreadPool::Instance().spawn(count); - -#if RTC_ENABLE_WEBSOCKET - PollService::Instance().start(); -#endif - -#if USE_GNUTLS - // Nothing to do -#elif USE_MBEDTLS - // Nothing to do -#else - openssl::init(); -#endif - - SctpTransport::Init(); - RTC_TRY { - RTC_UNWRAP_CATCH(SctpTransport::SetSettings(mCurrentSctpSettings)); - } RTC_CATCH(RTC_EXCEPTION e) { - PLOG_ERROR << e.RTC_WHAT(); - } - DtlsTransport::Init(); -#if RTC_ENABLE_WEBSOCKET - TlsTransport::Init(); -#endif -#if RTC_ENABLE_MEDIA - DtlsSrtpTransport::Init(); -#endif - IceTransport::Init(); -} - -void Init::doCleanup() { - std::lock_guard lock(mMutex); - if (mGlobal) - return; - - if (!std::exchange(mInitialized, false)) - return; - - PLOG_DEBUG << "Global cleanup"; - - ThreadPool::Instance().join(); - ThreadPool::Instance().clear(); -#if RTC_ENABLE_WEBSOCKET - PollService::Instance().join(); -#endif - - SctpTransport::Cleanup(); - DtlsTransport::Cleanup(); -#if RTC_ENABLE_WEBSOCKET - TlsTransport::Cleanup(); -#endif -#if RTC_ENABLE_MEDIA - DtlsSrtpTransport::Cleanup(); -#endif - IceTransport::Cleanup(); - -#ifdef _WIN32 - WSACleanup(); -#endif -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/init.hpp b/godot/thirdparty/libdatachannel/src/impl/init.hpp deleted file mode 100644 index 17419713..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/init.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2020-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_INIT_H -#define RTC_IMPL_INIT_H - -#include "common.hpp" -#include "global.hpp" // for SctpSettings - -#include -#include -#include - -namespace rtc::impl { - -using init_token = shared_ptr; - -class Init { -public: - static Init &Instance(); - - Init(const Init &) = delete; - Init &operator=(const Init &) = delete; - Init(Init &&) = delete; - Init &operator=(Init &&) = delete; - - init_token token(); - void preload(); - std::shared_future cleanup(); - RTC_WRAPPED(void) setSctpSettings(SctpSettings s); - -private: - Init(); - ~Init(); - - void doInit(); - void doCleanup(); - - std::optional> mGlobal; - weak_ptr mWeak; - bool mInitialized = false; - SctpSettings mCurrentSctpSettings = {}; - std::mutex mMutex; - std::shared_future mCleanupFuture; - - struct TokenPayload; -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/internals.hpp b/godot/thirdparty/libdatachannel/src/impl/internals.hpp deleted file mode 100644 index bbbb68b0..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/internals.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_INTERNALS_H -#define RTC_IMPL_INTERNALS_H - -#include "common.hpp" - -// Disable warnings before including plog -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wall" -#elif defined(_MSC_VER) -#pragma warning(push, 0) -#endif - -#include "plog/Log.h" - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#elif defined(_MSC_VER) -#pragma warning(pop) -#endif - -namespace rtc { - -const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length -const size_t MAX_NUMERICSERV_LEN = 6; // Max port string representation length - -const uint16_t DEFAULT_SCTP_PORT = 5000; // SCTP port to use by default - -const uint16_t MAX_SCTP_STREAMS_COUNT = 1024; // Max number of negotiated SCTP streams - // RFC 8831 recommends 65535 but usrsctp needs a lot - // of memory, Chromium historically limits to 1024. - -const size_t DEFAULT_LOCAL_MAX_MESSAGE_SIZE = 256 * 1024; // Default local max message size -const size_t DEFAULT_MAX_MESSAGE_SIZE = 65536; // Remote max message size if not specified in SDP - -const size_t RECV_QUEUE_LIMIT = 1024 * 1024; // Max per-channel queue size - -const int MIN_THREADPOOL_SIZE = 4; // Minimum number of threads in the global thread pool (>= 2) - -const size_t DEFAULT_MTU = RTC_DEFAULT_MTU; // defined in rtc.h - -} // namespace rtc - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/logcounter.cpp b/godot/thirdparty/libdatachannel/src/impl/logcounter.cpp deleted file mode 100644 index 513506f0..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/logcounter.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2021 Staz Modrzynski - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "logcounter.hpp" - -namespace rtc::impl { - -LogCounter::LogCounter(plog::Severity severity, const std::string &text, - std::chrono::seconds duration) { - mData = std::make_shared(); - mData->mDuration = duration; - mData->mSeverity = severity; - mData->mText = text; -} - -LogCounter &LogCounter::operator++(int) { - if (mData->mCount++ == 0) { - ThreadPool::Instance().schedule( - mData->mDuration, - [](weak_ptr data) { - if (auto ptr = data.lock()) { - int countCopy; - countCopy = ptr->mCount.exchange(0); - PLOG(ptr->mSeverity) - << ptr->mText << ": " << countCopy << " (over " - << std::chrono::duration_cast(ptr->mDuration).count() - << " seconds)"; - } - }, - mData); - } - return *this; -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/logcounter.hpp b/godot/thirdparty/libdatachannel/src/impl/logcounter.hpp deleted file mode 100644 index 9a14ed58..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/logcounter.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021 Staz Modrzynski - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_SERVER_LOGCOUNTER_HPP -#define RTC_SERVER_LOGCOUNTER_HPP - -#include "common.hpp" -#include "threadpool.hpp" - -#include -#include - -namespace rtc::impl { - -class LogCounter { -private: - struct LogData { - plog::Severity mSeverity; - std::string mText; - std::chrono::steady_clock::duration mDuration; - - std::atomic mCount = 0; - }; - - shared_ptr mData; - -public: - LogCounter(plog::Severity severity, const std::string &text, - std::chrono::seconds duration = std::chrono::seconds(1)); - - LogCounter &operator++(int); -}; - -} // namespace rtc::impl - -#endif // RTC_SERVER_LOGCOUNTER_HPP diff --git a/godot/thirdparty/libdatachannel/src/impl/peerconnection.cpp b/godot/thirdparty/libdatachannel/src/impl/peerconnection.cpp deleted file mode 100644 index 592f393e..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/peerconnection.cpp +++ /dev/null @@ -1,1355 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "peerconnection.hpp" -#include "certificate.hpp" -#include "dtlstransport.hpp" -#include "icetransport.hpp" -#include "internals.hpp" -#include "logcounter.hpp" -#include "peerconnection.hpp" -#include "processor.hpp" -#include "rtp.hpp" -#include "sctptransport.hpp" -#include "utils.hpp" - -#if RTC_ENABLE_MEDIA -#include "dtlssrtptransport.hpp" -#endif - -#include -#include -#include -#include -#include -#include - -using namespace std::placeholders; - -namespace rtc::impl { - -static LogCounter COUNTER_MEDIA_TRUNCATED(plog::warning, - "Number of truncated RTP packets over past second"); -static LogCounter COUNTER_SRTP_DECRYPT_ERROR(plog::warning, - "Number of SRTP decryption errors over past second"); -static LogCounter COUNTER_SRTP_ENCRYPT_ERROR(plog::warning, - "Number of SRTP encryption errors over past second"); -static LogCounter - COUNTER_UNKNOWN_PACKET_TYPE(plog::warning, - "Number of unknown RTCP packet types over past second"); - -PeerConnection::PeerConnection(Configuration config_) - : config(std::move(config_)), mCertificate(make_certificate(config.certificateType)) { - PLOG_VERBOSE << "Creating PeerConnection"; - - if (config.portRangeEnd && config.portRangeBegin > config.portRangeEnd) - PLOG_ERROR << "Invalid port range"; - - if (config.mtu) { - if (*config.mtu < 576) // Min MTU for IPv4 - PLOG_ERROR << "Invalid MTU value"; - - if (*config.mtu > 1500) { // Standard Ethernet - PLOG_WARNING << "MTU set to " << *config.mtu; - } else { - PLOG_VERBOSE << "MTU set to " << *config.mtu; - } - } -} - -PeerConnection::~PeerConnection() { - PLOG_VERBOSE << "Destroying PeerConnection"; - mProcessor.join(); -} - -void PeerConnection::close() { - negotiationNeeded = false; - if (!closing.exchange(true)) { - PLOG_VERBOSE << "Closing PeerConnection"; - if (auto transport = std::atomic_load(&mSctpTransport)) - transport->stop(); - else - remoteClose(); - } -} - -void PeerConnection::remoteClose() { - close(); - if (state.load() != State::Closed) { - // Close data channels and tracks asynchronously - mProcessor.enqueue(&PeerConnection::closeDataChannels, shared_from_this()); -#if RTC_ENABLE_MEDIA - mProcessor.enqueue(&PeerConnection::closeTracks, shared_from_this()); -#endif - - closeTransports(); - } -} - -optional PeerConnection::localDescription() const { - std::lock_guard lock(mLocalDescriptionMutex); - return mLocalDescription; -} - -optional PeerConnection::remoteDescription() const { - std::lock_guard lock(mRemoteDescriptionMutex); - return mRemoteDescription; -} - -size_t PeerConnection::remoteMaxMessageSize() const { - const size_t localMax = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE); - - size_t remoteMax = DEFAULT_MAX_MESSAGE_SIZE; - std::lock_guard lock(mRemoteDescriptionMutex); - if (mRemoteDescription) - if (auto *application = mRemoteDescription->application()) - if (auto max = application->maxMessageSize()) { - // RFC 8841: If the SDP "max-message-size" attribute contains a maximum message - // size value of zero, it indicates that the SCTP endpoint will handle messages - // of any size, subject to memory capacity, etc. - remoteMax = *max > 0 ? *max : std::numeric_limits::max(); - } - - return std::min(remoteMax, localMax); -} - -// Helper for PeerConnection::initXTransport methods: start and emplace the transport -template -static RTC_WRAPPED(shared_ptr) emplaceTransport(PeerConnection *pc, shared_ptr *member, shared_ptr transport) { - std::atomic_store(member, transport); - RTC_TRY { - RTC_UNWRAP_CATCH(transport->start()); - } RTC_CATCH (...) { - std::atomic_store(member, decltype(transport)(nullptr)); - RTC_RETHROW; - } - - if (pc->closing.load() || pc->state.load() == PeerConnection::State::Closed) { - std::atomic_store(member, decltype(transport)(nullptr)); - transport->stop(); - return shared_ptr(); - } - - return transport; -} - -RTC_WRAPPED(shared_ptr) PeerConnection::initIceTransport() { - RTC_TRY { - if (auto transport = std::atomic_load(&mIceTransport)) - return transport; - - PLOG_VERBOSE << "Starting ICE transport"; - - auto transport = std::make_shared( - [this, weak_this = weak_from_this()](Candidate candidate) -> RTC_WRAPPED(void) { - return PeerConnection::processLocalCandidate(candidate); - }, - [this, weak_this = weak_from_this()](IceTransport::State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (transportState) { - case IceTransport::State::Connecting: - changeIceState(IceState::Checking); - changeState(State::Connecting); - break; - case IceTransport::State::Connected: - changeIceState(IceState::Connected); - { RTC_TRY { - RTC_UNWRAP_CATCH(initDtlsTransport()); - } RTC_CATCH(...) { - } } - break; - case IceTransport::State::Completed: - changeIceState(IceState::Completed); - break; - case IceTransport::State::Failed: - changeIceState(IceState::Failed); - changeState(State::Failed); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - case IceTransport::State::Disconnected: - changeIceState(IceState::Disconnected); - changeState(State::Disconnected); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - default: - // Ignore - break; - } - return; - }, - [this, weak_this = weak_from_this()](IceTransport::GatheringState gatheringState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (gatheringState) { - case IceTransport::GatheringState::InProgress: - changeGatheringState(GatheringState::InProgress); - break; - case IceTransport::GatheringState::Complete: - endLocalCandidates(); - changeGatheringState(GatheringState::Complete); - break; - default: - // Ignore - break; - } - }); - RTC_UNWRAP_CATCH(transport->construct(config)); - - return emplaceTransport(this, &mIceTransport, std::move(transport)); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << e.RTC_WHAT(); - changeState(State::Failed); - RTC_THROW RTC_RUNTIME_ERROR("ICE transport initialization failed"); - } -} - -RTC_WRAPPED(shared_ptr) PeerConnection::initDtlsTransport() { - RTC_TRY { - if (auto transport = std::atomic_load(&mDtlsTransport)) - return transport; - - PLOG_VERBOSE << "Starting DTLS transport"; - - auto lower = std::atomic_load(&mIceTransport); - if (!lower) - RTC_THROW RTC_LOGIC_ERROR("No underlying ICE transport for DTLS transport"); - - RTC_UNWRAP_CATCH_DECL(certificate_ptr, certificate, mCertificate.get()); - auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1); - auto dtlsStateChangeCallback = - [this, weak_this = weak_from_this()](DtlsTransport::State transportState) -> void { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - - switch (transportState) { - case DtlsTransport::State::Connected: - if (auto remote = remoteDescription(); remote && remote->hasApplication()) { - RTC_TRY { - RTC_UNWRAP_CATCH(initSctpTransport()); - } RTC_CATCH(RTC_EXCEPTION e) { - PLOG_ERROR << e.RTC_WHAT(); - } - } else - changeState(State::Connected); - -#if RTC_ENABLE_MEDIA - mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); -#endif - break; - case DtlsTransport::State::Failed: - changeState(State::Failed); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - case DtlsTransport::State::Disconnected: - changeState(State::Disconnected); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - default: - // Ignore - break; - } - return; - }; - - shared_ptr transport; - auto local = localDescription(); - if (config.forceMediaTransport || (local && local->hasAudioOrVideo())) { -#if RTC_ENABLE_MEDIA - PLOG_INFO << "This connection requires media support"; - - // DTLS-SRTP - transport = std::make_shared( - lower, certificate, config.mtu, verifierCallback, - weak_bind(&PeerConnection::forwardMedia, this, _1), dtlsStateChangeCallback); -#else - PLOG_WARNING << "Ignoring media support (not compiled with media support)"; -#endif - } - - if (!transport) { - // DTLS only - transport = std::make_shared(lower, certificate, config.mtu, - verifierCallback, dtlsStateChangeCallback); - RTC_UNWRAP_CATCH(transport->construct()); - } - - return emplaceTransport(this, &mDtlsTransport, std::move(transport)); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << e.RTC_WHAT(); - changeState(State::Failed); - RTC_THROW RTC_RUNTIME_ERROR("DTLS transport initialization failed"); - } -} - -RTC_WRAPPED(shared_ptr) PeerConnection::initSctpTransport() { - RTC_TRY { - if (auto transport = std::atomic_load(&mSctpTransport)) - return transport; - - PLOG_VERBOSE << "Starting SCTP transport"; - - auto lower = std::atomic_load(&mDtlsTransport); - if (!lower) - RTC_THROW RTC_LOGIC_ERROR("No underlying DTLS transport for SCTP transport"); - - auto local = localDescription(); - if (!local || !local->application()) - RTC_THROW RTC_LOGIC_ERROR("Starting SCTP transport without local application description"); - - auto remote = remoteDescription(); - if (!remote || !remote->application()) - RTC_THROW RTC_LOGIC_ERROR( - "Starting SCTP transport without remote application description"); - - SctpTransport::Ports ports = {}; - ports.local = local->application()->sctpPort().value_or(DEFAULT_SCTP_PORT); - ports.remote = remote->application()->sctpPort().value_or(DEFAULT_SCTP_PORT); - - auto transport = std::make_shared( - lower, std::move(ports), - [this, weak_this = weak_from_this()](message_ptr message) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - RTC_TRY { - RTC_UNWRAP_CATCH(shared_this->forwardMessage(message)); - } RTC_CATCH(RTC_EXCEPTION e) { - PLOG_WARNING << e.RTC_WHAT(); // FIXME - } - }, - weak_bind(&PeerConnection::forwardBufferedAmount, this, _1, _2), - [this, weak_this = weak_from_this()](SctpTransport::State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - - switch (transportState) { - case SctpTransport::State::Connected: - changeState(State::Connected); - { RTC_TRY { - RTC_UNWRAP_CATCH(assignDataChannels()); - } RTC_CATCH(...) { - } } - mProcessor.enqueue(&PeerConnection::openDataChannels, shared_from_this()); - break; - case SctpTransport::State::Failed: - changeState(State::Failed); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - case SctpTransport::State::Disconnected: - changeState(State::Disconnected); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - default: - // Ignore - break; - } - }); - RTC_UNWRAP_CATCH(transport->construct(config)); - return emplaceTransport(this, &mSctpTransport, std::move(transport)); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << e.RTC_WHAT(); - changeState(State::Failed); - RTC_THROW RTC_RUNTIME_ERROR("SCTP transport initialization failed"); - } -} - -shared_ptr PeerConnection::getIceTransport() const { - return std::atomic_load(&mIceTransport); -} - -shared_ptr PeerConnection::getDtlsTransport() const { - return std::atomic_load(&mDtlsTransport); -} - -shared_ptr PeerConnection::getSctpTransport() const { - return std::atomic_load(&mSctpTransport); -} - -void PeerConnection::closeTransports() { - PLOG_VERBOSE << "Closing transports"; - - // Change ICE state to sink state Closed - changeIceState(IceState::Closed); - - // Change state to sink state Closed - if (!changeState(State::Closed)) - return; // already closed - - // Reset interceptor and callbacks now that state is changed -#if RTC_ENABLE_MEDIA - setMediaHandler(nullptr); -#endif - resetCallbacks(); - - // Pass the pointers to a thread, allowing to terminate a transport from its own thread - auto sctp = std::atomic_exchange(&mSctpTransport, decltype(mSctpTransport)(nullptr)); - auto dtls = std::atomic_exchange(&mDtlsTransport, decltype(mDtlsTransport)(nullptr)); - auto ice = std::atomic_exchange(&mIceTransport, decltype(mIceTransport)(nullptr)); - - if (sctp) { - sctp->onRecv(nullptr); - sctp->onBufferedAmount(nullptr); - } - - using array = std::array, 3>; - array transports{std::move(sctp), std::move(dtls), std::move(ice)}; - - for (const auto &t : transports) - if (t) - t->onStateChange(nullptr); - - TearDownProcessor::Instance().enqueue( - [transports = std::move(transports), token = Init::Instance().token()]() mutable { - for (const auto &t : transports) { - if (t) { - t->stop(); - break; - } - } - - for (auto &t : transports) - t.reset(); - }); -} - -void PeerConnection::endLocalCandidates() { - std::lock_guard lock(mLocalDescriptionMutex); - if (mLocalDescription) - mLocalDescription->endCandidates(); -} - -void PeerConnection::rollbackLocalDescription() { - PLOG_DEBUG << "Rolling back pending local description"; - - std::unique_lock lock(mLocalDescriptionMutex); - if (mCurrentLocalDescription) { - std::vector existingCandidates; - if (mLocalDescription) - existingCandidates = mLocalDescription->extractCandidates(); - - mLocalDescription.emplace(std::move(*mCurrentLocalDescription)); - mLocalDescription->addCandidates(std::move(existingCandidates)); - mCurrentLocalDescription.reset(); - } -} - -bool PeerConnection::checkFingerprint(const std::string &fingerprint) const { - std::lock_guard lock(mRemoteDescriptionMutex); - auto expectedFingerprint = mRemoteDescription ? mRemoteDescription->fingerprint() : nullopt; - if (expectedFingerprint && *expectedFingerprint == fingerprint) { - PLOG_VERBOSE << "Valid fingerprint \"" << fingerprint << "\""; - return true; - } - - PLOG_ERROR << "Invalid fingerprint \"" << fingerprint << "\", expected \"" - << expectedFingerprint.value_or("[none]") << "\""; - return false; -} - -RTC_WRAPPED(void) PeerConnection::forwardMessage(message_ptr message) { - RTC_BEGIN; - if (!message) { - remoteCloseDataChannels(); - RTC_RET; - } - - auto iceTransport = std::atomic_load(&mIceTransport); - auto sctpTransport = std::atomic_load(&mSctpTransport); - if (!iceTransport || !sctpTransport) - RTC_RET; - - const uint16_t stream = uint16_t(message->stream); - auto [channel_, found_] = findDataChannel(stream); - auto channel = channel_; - bool found = found_; - - if (DataChannel::IsOpenMessage(message)) { - if (found) { - // The stream is already used, the receiver must close the DataChannel - PLOG_WARNING << "Got open message on already used stream " << stream; - if (channel && !channel->isClosed()) - channel->close(); - else - sctpTransport->closeStream(message->stream); - - RTC_RET; - } - - const uint16_t remoteParity = (iceTransport->role() == Description::Role::Active) ? 1 : 0; - if (stream % 2 != remoteParity) { - // The odd/even rule is violated, the receiver must close the DataChannel - PLOG_WARNING << "Got open message violating the odd/even rule on stream " << stream; - sctpTransport->closeStream(message->stream); - RTC_RET; - } - - channel = std::make_shared(weak_from_this(), sctpTransport); - RTC_UNWRAP_RETHROW(channel->assignStream(stream)); - channel->openCallback = - weak_bind(&PeerConnection::triggerDataChannel, this, weak_ptr{channel}); - - std::unique_lock lock(mDataChannelsMutex); // we are going to emplace - mDataChannels.emplace(stream, channel); - } else if (!found) { - if (message->type == Message::Reset) - RTC_RET; // ignore - - // Invalid, close the DataChannel - PLOG_WARNING << "Got unexpected message on stream " << stream; - sctpTransport->closeStream(message->stream); - RTC_RET; - } - - if (message->type == Message::Reset) { - // Incoming stream is reset, unregister it - removeDataChannel(stream); - } - - if (channel) { - // Forward the message - RTC_UNWRAP_RETHROW(channel->incoming(message)); - } else { - // DataChannel was destroyed, ignore - PLOG_DEBUG << "Ignored message on stream " << stream << ", DataChannel is destroyed"; - } - RTC_RET; -} - -void PeerConnection::forwardMedia(message_ptr message) { -#if RTC_ENABLE_MEDIA - if (!message) - return; - - auto handler = getMediaHandler(); - - if (handler) { - message = handler->incoming(message); - if (!message) - return; - } - - // Browsers like to compound their packets with a random SSRC. - // we have to do this monstrosity to distribute the report blocks - if (message->type == Message::Control) { - std::set ssrcs; - size_t offset = 0; - while ((sizeof(RtcpHeader) + offset) <= message->size()) { - auto header = reinterpret_cast(message->data() + offset); - if (header->lengthInBytes() > message->size() - offset) { - COUNTER_MEDIA_TRUNCATED++; - break; - } - offset += header->lengthInBytes(); - if (header->payloadType() == 205 || header->payloadType() == 206) { - auto rtcpfb = reinterpret_cast(header); - ssrcs.insert(rtcpfb->packetSenderSSRC()); - ssrcs.insert(rtcpfb->mediaSourceSSRC()); - - } else if (header->payloadType() == 200) { - auto rtcpsr = reinterpret_cast(header); - ssrcs.insert(rtcpsr->senderSSRC()); - for (int i = 0; i < rtcpsr->header.reportCount(); ++i) - ssrcs.insert(rtcpsr->getReportBlock(i)->getSSRC()); - } else if (header->payloadType() == 201) { - auto rtcprr = reinterpret_cast(header); - ssrcs.insert(rtcprr->senderSSRC()); - for (int i = 0; i < rtcprr->header.reportCount(); ++i) - ssrcs.insert(rtcprr->getReportBlock(i)->getSSRC()); - } else if (header->payloadType() == 202) { - auto sdes = reinterpret_cast(header); - if (!sdes->isValid()) { - PLOG_WARNING << "RTCP SDES packet is invalid"; - continue; - } - for (unsigned int i = 0; i < sdes->chunksCount(); i++) { - auto chunk = sdes->getChunk(i); - ssrcs.insert(chunk->ssrc()); - } - } else { - // PT=203 == Goodbye - // PT=204 == Application Specific - // PT=207 == Extended Report - if (header->payloadType() != 203 && header->payloadType() != 204 && - header->payloadType() != 207) { - COUNTER_UNKNOWN_PACKET_TYPE++; - } - } - } - - if (!ssrcs.empty()) { - std::shared_lock lock(mTracksMutex); // read-only - for (uint32_t ssrc : ssrcs) { - if (auto it = mTracksBySsrc.find(ssrc); it != mTracksBySsrc.end()) { - if (auto track = it->second.lock()) - track->incoming(message); - } - } - return; - } - } - - uint32_t ssrc = uint32_t(message->stream); - - std::shared_lock lock(mTracksMutex); // read-only - if (auto it = mTracksBySsrc.find(ssrc); it != mTracksBySsrc.end()) { - if (auto track = it->second.lock()) - track->incoming(message); - } else { - /* - * TODO: So the problem is that when stop sending streams, we stop getting report blocks for - * those streams Therefore when we get compound RTCP packets, they are empty, and we can't - * forward them. Therefore, it is expected that we don't know where to forward packets. Is - * this ideal? No! Do I know how to fix it? No! - */ - // PLOG_WARNING << "Track not found for SSRC " << ssrc << ", dropping"; - return; - } -#endif -} - -void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) { - [[maybe_unused]] auto [channel, found] = findDataChannel(stream); - if (channel) - channel->triggerBufferedAmount(amount); -} - -RTC_WRAPPED(shared_ptr) PeerConnection::emplaceDataChannel(string label, DataChannelInit init) { - RTC_BEGIN; - std::unique_lock lock(mDataChannelsMutex); // we are going to emplace - - // If the DataChannel is user-negotiated, do not negotiate it in-band - auto channel = - init.negotiated - ? std::make_shared(weak_from_this(), std::move(label), - std::move(init.protocol), std::move(init.reliability)) - : std::make_shared(weak_from_this(), std::move(label), - std::move(init.protocol), - std::move(init.reliability)); - - // If the user supplied a stream id, use it, otherwise assign it later - if (init.id) { - uint16_t stream = *init.id; - if (stream > maxDataChannelStream()) - RTC_THROW RTC_INVALID_ARGUMENT("DataChannel stream id is too high"); - - RTC_UNWRAP_RETHROW(channel->assignStream(stream)); - mDataChannels.emplace(std::make_pair(stream, channel)); - - } else { - mUnassignedDataChannels.push_back(channel); - } - - lock.unlock(); // we are going to call assignDataChannels() - - // If SCTP is connected, assign and open now - auto sctpTransport = std::atomic_load(&mSctpTransport); - if (sctpTransport && sctpTransport->state() == SctpTransport::State::Connected) { - RTC_UNWRAP_RETHROW(assignDataChannels()); - RTC_UNWRAP_RETHROW(channel->open(sctpTransport)); - } - - return channel; -} - -std::pair, bool> PeerConnection::findDataChannel(uint16_t stream) { - std::shared_lock lock(mDataChannelsMutex); // read-only - if (auto it = mDataChannels.find(stream); it != mDataChannels.end()) - return std::make_pair(it->second.lock(), true); - else - return std::make_pair(nullptr, false); -} - -bool PeerConnection::removeDataChannel(uint16_t stream) { - std::unique_lock lock(mDataChannelsMutex); // we are going to erase - return mDataChannels.erase(stream) != 0; -} - -uint16_t PeerConnection::maxDataChannelStream() const { - auto sctpTransport = std::atomic_load(&mSctpTransport); - return sctpTransport ? sctpTransport->maxStream() : (MAX_SCTP_STREAMS_COUNT - 1); -} - -RTC_WRAPPED(void) PeerConnection::assignDataChannels() { - RTC_BEGIN; - std::unique_lock lock(mDataChannelsMutex); // we are going to emplace - - auto iceTransport = std::atomic_load(&mIceTransport); - if (!iceTransport) - RTC_THROW RTC_LOGIC_ERROR("Attempted to assign DataChannels without ICE transport"); - - const uint16_t maxStream = maxDataChannelStream(); - for (auto it = mUnassignedDataChannels.begin(); it != mUnassignedDataChannels.end(); ++it) { - auto channel = it->lock(); - if (!channel) - continue; - - // RFC 8832: The peer that initiates opening a data channel selects a stream identifier - // for which the corresponding incoming and outgoing streams are unused. If the side is - // acting as the DTLS client, it MUST choose an even stream identifier; if the side is - // acting as the DTLS server, it MUST choose an odd one. See - // https://www.rfc-editor.org/rfc/rfc8832.html#section-6 - uint16_t stream = (iceTransport->role() == Description::Role::Active) ? 0 : 1; - while (true) { - if (stream > maxStream) - RTC_THROW RTC_RUNTIME_ERROR("Too many DataChannels"); - - if (mDataChannels.find(stream) == mDataChannels.end()) - break; - - stream += 2; - } - - PLOG_DEBUG << "Assigning stream " << stream << " to DataChannel"; - - RTC_UNWRAP_RETHROW(channel->assignStream(stream)); - mDataChannels.emplace(std::make_pair(stream, channel)); - } - - mUnassignedDataChannels.clear(); - RTC_RET; -} - -void PeerConnection::iterateDataChannels( - std::function channel)> func) { - std::vector> locked; - { - std::shared_lock lock(mDataChannelsMutex); // read-only - locked.reserve(mDataChannels.size()); - auto it = mDataChannels.begin(); - while (it != mDataChannels.end()) { - auto channel = it->second.lock(); - if (channel && !channel->isClosed()) - locked.push_back(std::move(channel)); - - ++it; - } - } - - for (auto &channel : locked) { - RTC_TRY { - RTC_UNWRAP_CATCH(func(std::move(channel))); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } - } -} - -void PeerConnection::openDataChannels() { - if (auto transport = std::atomic_load(&mSctpTransport)) - iterateDataChannels([&](shared_ptr channel) { - if (!channel->isOpen()) - return channel->open(transport); - RTC_RET; - }); -} - -void PeerConnection::closeDataChannels() { - iterateDataChannels([&](shared_ptr channel) { channel->close(); RTC_RET; }); -} - -void PeerConnection::remoteCloseDataChannels() { - iterateDataChannels([&](shared_ptr channel) { channel->remoteClose(); RTC_RET; }); -} - -#if RTC_ENABLE_MEDIA -shared_ptr PeerConnection::emplaceTrack(Description::Media description) { -#if !RTC_ENABLE_MEDIA - // No media support, mark as removed - PLOG_WARNING << "Tracks are disabled (not compiled with media support)"; - description.markRemoved(); -#endif - - shared_ptr track; - if (auto it = mTracks.find(description.mid()); it != mTracks.end()) - if (track = it->second.lock(); track) - track->setDescription(std::move(description)); - - if (!track) { - track = std::make_shared(weak_from_this(), std::move(description)); - mTracks.emplace(std::make_pair(track->mid(), track)); - mTrackLines.emplace_back(track); - } - - if (track->description().isRemoved()) - track->close(); - - return track; -} - -void PeerConnection::iterateTracks(std::function track)> func) { - std::shared_lock lock(mTracksMutex); // read-only - for (auto it = mTrackLines.begin(); it != mTrackLines.end(); ++it) { - auto track = it->lock(); - if (track && !track->isClosed()) { - RTC_TRY { - func(std::move(track)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } - } - } -} - -void PeerConnection::openTracks() { - if (auto transport = std::atomic_load(&mDtlsTransport)) { - auto srtpTransport = std::dynamic_pointer_cast(transport); - - iterateTracks([&](const shared_ptr &track) { - if (!track->isOpen()) { - if (srtpTransport) { - track->open(srtpTransport); - } else { - // A track was added during a latter renegotiation, whereas SRTP transport was - // not initialized. This is an optimization to use the library with data - // channels only. Set forceMediaTransport to true to initialize the transport - // before dynamically adding tracks. - auto errorMsg = "The connection has no media transport"; - PLOG_ERROR << errorMsg; - track->triggerError(errorMsg); - } - } - }); - } -} - -void PeerConnection::closeTracks() { - std::shared_lock lock(mTracksMutex); // read-only - iterateTracks([&](shared_ptr track) { track->close(); }); -} -#endif - -RTC_WRAPPED(void) PeerConnection::validateRemoteDescription(const Description &description) { - RTC_BEGIN; - if (!description.iceUfrag()) - RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no ICE user fragment"); - - if (!description.icePwd()) - RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no ICE password"); - - if (!description.fingerprint()) - RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no valid fingerprint"); - - if (description.mediaCount() == 0) - RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no media line"); - - int activeMediaCount = 0; - for (unsigned int i = 0; i < description.mediaCount(); ++i) { - RTC_UNWRAP_RETHROW_DECL(auto, media, description.media(i)); - std::visit(rtc::overloaded{[&](const Description::Application *application) { - if (!application->isRemoved()) - ++activeMediaCount; - }, - [&](const Description::Media *media) { - if (!media->isRemoved() || - media->direction() != Description::Direction::Inactive) - ++activeMediaCount; - }}, - media); - } - - if (activeMediaCount == 0) - RTC_THROW RTC_INVALID_ARGUMENT("Remote description has no active media"); - - if (auto local = localDescription(); local && local->iceUfrag() && local->icePwd()) - if (*description.iceUfrag() == *local->iceUfrag() && - *description.icePwd() == *local->icePwd()) - RTC_THROW RTC_LOGIC_ERROR("Got the local description as remote description"); - - PLOG_VERBOSE << "Remote description looks valid"; - RTC_RET; -} - -RTC_WRAPPED(void) PeerConnection::processLocalDescription(Description description) { - RTC_BEGIN; - const uint16_t localSctpPort = DEFAULT_SCTP_PORT; - const size_t localMaxMessageSize = - config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE); - - // Clean up the application entry the ICE transport might have added already (libnice) - description.clearMedia(); - - if (auto remote = remoteDescription()) { - // Reciprocate remote description - for (unsigned int i = 0; i < remote->mediaCount(); ++i) { - RTC_UNWRAP_RETHROW_DECL(auto, remote_media, remote->media(i)); - std::visit( // reciprocate each media - rtc::overloaded{ - [&](Description::Application *remoteApp) { - std::shared_lock lock(mDataChannelsMutex); - if (!mDataChannels.empty() || !mUnassignedDataChannels.empty()) { - // Prefer local description - Description::Application app(remoteApp->mid()); - app.setSctpPort(localSctpPort); - app.setMaxMessageSize(localMaxMessageSize); - - PLOG_DEBUG << "Adding application to local description, mid=\"" - << app.mid() << "\""; - - description.addMedia(std::move(app)); - return; - } - - auto reciprocated = remoteApp->reciprocate(); - reciprocated.hintSctpPort(localSctpPort); - reciprocated.setMaxMessageSize(localMaxMessageSize); - - PLOG_DEBUG << "Reciprocating application in local description, mid=\"" - << reciprocated.mid() << "\""; - - description.addMedia(std::move(reciprocated)); - }, - [&](Description::Media *remoteMedia) { -#if RTC_ENABLE_MEDIA - std::shared_lock lock(mTracksMutex); - if (auto it = mTracks.find(remoteMedia->mid()); it != mTracks.end()) { - // Prefer local description - if (auto track = it->second.lock()) { - auto media = track->description(); - - PLOG_DEBUG << "Adding media to local description, mid=\"" - << media.mid() << "\", removed=" << std::boolalpha - << media.isRemoved(); - - description.addMedia(std::move(media)); - - } else { - auto reciprocated = remoteMedia->reciprocate(); - reciprocated.markRemoved(); - - PLOG_DEBUG << "Adding media to local description, mid=\"" - << reciprocated.mid() - << "\", removed=true (track is destroyed)"; - - description.addMedia(std::move(reciprocated)); - } - return; - } -#endif - auto reciprocated = remoteMedia->reciprocate(); -#if !RTC_ENABLE_MEDIA - if (!reciprocated.isRemoved()) { - // No media support, mark as removed - PLOG_WARNING << "Rejecting track (not compiled with media support)"; - reciprocated.markRemoved(); - } -#endif -#if RTC_ENABLE_MEDIA - PLOG_DEBUG << "Reciprocating media in local description, mid=\"" - << reciprocated.mid() << "\", removed=" << std::boolalpha - << reciprocated.isRemoved(); - - // Create incoming track - auto track = - std::make_shared(weak_from_this(), std::move(reciprocated)); - mTracks.emplace(std::make_pair(track->mid(), track)); - mTrackLines.emplace_back(track); - triggerTrack(track); // The user may modify the track description - - if (track->description().isRemoved()) - track->close(); - - description.addMedia(track->description()); -#endif - }, - }, - remote_media); - } - - // We need to update the SSRC cache for newly-created incoming tracks - updateTrackSsrcCache(*remote); - } - - if (description.type() == Description::Type::Offer) { - // This is an offer, add locally created data channels and tracks -#if RTC_ENABLE_MEDIA - // Add media for local tracks - std::shared_lock lock(mTracksMutex); - for (auto it = mTrackLines.begin(); it != mTrackLines.end(); ++it) { - if (auto track = it->lock()) { - if (description.hasMid(track->mid())) - continue; - - auto media = track->description(); - - PLOG_DEBUG << "Adding media to local description, mid=\"" << media.mid() - << "\", removed=" << std::boolalpha << media.isRemoved(); - - description.addMedia(std::move(media)); - } - } -#endif - - // Add application for data channels - if (!description.hasApplication()) { - std::shared_lock lock(mDataChannelsMutex); - if (!mDataChannels.empty() || !mUnassignedDataChannels.empty()) { - // Prevents mid collision with remote or local tracks - unsigned int m = 0; - while (description.hasMid(std::to_string(m))) - ++m; - - Description::Application app(std::to_string(m)); - app.setSctpPort(localSctpPort); - app.setMaxMessageSize(localMaxMessageSize); - - PLOG_DEBUG << "Adding application to local description, mid=\"" << app.mid() - << "\""; - - description.addMedia(std::move(app)); - } - } - - // There might be no media at this point if the user created a Track, deleted it, - // then called setLocalDescription(). - if (description.mediaCount() == 0) - RTC_THROW RTC_RUNTIME_ERROR("No DataChannel or Track to negotiate"); - } - - // Set local fingerprint (wait for certificate if necessary) - RTC_UNWRAP_RETHROW_DECL(certificate_ptr, certificate, mCertificate.get()); - RTC_UNWRAP_RETHROW(description.setFingerprint(certificate->fingerprint())); - - PLOG_VERBOSE << "Issuing local description: " << description; - - if (description.mediaCount() == 0) - RTC_THROW RTC_LOGIC_ERROR("Local description has no media line"); - - updateTrackSsrcCache(description); - - { - // Set as local description - std::lock_guard lock(mLocalDescriptionMutex); - - std::vector existingCandidates; - if (mLocalDescription) { - existingCandidates = mLocalDescription->extractCandidates(); - mCurrentLocalDescription.emplace(std::move(*mLocalDescription)); - } - - mLocalDescription.emplace(description); - mLocalDescription->addCandidates(std::move(existingCandidates)); - } - - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &localDescriptionCallback, std::move(description)); - - // Reciprocated tracks might need to be open -#if RTC_ENABLE_MEDIA - if (auto dtlsTransport = std::atomic_load(&mDtlsTransport); - dtlsTransport && dtlsTransport->state() == Transport::State::Connected) - mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); -#endif - RTC_RET; -} - -RTC_WRAPPED(void) PeerConnection::processLocalCandidate(Candidate candidate) { - std::lock_guard lock(mLocalDescriptionMutex); - if (!mLocalDescription) - RTC_THROW RTC_LOGIC_ERROR("Got a local candidate without local description"); - - if (config.iceTransportPolicy == TransportPolicy::Relay && - candidate.type() != Candidate::Type::Relayed) { - PLOG_VERBOSE << "Not issuing local candidate because of transport policy: " << candidate; - RTC_RET; - } - - PLOG_VERBOSE << "Issuing local candidate: " << candidate; - - candidate.resolve(Candidate::ResolveMode::Simple); - mLocalDescription->addCandidate(candidate); - - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &localCandidateCallback, std::move(candidate)); - RTC_RET; -} - -RTC_WRAPPED(void) PeerConnection::processRemoteDescription(Description description) { - RTC_BEGIN; - // Update the SSRC cache for existing tracks - updateTrackSsrcCache(description); - - { - // Set as remote description - std::lock_guard lock(mRemoteDescriptionMutex); - - std::vector existingCandidates; - if (mRemoteDescription) - existingCandidates = mRemoteDescription->extractCandidates(); - - mRemoteDescription.emplace(description); - mRemoteDescription->addCandidates(std::move(existingCandidates)); - } - - if (description.hasApplication()) { - auto dtlsTransport = std::atomic_load(&mDtlsTransport); - auto sctpTransport = std::atomic_load(&mSctpTransport); - if (!sctpTransport && dtlsTransport && - dtlsTransport->state() == Transport::State::Connected) - RTC_UNWRAP_RETHROW(initSctpTransport()); - } else { - mProcessor.enqueue(&PeerConnection::remoteCloseDataChannels, shared_from_this()); - } - RTC_RET; -} - -RTC_WRAPPED(void) PeerConnection::processRemoteCandidate(Candidate candidate) { - auto iceTransport = std::atomic_load(&mIceTransport); - { - // Set as remote candidate - std::lock_guard lock(mRemoteDescriptionMutex); - if (!mRemoteDescription) - RTC_THROW RTC_LOGIC_ERROR("Got a remote candidate without remote description"); - - if (!iceTransport) - RTC_THROW RTC_LOGIC_ERROR("Got a remote candidate without ICE transport"); - - candidate.hintMid(mRemoteDescription->bundleMid()); - - if (mRemoteDescription->hasCandidate(candidate)) - RTC_RET; // already in description, ignore - - candidate.resolve(Candidate::ResolveMode::Simple); - mRemoteDescription->addCandidate(candidate); - } - - if (candidate.isResolved()) { - iceTransport->addRemoteCandidate(std::move(candidate)); - } else { - // We might need a lookup, do it asynchronously - // We don't use the thread pool because we have no control on the timeout - if ((iceTransport = std::atomic_load(&mIceTransport))) { - weak_ptr weakIceTransport{iceTransport}; - std::thread t([weakIceTransport, candidate = std::move(candidate)]() mutable { - utils::this_thread::set_name("RTC resolver"); - if (candidate.resolve(Candidate::ResolveMode::Lookup)) - if (auto iceTransport = weakIceTransport.lock()) - iceTransport->addRemoteCandidate(std::move(candidate)); - }); - t.detach(); - } - } - RTC_RET; -} - -string PeerConnection::localBundleMid() const { - std::lock_guard lock(mLocalDescriptionMutex); - return mLocalDescription ? mLocalDescription->bundleMid() : "0"; -} - -#if RTC_ENABLE_MEDIA -void PeerConnection::setMediaHandler(shared_ptr handler) { - std::unique_lock lock(mMediaHandlerMutex); - if (mMediaHandler) - mMediaHandler->onOutgoing(nullptr); - mMediaHandler = handler; -} - -shared_ptr PeerConnection::getMediaHandler() { - std::shared_lock lock(mMediaHandlerMutex); - return mMediaHandler; -} -#endif - -void PeerConnection::triggerDataChannel(weak_ptr weakDataChannel) { - auto dataChannel = weakDataChannel.lock(); - if (dataChannel) { - dataChannel->resetOpenCallback(); // might be set internally - mPendingDataChannels.push(std::move(dataChannel)); - } - triggerPendingDataChannels(); -} - -#if RTC_ENABLE_MEDIA -void PeerConnection::triggerTrack(weak_ptr weakTrack) { - auto track = weakTrack.lock(); - if (track) { - track->resetOpenCallback(); // might be set internally - mPendingTracks.push(std::move(track)); - } - triggerPendingTracks(); -} -#endif - -void PeerConnection::triggerPendingDataChannels() { - while (dataChannelCallback) { - auto next = mPendingDataChannels.pop(); - if (!next) - break; - - auto impl = std::move(*next); - - RTC_TRY { - dataChannelCallback(std::make_shared(impl)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - - impl->triggerOpen(); - } -} - -void PeerConnection::triggerPendingTracks() { -#if RTC_ENABLE_MEDIA - while (trackCallback) { - auto next = mPendingTracks.pop(); - if (!next) - break; - - auto impl = std::move(*next); - - RTC_TRY { - trackCallback(std::make_shared(impl)); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "Uncaught exception in callback: " << e.RTC_WHAT(); - } - - // Do not trigger open immediately for tracks as it'll be done later - } -#endif -} - -void PeerConnection::flushPendingDataChannels() { - mProcessor.enqueue(&PeerConnection::triggerPendingDataChannels, shared_from_this()); -} - -void PeerConnection::flushPendingTracks() { -#if RTC_ENABLE_MEDIA - mProcessor.enqueue(&PeerConnection::triggerPendingTracks, shared_from_this()); -#endif -} - -bool PeerConnection::changeState(State newState) { - State current; - do { - current = state.load(); - if (current == State::Closed) - return false; - if (current == newState) - return false; - - } while (!state.compare_exchange_weak(current, newState)); - - std::ostringstream s; - s << newState; - PLOG_INFO << "Changed state to " << s.str(); - - if (newState == State::Closed) { - auto callback = std::move(stateChangeCallback); // steal the callback - callback(State::Closed); // call it synchronously - } else { - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &stateChangeCallback, newState); - } - return true; -} - -bool PeerConnection::changeIceState(IceState newState) { - if (iceState.exchange(newState) == newState) - return false; - - std::ostringstream s; - s << newState; - PLOG_INFO << "Changed ICE state to " << s.str(); - - if (newState == IceState::Closed) { - auto callback = std::move(iceStateChangeCallback); // steal the callback - callback(IceState::Closed); // call it synchronously - } else { - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &iceStateChangeCallback, newState); - } - return true; -} - -bool PeerConnection::changeGatheringState(GatheringState newState) { - if (gatheringState.exchange(newState) == newState) - return false; - - std::ostringstream s; - s << newState; - PLOG_INFO << "Changed gathering state to " << s.str(); - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &gatheringStateChangeCallback, newState); - - return true; -} - -bool PeerConnection::changeSignalingState(SignalingState newState) { - if (signalingState.exchange(newState) == newState) - return false; - - std::ostringstream s; - s << newState; - PLOG_INFO << "Changed signaling state to " << s.str(); - mProcessor.enqueue(&PeerConnection::trigger, shared_from_this(), - &signalingStateChangeCallback, newState); - - return true; -} - -void PeerConnection::resetCallbacks() { - // Unregister all callbacks - dataChannelCallback = nullptr; - localDescriptionCallback = nullptr; - localCandidateCallback = nullptr; - stateChangeCallback = nullptr; - iceStateChangeCallback = nullptr; - gatheringStateChangeCallback = nullptr; - signalingStateChangeCallback = nullptr; -#if RTC_ENABLE_MEDIA - trackCallback = nullptr; -#endif -} - -void PeerConnection::updateTrackSsrcCache(const Description &description) { -#if RTC_ENABLE_MEDIA - std::unique_lock lock(mTracksMutex); // for safely writing to mTracksBySsrc - - // Setup SSRC -> Track mapping - for (unsigned int i = 0; i < description.mediaCount(); ++i) - std::visit( // ssrc -> track mapping - rtc::overloaded{ - [&](Description::Application const *) { return; }, - [&](Description::Media const *media) { - const auto ssrcs = media->getSSRCs(); - - // Note: We don't want to lock (or do any other lookups), if we - // already know there's no SSRCs to loop over. - if (ssrcs.size() <= 0) { - return; - } - - std::shared_ptr track{nullptr}; - if (auto it = mTracks.find(media->mid()); it != mTracks.end()) - if (auto track_for_mid = it->second.lock()) - track = track_for_mid; - - if (!track) { - // Unable to find track for MID - return; - } - - for (auto ssrc : ssrcs) { - mTracksBySsrc.insert_or_assign(ssrc, track); - } - }, - }, - description.media(i)); -#endif -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/peerconnection.hpp b/godot/thirdparty/libdatachannel/src/impl/peerconnection.hpp deleted file mode 100644 index ca858134..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/peerconnection.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_PEER_CONNECTION_H -#define RTC_IMPL_PEER_CONNECTION_H - -#include "common.hpp" -#include "datachannel.hpp" -#include "dtlstransport.hpp" -#include "icetransport.hpp" -#include "init.hpp" -#include "processor.hpp" -#include "sctptransport.hpp" -#include "track.hpp" - -#include "rtc/peerconnection.hpp" - -#include -#include -#include -#include - -namespace rtc::impl { - -struct PeerConnection : std::enable_shared_from_this { - using State = rtc::PeerConnection::State; - using IceState = rtc::PeerConnection::IceState; - using GatheringState = rtc::PeerConnection::GatheringState; - using SignalingState = rtc::PeerConnection::SignalingState; - - PeerConnection(Configuration config_); - ~PeerConnection(); - - void close(); - void remoteClose(); - - optional localDescription() const; - optional remoteDescription() const; - size_t remoteMaxMessageSize() const; - - RTC_WRAPPED(shared_ptr) initIceTransport(); - RTC_WRAPPED(shared_ptr) initDtlsTransport(); - RTC_WRAPPED(shared_ptr) initSctpTransport(); - shared_ptr getIceTransport() const; - shared_ptr getDtlsTransport() const; - shared_ptr getSctpTransport() const; - void closeTransports(); - - void endLocalCandidates(); - void rollbackLocalDescription(); - bool checkFingerprint(const std::string &fingerprint) const; - RTC_WRAPPED(void) forwardMessage(message_ptr message); - void forwardMedia(message_ptr message); - void forwardBufferedAmount(uint16_t stream, size_t amount); - - RTC_WRAPPED(shared_ptr) emplaceDataChannel(string label, DataChannelInit init); - std::pair, bool> findDataChannel(uint16_t stream); - bool removeDataChannel(uint16_t stream); - uint16_t maxDataChannelStream() const; - RTC_WRAPPED(void) assignDataChannels(); - void iterateDataChannels(std::function channel)> func); - void openDataChannels(); - void closeDataChannels(); - void remoteCloseDataChannels(); - -#if RTC_ENABLE_MEDIA - shared_ptr emplaceTrack(Description::Media description); - void iterateTracks(std::function track)> func); - void openTracks(); - void closeTracks(); -#endif - - RTC_WRAPPED(void) validateRemoteDescription(const Description &description); - RTC_WRAPPED(void) processLocalDescription(Description description); - RTC_WRAPPED(void) processLocalCandidate(Candidate candidate); - RTC_WRAPPED(void) processRemoteDescription(Description description); - RTC_WRAPPED(void) processRemoteCandidate(Candidate candidate); - string localBundleMid() const; - -#if RTC_ENABLE_MEDIA - void setMediaHandler(shared_ptr handler); - shared_ptr getMediaHandler(); -#endif - - void triggerDataChannel(weak_ptr weakDataChannel); -#if RTC_ENABLE_MEDIA - void triggerTrack(weak_ptr weakTrack); -#endif - - void triggerPendingDataChannels(); - void triggerPendingTracks(); - - void flushPendingDataChannels(); - void flushPendingTracks(); - - bool changeState(State newState); - bool changeIceState(IceState newState); - bool changeGatheringState(GatheringState newState); - bool changeSignalingState(SignalingState newState); - - void resetCallbacks(); - - // Helper method for asynchronous callback invocation - template void trigger(synchronized_callback *cb, Args... args) { - (*cb)(std::move(args...)); - } - - const Configuration config; - std::atomic state = State::New; - std::atomic iceState = IceState::New; - std::atomic gatheringState = GatheringState::New; - std::atomic signalingState = SignalingState::Stable; - std::atomic negotiationNeeded = false; - std::atomic closing = false; - std::mutex signalingMutex; - - synchronized_callback> dataChannelCallback; - synchronized_callback localDescriptionCallback; - synchronized_callback localCandidateCallback; - synchronized_callback stateChangeCallback; - synchronized_callback iceStateChangeCallback; - synchronized_callback gatheringStateChangeCallback; - synchronized_callback signalingStateChangeCallback; -#if RTC_ENABLE_MEDIA - synchronized_callback> trackCallback; -#endif - -private: - void updateTrackSsrcCache(const Description &description); - - const init_token mInitToken = Init::Instance().token(); - const future_certificate_ptr mCertificate; - - Processor mProcessor; - optional mLocalDescription, mRemoteDescription; - optional mCurrentLocalDescription; - mutable std::mutex mLocalDescriptionMutex, mRemoteDescriptionMutex; - -#if RTC_ENABLE_MEDIA - shared_ptr mMediaHandler; - - mutable std::shared_mutex mMediaHandlerMutex; -#endif - shared_ptr mIceTransport; - shared_ptr mDtlsTransport; - shared_ptr mSctpTransport; - - std::unordered_map> mDataChannels; // by stream ID - std::vector> mUnassignedDataChannels; - std::shared_mutex mDataChannelsMutex; - -#if RTC_ENABLE_MEDIA - std::unordered_map> mTracks; // by mid - std::unordered_map> mTracksBySsrc; // by SSRC - std::vector> mTrackLines; // by SDP order - std::shared_mutex mTracksMutex; -#endif - - Queue> mPendingDataChannels; - -#if RTC_ENABLE_MEDIA - Queue> mPendingTracks; -#endif -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/pollinterrupter.hpp b/godot/thirdparty/libdatachannel/src/impl/pollinterrupter.hpp deleted file mode 100644 index 8ab948b8..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/pollinterrupter.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_POLL_INTERRUPTER_H -#define RTC_IMPL_POLL_INTERRUPTER_H - -#include "common.hpp" -#include "socket.hpp" - -#if RTC_ENABLE_WEBSOCKET - -namespace rtc::impl { - -// Utility class to interrupt poll() -class PollInterrupter final { -public: - PollInterrupter(); - ~PollInterrupter(); - - PollInterrupter(const PollInterrupter &other) = delete; - void operator=(const PollInterrupter &other) = delete; - - void prepare(struct pollfd &pfd); - void process(struct pollfd &pfd); - void interrupt(); - -private: -#ifdef _WIN32 - socket_t mSock; -#else // assume POSIX - int mPipeIn, mPipeOut; -#endif -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/pollservice.hpp b/godot/thirdparty/libdatachannel/src/impl/pollservice.hpp deleted file mode 100644 index d0fd6e78..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/pollservice.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_POLL_SERVICE_H -#define RTC_IMPL_POLL_SERVICE_H - -#include "common.hpp" -#include "internals.hpp" -#include "pollinterrupter.hpp" -#include "socket.hpp" - -#if RTC_ENABLE_WEBSOCKET - -#include -#include -#include -#include -#include -#include - -namespace rtc::impl { - -class PollService { -public: - using clock = std::chrono::steady_clock; - - static PollService &Instance(); - - PollService(const PollService &) = delete; - PollService &operator=(const PollService &) = delete; - PollService(PollService &&) = delete; - PollService &operator=(PollService &&) = delete; - - void start(); - void join(); - - enum class Direction { Both, In, Out }; - enum class Event { None, Error, Timeout, In, Out }; - - struct Params { - Direction direction; - optional timeout; - std::function callback; - }; - - void add(socket_t sock, Params params); - void remove(socket_t sock); - -private: - PollService(); - ~PollService(); - - void prepare(std::vector &pfds, optional &next); - void process(std::vector &pfds); - void runLoop(); - - struct SocketEntry { - Params params; - optional until; - }; - - using SocketMap = std::unordered_map; - unique_ptr mSocks; - unique_ptr mInterrupter; - - std::recursive_mutex mMutex; - std::thread mThread; - bool mStopped; -}; - -std::ostream &operator<<(std::ostream &out, PollService::Direction direction); - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/processor.cpp b/godot/thirdparty/libdatachannel/src/impl/processor.cpp deleted file mode 100644 index f24cc097..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/processor.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "processor.hpp" - -namespace rtc::impl { - -Processor::Processor(size_t limit) : mTasks(limit) {} - -Processor::~Processor() { join(); } - -void Processor::join() { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this]() { return !mPending && mTasks.empty(); }); -} - -void Processor::schedule() { - std::unique_lock lock(mMutex); - if (auto next = mTasks.pop()) { - ThreadPool::Instance().enqueue(std::move(*next)); - } else { - // No more tasks - mPending = false; - mCondition.notify_all(); - } -} - -TearDownProcessor &TearDownProcessor::Instance() { - static TearDownProcessor *instance = new TearDownProcessor; - return *instance; -} - -TearDownProcessor::TearDownProcessor() {} - -TearDownProcessor::~TearDownProcessor() {} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/processor.hpp b/godot/thirdparty/libdatachannel/src/impl/processor.hpp deleted file mode 100644 index d26bda55..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/processor.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_PROCESSOR_H -#define RTC_IMPL_PROCESSOR_H - -#include "common.hpp" -#include "queue.hpp" -#include "threadpool.hpp" - -#include -#include -#include -#include -#include - -namespace rtc::impl { - -// Processed tasks in order by delegating them to the thread pool -class Processor { -public: - Processor(size_t limit = 0); - virtual ~Processor(); - - Processor(const Processor &) = delete; - Processor &operator=(const Processor &) = delete; - Processor(Processor &&) = delete; - Processor &operator=(Processor &&) = delete; - - void join(); - - template void enqueue(F &&f, Args &&...args) noexcept; - -private: - void schedule(); - - Queue> mTasks; - bool mPending = false; // true iff a task is pending in the thread pool - - mutable std::mutex mMutex; - std::condition_variable mCondition; -}; - -class TearDownProcessor final : public Processor { -public: - static TearDownProcessor &Instance(); - -private: - TearDownProcessor(); - ~TearDownProcessor(); -}; - -template void Processor::enqueue(F &&f, Args &&...args) noexcept { - std::unique_lock lock(mMutex); - auto bound = std::bind(std::forward(f), std::forward(args)...); - auto task = [this, bound = std::move(bound)]() mutable { - scope_guard guard(std::bind(&Processor::schedule, this)); // chain the next task - return bound(); - }; - - if (!mPending) { - ThreadPool::Instance().enqueue(std::move(task)); - mPending = true; - } else { - mTasks.push(std::move(task)); - } -} - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/queue.hpp b/godot/thirdparty/libdatachannel/src/impl/queue.hpp deleted file mode 100644 index 6a5ee220..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/queue.hpp +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_QUEUE_H -#define RTC_IMPL_QUEUE_H - -#include "common.hpp" - -#include -#include -#include -#include -#include - -namespace rtc::impl { - -template class Queue { -public: - using amount_function = std::function; - - Queue(size_t limit = 0, amount_function func = nullptr); - ~Queue(); - - void stop(); - bool running() const; - bool empty() const; - bool full() const; - size_t size() const; // elements - size_t amount() const; // amount - void push(T element); - optional pop(); - optional peek(); - optional exchange(T element); - -private: - const size_t mLimit; - size_t mAmount; - std::queue mQueue; - std::condition_variable mPushCondition; - amount_function mAmountFunction; - bool mStopping = false; - - mutable std::mutex mMutex; -}; - -template -Queue::Queue(size_t limit, amount_function func) : mLimit(limit), mAmount(0) { - mAmountFunction = func ? func : [](const T &element) -> size_t { - static_cast(element); - return 1; - }; -} - -template Queue::~Queue() { stop(); } - -template void Queue::stop() { - std::lock_guard lock(mMutex); - mStopping = true; - mPushCondition.notify_all(); -} - -template bool Queue::running() const { - std::lock_guard lock(mMutex); - return !mQueue.empty() || !mStopping; -} - -template bool Queue::empty() const { - std::lock_guard lock(mMutex); - return mQueue.empty(); -} - -template bool Queue::full() const { - std::lock_guard lock(mMutex); - return mQueue.size() >= mLimit; -} - -template size_t Queue::size() const { - std::lock_guard lock(mMutex); - return mQueue.size(); -} - -template size_t Queue::amount() const { - std::lock_guard lock(mMutex); - return mAmount; -} - -template void Queue::push(T element) { - std::unique_lock lock(mMutex); - mPushCondition.wait(lock, [this]() { return !mLimit || mQueue.size() < mLimit || mStopping; }); - if (mStopping) - return; - - mAmount += mAmountFunction(element); - mQueue.emplace(std::move(element)); -} - -template optional Queue::pop() { - std::unique_lock lock(mMutex); - if (mQueue.empty()) - return nullopt; - - mAmount -= mAmountFunction(mQueue.front()); - optional element{std::move(mQueue.front())}; - mQueue.pop(); - return element; -} - -template optional Queue::peek() { - std::unique_lock lock(mMutex); - return !mQueue.empty() ? std::make_optional(mQueue.front()) : nullopt; -} - -template optional Queue::exchange(T element) { - std::unique_lock lock(mMutex); - if (mQueue.empty()) - return nullopt; - - std::swap(mQueue.front(), element); - return std::make_optional(std::move(element)); -} - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/sctptransport.cpp b/godot/thirdparty/libdatachannel/src/impl/sctptransport.cpp deleted file mode 100644 index 424218f1..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/sctptransport.cpp +++ /dev/null @@ -1,1000 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "sctptransport.hpp" -#include "dtlstransport.hpp" -#include "internals.hpp" -#include "logcounter.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// RFC 8831: SCTP MUST support performing Path MTU discovery without relying on ICMP or ICMPv6 as -// specified in [RFC4821] by using probing messages specified in [RFC4820]. -// See https://www.rfc-editor.org/rfc/rfc8831.html#section-5 -// -// However, usrsctp does not implement Path MTU discovery, so we need to disable it for now. -// See https://github.com/sctplab/usrsctp/issues/205 -#define USE_PMTUD 0 - -// TODO: When Path MTU discovery is supported, it needs to be enabled with libjuice as ICE backend -// on all platforms except Mac OS where the Don't Fragment (DF) flag can't be set: -/* -#if !USE_NICE -#ifndef __APPLE__ -// libjuice enables Linux path MTU discovery or sets the DF flag -#define USE_PMTUD 1 -#else -// Setting the DF flag is not available on Mac OS -#define USE_PMTUD 0 -#endif -#else // USE_NICE == 1 -#define USE_PMTUD 0 -#endif -*/ - -using namespace std::chrono_literals; -using namespace std::chrono; - -namespace { - -template RTC_WRAPPED(uint16_t) to_uint16(T i) { - if (i >= 0 && static_cast::type>(i) <= - std::numeric_limits::max()) - return static_cast(i); - else - RTC_THROW RTC_INVALID_ARGUMENT("Integer out of range"); -} - -template RTC_WRAPPED(uint32_t) to_uint32(T i) { - if (i >= 0 && static_cast::type>(i) <= - std::numeric_limits::max()) - return static_cast(i); - else - RTC_THROW RTC_INVALID_ARGUMENT("Integer out of range"); -} - -} // namespace - -namespace rtc::impl { - -static LogCounter COUNTER_UNKNOWN_PPID(plog::warning, - "Number of SCTP packets received with an unknown PPID"); - -class SctpTransport::InstancesSet { -public: - void insert(SctpTransport *instance) { - std::unique_lock lock(mMutex); - mSet.insert(instance); - } - - void erase(SctpTransport *instance) { - std::unique_lock lock(mMutex); - mSet.erase(instance); - } - - using shared_lock = std::shared_lock; - optional lock(SctpTransport *instance) noexcept { - shared_lock lock(mMutex); - return mSet.find(instance) != mSet.end() ? std::make_optional(std::move(lock)) : nullopt; - } - -private: - std::unordered_set mSet; - std::shared_mutex mMutex; -}; - -SctpTransport::InstancesSet *SctpTransport::Instances = new InstancesSet; - -void SctpTransport::Init() { - usrsctp_init(0, SctpTransport::WriteCallback, SctpTransport::DebugCallback); - usrsctp_enable_crc32c_offload(); // We'll compute CRC32 only for outgoing packets - usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758) - usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification -#ifdef SCTP_DEBUG - usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); -#endif -} - -RTC_WRAPPED(void) SctpTransport::SetSettings(const SctpSettings &s) { - RTC_BEGIN; - // The send and receive window size of usrsctp is 256KiB, which is too small for realistic RTTs, - // therefore we increase it to 1MiB by default for better performance. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685 - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_recvspace, to_uint32(s.recvBufferSize.value_or(1024 * 1024))); - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_sendspace, to_uint32(s.sendBufferSize.value_or(1024 * 1024))); - - // Increase maximum chunks number on queue to 10K by default - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_max_chunks_on_queue, to_uint32(s.maxChunksOnQueue.value_or(10 * 1024))); - - // Increase initial congestion window size to 10 MTUs (RFC 6928) by default - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_initial_cwnd, to_uint32(s.initialCongestionWindow.value_or(10))); - - // Set max burst to 10 MTUs by default (max burst is initially 0, meaning disabled) - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_max_burst_default, to_uint32(s.maxBurst.value_or(10))); - - // Use standard SCTP congestion control (RFC 4960) by default - // See https://github.com/paullouisageneau/libdatachannel/issues/354 - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_default_cc_module, to_uint32(s.congestionControlModule.value_or(0))); - - // Reduce SACK delay to 20ms by default (the recommended default value from RFC 4960 is 200ms) - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_delayed_sack_time_default, - to_uint32(s.delayedSackTime.value_or(20ms).count())); - - // RTO settings - // RFC 2988 recommends a 1s min RTO, which is very high, but TCP on Linux has a 200ms min RTO - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_rto_min_default, - to_uint32(s.minRetransmitTimeout.value_or(200ms).count())); - // Set only 10s as max RTO instead of 60s for shorter connection timeout - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_rto_max_default, - to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_init_rto_max_default, - to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); - // Still set 1s as initial RTO - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_rto_initial_default, - to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count())); - - // RTX settings - // 5 retransmissions instead of 8 to shorten the backoff for shorter connection timeout - RTC_UNWRAP_RETHROW_DECL(auto, maxRtx, to_uint32(s.maxRetransmitAttempts.value_or(5))); - usrsctp_sysctl_set_sctp_init_rtx_max_default(maxRtx); - usrsctp_sysctl_set_sctp_assoc_rtx_max_default(maxRtx); - usrsctp_sysctl_set_sctp_path_rtx_max_default(maxRtx); // single path - - // Heartbeat interval - RTC_UNWRAP_RETHROW_ARG(usrsctp_sysctl_set_sctp_heartbeat_interval_default, - to_uint32(s.heartbeatInterval.value_or(10000ms).count())); - RTC_RET; -} - -void SctpTransport::Cleanup() { - while (usrsctp_finish()) - std::this_thread::sleep_for(100ms); -} - -SctpTransport::SctpTransport(shared_ptr lower, Ports ports, - message_callback recvCallback, amount_callback bufferedAmountCallback, - state_callback stateChangeCallback) - : Transport(lower, std::move(stateChangeCallback)), mPorts(std::move(ports)), - mSendQueue(0, message_size_func), mBufferedAmountCallback(std::move(bufferedAmountCallback)) { - onRecv(std::move(recvCallback)); -} - -RTC_WRAPPED(void) SctpTransport::construct(const Configuration &config) { - RTC_BEGIN; - PLOG_DEBUG << "Initializing SCTP transport"; - - mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, nullptr, nullptr, 0, nullptr); - if (!mSock) - RTC_THROW RTC_RUNTIME_ERROR("Could not create SCTP socket, errno=" + std::to_string(errno)); - - usrsctp_set_upcall(mSock, &SctpTransport::UpcallCallback, this); - - if (usrsctp_set_non_blocking(mSock, 1)) - RTC_THROW RTC_RUNTIME_ERROR("Unable to set non-blocking mode, errno=" + std::to_string(errno)); - - // SCTP must stop sending after the lower layer is shut down, so disable linger - struct linger sol = {}; - sol.l_onoff = 1; - sol.l_linger = 0; - if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_LINGER, &sol, sizeof(sol))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SO_LINGER, errno=" + - std::to_string(errno)); - - struct sctp_assoc_value av = {}; - av.assoc_id = SCTP_ALL_ASSOC; - av.assoc_value = 1; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, &av, sizeof(av))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_ENABLE_STREAM_RESET, errno=" + - std::to_string(errno)); - int on = 1; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on))) - RTC_THROW RTC_RUNTIME_ERROR("Could set socket option SCTP_RECVRCVINFO, errno=" + - std::to_string(errno)); - - struct sctp_event se = {}; - se.se_assoc_id = SCTP_ALL_ASSOC; - se.se_on = 1; - se.se_type = SCTP_ASSOC_CHANGE; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se))) - RTC_THROW RTC_RUNTIME_ERROR("Could not subscribe to event SCTP_ASSOC_CHANGE, errno=" + - std::to_string(errno)); - se.se_type = SCTP_SENDER_DRY_EVENT; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se))) - RTC_THROW RTC_RUNTIME_ERROR("Could not subscribe to event SCTP_SENDER_DRY_EVENT, errno=" + - std::to_string(errno)); - se.se_type = SCTP_STREAM_RESET_EVENT; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se))) - RTC_THROW RTC_RUNTIME_ERROR("Could not subscribe to event SCTP_STREAM_RESET_EVENT, errno=" + - std::to_string(errno)); - - // RFC 8831 6.6. Transferring User Data on a Data Channel - // The sender SHOULD disable the Nagle algorithm (see [RFC1122) to minimize the latency - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.6 - int nodelay = 1; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_NODELAY, errno=" + - std::to_string(errno)); - - struct sctp_paddrparams spp = {}; - // Enable SCTP heartbeats - spp.spp_flags = SPP_HB_ENABLE; - - // RFC 8261 5. DTLS considerations: - // If path MTU discovery is performed by the SCTP layer and IPv4 is used as the network-layer - // protocol, the DTLS implementation SHOULD allow the DTLS user to enforce that the - // corresponding IPv4 packet is sent with the Don't Fragment (DF) bit set. If controlling the DF - // bit is not possible (for example, due to implementation restrictions), a safe value for the - // path MTU has to be used by the SCTP stack. It is RECOMMENDED that the safe value not exceed - // 1200 bytes. - // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5 -#if USE_PMTUD - if (!config.mtu.has_value()) { -#else - if (false) { -#endif - // Enable SCTP path MTU discovery - spp.spp_flags |= SPP_PMTUD_ENABLE; - PLOG_VERBOSE << "Path MTU discovery enabled"; - - } else { - // Fall back to a safe MTU value. - spp.spp_flags |= SPP_PMTUD_DISABLE; - // The MTU value provided specifies the space available for chunks in the - // packet, so we also subtract the SCTP header size. - size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 48 - 8 - 40; // SCTP/DTLS/UDP/IPv6 - RTC_UNWRAP_RETHROW_VAR(spp.spp_pathmtu, to_uint32(pmtu)); - PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu; - } - - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &spp, sizeof(spp))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_PEER_ADDR_PARAMS, errno=" + - std::to_string(errno)); - - // RFC 8831 6.2. SCTP Association Management - // The number of streams negotiated during SCTP association setup SHOULD be 65535, which is the - // maximum number of streams that can be negotiated during the association setup. - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.2 - // However, usrsctp allocates tables to hold the stream states. For 65535 streams, it results in - // the waste of a few MBs for each association. Therefore, we use a lower limit to save memory. - // See https://github.com/sctplab/usrsctp/issues/121 - struct sctp_initmsg sinit = {}; - sinit.sinit_num_ostreams = MAX_SCTP_STREAMS_COUNT; - sinit.sinit_max_instreams = MAX_SCTP_STREAMS_COUNT; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_INITMSG, &sinit, sizeof(sinit))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set socket option SCTP_INITMSG, errno=" + - std::to_string(errno)); - - // Prevent fragmented interleave of messages (i.e. level 0), see RFC 6458 section 8.1.20. - // Unless the user has set the fragmentation interleave level to 0, notifications - // may also be interleaved with partially delivered messages. - int level = 0; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &level, sizeof(level))) - RTC_THROW RTC_RUNTIME_ERROR("Could not disable SCTP fragmented interleave, errno=" + - std::to_string(errno)); - - int rcvBuf = 0; - socklen_t rcvBufLen = sizeof(rcvBuf); - if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen)) - RTC_THROW RTC_RUNTIME_ERROR("Could not get SCTP recv buffer size, errno=" + - std::to_string(errno)); - int sndBuf = 0; - socklen_t sndBufLen = sizeof(sndBuf); - if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, &sndBufLen)) - RTC_THROW RTC_RUNTIME_ERROR("Could not get SCTP send buffer size, errno=" + - std::to_string(errno)); - - // Ensure the buffer is also large enough to accomodate the largest messages - const size_t maxMessageSize = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE); - const int minBuf = int(std::min(maxMessageSize, size_t(std::numeric_limits::max()))); - rcvBuf = std::max(rcvBuf, minBuf); - sndBuf = std::max(sndBuf, minBuf); - - if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, sizeof(rcvBuf))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set SCTP recv buffer size, errno=" + - std::to_string(errno)); - - if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, sizeof(sndBuf))) - RTC_THROW RTC_RUNTIME_ERROR("Could not set SCTP send buffer size, errno=" + - std::to_string(errno)); - - usrsctp_register_address(this); - Instances->insert(this); - RTC_RET; -} - -SctpTransport::~SctpTransport() { - PLOG_DEBUG << "Destroying SCTP transport"; - - mProcessor.join(); // if we are here, the processor must be empty - - // Before unregistering incoming() from the lower layer, we need to make sure the thread from - // lower layers is not blocked in incoming() by the WrittenOnce condition. - mWrittenOnce = true; - mWrittenCondition.notify_all(); - - unregisterIncoming(); - - usrsctp_close(mSock); - - usrsctp_deregister_address(this); - Instances->erase(this); -} - -void SctpTransport::onBufferedAmount(amount_callback callback) { - mBufferedAmountCallback = std::move(callback); -} - -RTC_WRAPPED(void) SctpTransport::start() { - registerIncoming(); - return connect(); -} - -void SctpTransport::stop() { close(); } - -struct sockaddr_conn SctpTransport::getSockAddrConn(uint16_t port) { - struct sockaddr_conn sconn = {}; - sconn.sconn_family = AF_CONN; - sconn.sconn_port = htons(port); - sconn.sconn_addr = this; -#ifdef HAVE_SCONN_LEN - sconn.sconn_len = sizeof(sconn); -#endif - return sconn; -} - -RTC_WRAPPED(void) SctpTransport::connect() { - PLOG_DEBUG << "SCTP connecting (local port=" << mPorts.local - << ", remote port=" << mPorts.remote << ")"; - changeState(State::Connecting); - - auto local = getSockAddrConn(mPorts.local); - if (usrsctp_bind(mSock, reinterpret_cast(&local), sizeof(local))) - RTC_THROW RTC_RUNTIME_ERROR("Could not bind usrsctp socket, errno=" + std::to_string(errno)); - - // According to RFC 8841, both endpoints must initiate the SCTP association, in a - // simultaneous-open manner, irrelevent to the SDP setup role. - // See https://www.rfc-editor.org/rfc/rfc8841.html#section-9.3 - auto remote = getSockAddrConn(mPorts.remote); - int ret = usrsctp_connect(mSock, reinterpret_cast(&remote), sizeof(remote)); - if (ret && errno != EINPROGRESS) - RTC_THROW RTC_RUNTIME_ERROR("Connection attempt failed, errno=" + std::to_string(errno)); - RTC_RET; -} - -RTC_WRAPPED(bool) SctpTransport::send(message_ptr message) { - RTC_BEGIN; - std::lock_guard lock(mSendMutex); - if (state() != State::Connected) - return false; - - if (!message) - return trySendQueue(); - - PLOG_VERBOSE << "Send size=" << message->size(); - - // Flush the queue, and if nothing is pending, try to send directly - RTC_UNWRAP_RETHROW_DECL(bool, res1, trySendQueue()); - if (res1) { - RTC_UNWRAP_RETHROW_DECL(bool, res2, trySendMessage(message)); - if (res2) { - return true; - } - } - - mSendQueue.push(message); - RTC_UNWRAP_RETHROW_DECL(uint16_t, tmp, to_uint16(message->stream)); - updateBufferedAmount(tmp, ptrdiff_t(message_size_func(message))); - return false; -} - -bool SctpTransport::flush() { - RTC_TRY { - std::lock_guard lock(mSendMutex); - if (state() != State::Connected) - return false; - - RTC_UNWRAP_CATCH(trySendQueue()); - return true; - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "SCTP flush: " << e.RTC_WHAT(); - return false; - } -} - -void SctpTransport::closeStream(unsigned int stream) { - std::lock_guard lock(mSendMutex); - - // RFC 8831 6.7. Closing a Data Channel - // Closing of a data channel MUST be signaled by resetting the corresponding outgoing streams - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.7 - RTC_TRY { - RTC_UNWRAP_CATCH_DECL(uint16_t, sid, to_uint16(stream)); - mSendQueue.push(make_message(0, Message::Reset, sid)); - } RTC_CATCH(...) { - } - - // This method must not call the buffered callback synchronously - mProcessor.enqueue(&SctpTransport::flush, shared_from_this()); -} - -void SctpTransport::close() { - mSendQueue.stop(); - if (state() == State::Connected) { - mProcessor.enqueue(&SctpTransport::flush, shared_from_this()); - } else if (state() == State::Connecting) { - PLOG_DEBUG << "SCTP early shutdown"; - if (usrsctp_shutdown(mSock, SHUT_RDWR)) { - if (errno == ENOTCONN) { - PLOG_VERBOSE << "SCTP already shut down"; - } else { - PLOG_WARNING << "SCTP shutdown failed, errno=" << errno; - } - } - changeState(State::Failed); - mWrittenCondition.notify_all(); - } -} - -unsigned int SctpTransport::maxStream() const { - unsigned int streamsCount = mNegotiatedStreamsCount.value_or(MAX_SCTP_STREAMS_COUNT); - return streamsCount > 0 ? streamsCount - 1 : 0; -} - -void SctpTransport::incoming(message_ptr message) { - // There could be a race condition here where we receive the remote INIT before the local one is - // sent, which would result in the connection being aborted. Therefore, we need to wait for data - // to be sent on our side (i.e. the local INIT) before proceeding. - if (!mWrittenOnce) { // test the atomic boolean is not set first to prevent a lock contention - std::unique_lock lock(mWriteMutex); - mWrittenCondition.wait(lock, [&]() { return mWrittenOnce || state() == State::Failed; }); - } - - if (state() == State::Failed) - return; - - if (!message) { - PLOG_INFO << "SCTP disconnected"; - changeState(State::Disconnected); - recv(nullptr); - return; - } - - PLOG_VERBOSE << "Incoming size=" << message->size(); - - usrsctp_conninput(this, message->data(), message->size(), 0); -} - -RTC_WRAPPED(bool) SctpTransport::outgoing(message_ptr message) { - // Set recommended medium-priority DSCP value - // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5 - message->dscp = 10; // AF11: Assured Forwarding class 1, low drop probability - return Transport::outgoing(std::move(message)); -} - -void SctpTransport::doRecv() { - std::lock_guard lock(mRecvMutex); - --mPendingRecvCount; - RTC_TRY { - while (state() != State::Disconnected && state() != State::Failed) { - const size_t bufferSize = 65536; - byte buffer[bufferSize]; - socklen_t fromlen = 0; - struct sctp_rcvinfo info = {}; - socklen_t infolen = sizeof(info); - unsigned int infotype = 0; - int flags = 0; - ssize_t len = usrsctp_recvv(mSock, buffer, bufferSize, nullptr, &fromlen, &info, - &infolen, &infotype, &flags); - if (len < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ECONNRESET) - break; - else - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("SCTP recv failed, errno=" + std::to_string(errno))); - } else if (len == 0) { - break; - } - - PLOG_VERBOSE << "SCTP recv, len=" << len; - - // SCTP_FRAGMENT_INTERLEAVE does not seem to work as expected for messages > 64KB, - // therefore partial notifications and messages need to be handled separately. - if (flags & MSG_NOTIFICATION) { - // SCTP event notification - mPartialNotification.insert(mPartialNotification.end(), buffer, buffer + len); - if (flags & MSG_EOR) { - // Notification is complete, process it - auto notification = - reinterpret_cast(mPartialNotification.data()); - processNotification(notification, mPartialNotification.size()); - mPartialNotification.clear(); - } - } else { - // SCTP message - mPartialMessage.insert(mPartialMessage.end(), buffer, buffer + len); - if (flags & MSG_EOR) { - // Message is complete, process it - if (infotype != SCTP_RECVV_RCVINFO) - RTC_THROW_WITHIN(RTC_RUNTIME_ERROR("Missing SCTP recv info")); - - processData(std::move(mPartialMessage), info.rcv_sid, - PayloadId(ntohl(info.rcv_ppid))); - mPartialMessage.clear(); - } - } - } - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void SctpTransport::doFlush() { - std::lock_guard lock(mSendMutex); - --mPendingFlushCount; - RTC_TRY { - RTC_UNWRAP_CATCH(trySendQueue()); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void SctpTransport::enqueueRecv() { - if (mPendingRecvCount > 0) - return; - - if (auto shared_this = weak_from_this().lock()) { - // This is called from the upcall callback, we must not release the shared ptr here - ++mPendingRecvCount; - mProcessor.enqueue(&SctpTransport::doRecv, std::move(shared_this)); - } -} - -void SctpTransport::enqueueFlush() { - if (mPendingFlushCount > 0) - return; - - if (auto shared_this = weak_from_this().lock()) { - // This is called from the upcall callback, we must not release the shared ptr here - ++mPendingFlushCount; - mProcessor.enqueue(&SctpTransport::doFlush, std::move(shared_this)); - } -} - -RTC_WRAPPED(bool) SctpTransport::trySendQueue() { - RTC_BEGIN; - // Requires mSendMutex to be locked - while (auto next = mSendQueue.peek()) { - message_ptr message = std::move(*next); - RTC_UNWRAP_RETHROW_DECL(bool, res, trySendMessage(message)); - if (!res) - return false; - - mSendQueue.pop(); - RTC_UNWRAP_RETHROW_DECL(uint16_t, tmp, to_uint16(message->stream)); - updateBufferedAmount(tmp, -ptrdiff_t(message_size_func(message))); - } - - if (!mSendQueue.running() && !std::exchange(mSendShutdown, true)) { - PLOG_DEBUG << "SCTP shutdown"; - if (usrsctp_shutdown(mSock, SHUT_WR)) { - if (errno == ENOTCONN) { - PLOG_VERBOSE << "SCTP already shut down"; - } else { - PLOG_WARNING << "SCTP shutdown failed, errno=" << errno; - changeState(State::Disconnected); - recv(nullptr); - } - } - } - - return true; -} - -RTC_WRAPPED(bool) SctpTransport::trySendMessage(message_ptr message) { - RTC_BEGIN; - // Requires mSendMutex to be locked - if (state() != State::Connected) - return false; - - uint32_t ppid; - switch (message->type) { - case Message::String: - ppid = !message->empty() ? PPID_STRING : PPID_STRING_EMPTY; - break; - case Message::Binary: - ppid = !message->empty() ? PPID_BINARY : PPID_BINARY_EMPTY; - break; - case Message::Control: - ppid = PPID_CONTROL; - break; - case Message::Reset: - sendReset(uint16_t(message->stream)); - return true; - default: - // Ignore - return true; - } - - PLOG_VERBOSE << "SCTP try send size=" << message->size(); - - // TODO: Implement SCTP ndata specification draft when supported everywhere - // See https://datatracker.ietf.org/doc/html/draft-ietf-tsvwg-sctp-ndata-08 - - const Reliability reliability = message->reliability ? *message->reliability : Reliability(); - - struct sctp_sendv_spa spa = {}; - - // set sndinfo - spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID; - spa.sendv_sndinfo.snd_sid = uint16_t(message->stream); - spa.sendv_sndinfo.snd_ppid = htonl(ppid); - spa.sendv_sndinfo.snd_flags |= SCTP_EOR; // implicit here - - // set prinfo - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - if (reliability.unordered) - spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED; - - switch (reliability.type) { - case Reliability::Type::Rexmit: - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; - RTC_UNWRAP_RETHROW_VAR(spa.sendv_prinfo.pr_value, to_uint32(std::get(reliability.rexmit))); - break; - case Reliability::Type::Timed: - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL; - RTC_UNWRAP_RETHROW_VAR(spa.sendv_prinfo.pr_value, to_uint32(std::get(reliability.rexmit).count())); - break; - default: - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE; - break; - } - - ssize_t ret; - if (!message->empty()) { - ret = usrsctp_sendv(mSock, message->data(), message->size(), nullptr, 0, &spa, sizeof(spa), - SCTP_SENDV_SPA, 0); - } else { - const char zero = 0; - ret = usrsctp_sendv(mSock, &zero, 1, nullptr, 0, &spa, sizeof(spa), SCTP_SENDV_SPA, 0); - } - - if (ret < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN) { - PLOG_VERBOSE << "SCTP sending not possible"; - return false; - } - - PLOG_ERROR << "SCTP sending failed, errno=" << errno; - RTC_THROW RTC_RUNTIME_ERROR("Sending failed, errno=" + std::to_string(errno)); - } - - PLOG_VERBOSE << "SCTP sent size=" << message->size(); - if (message->type == Message::Binary || message->type == Message::String) - mBytesSent += message->size(); - return true; -} - -void SctpTransport::updateBufferedAmount(uint16_t streamId, ptrdiff_t delta) { - // Requires mSendMutex to be locked - - if (delta == 0) - return; - - auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first; - size_t amount = size_t(std::max(ptrdiff_t(it->second) + delta, ptrdiff_t(0))); - if (amount == 0) - mBufferedAmount.erase(it); - else - it->second = amount; - - // Synchronously call the buffered amount callback - triggerBufferedAmount(streamId, amount); -} - -void SctpTransport::triggerBufferedAmount(uint16_t streamId, size_t amount) { - RTC_TRY { - mBufferedAmountCallback(streamId, amount); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << "SCTP buffered amount callback: " << e.RTC_WHAT(); - } -} - -void SctpTransport::sendReset(uint16_t streamId) { - // Requires mSendMutex to be locked - if (state() != State::Connected) - return; - - PLOG_DEBUG << "SCTP resetting stream " << streamId; - - using srs_t = struct sctp_reset_streams; - const size_t len = sizeof(srs_t) + sizeof(uint16_t); - byte buffer[len] = {}; - srs_t &srs = *reinterpret_cast(buffer); - srs.srs_flags = SCTP_STREAM_RESET_OUTGOING; - srs.srs_number_streams = 1; - srs.srs_stream_list[0] = streamId; - - mWritten = false; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_RESET_STREAMS, &srs, len) == 0) { - std::unique_lock lock(mWriteMutex); // locking before setsockopt might deadlock usrsctp... - mWrittenCondition.wait_for(lock, 1000ms, - [&]() { return mWritten || state() != State::Connected; }); - } else if (errno == EINVAL) { - PLOG_DEBUG << "SCTP stream " << streamId << " already reset"; - } else { - PLOG_WARNING << "SCTP reset stream " << streamId << " failed, errno=" << errno; - } -} - -void SctpTransport::handleUpcall() noexcept { - RTC_TRY { - PLOG_VERBOSE << "Handle upcall"; - - int events = usrsctp_get_events(mSock); - - if (events & SCTP_EVENT_READ) - enqueueRecv(); - - if (events & SCTP_EVENT_WRITE) - enqueueFlush(); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << "SCTP upcall: " << e.RTC_WHAT(); - } -} - -int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, - uint8_t /*set_df*/) noexcept { - RTC_TRY { - std::unique_lock lock(mWriteMutex); - PLOG_VERBOSE << "Handle write, len=" << len; - - RTC_UNWRAP_CATCH_DECL(bool, res, outgoing(make_message(data, data + len))); - if (!res) - return -1; - - mWritten = true; - mWrittenOnce = true; - mWrittenCondition.notify_all(); - - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_ERROR << "SCTP write: " << e.RTC_WHAT(); - return -1; - } - return 0; // success -} - -void SctpTransport::processData(binary &&data, uint16_t sid, PayloadId ppid) { - PLOG_VERBOSE << "Process data, size=" << data.size(); - - // RFC 8831: The usage of the PPIDs "WebRTC String Partial" and "WebRTC Binary Partial" is - // deprecated. They were used for a PPID-based fragmentation and reassembly of user messages - // belonging to reliable and ordered data channels. - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.6 - // We handle those PPIDs at reception for compatibility reasons but shall never send them. - switch (ppid) { - case PPID_CONTROL: - recv(make_message(std::move(data), Message::Control, sid)); - break; - - case PPID_STRING_PARTIAL: // deprecated - mPartialStringData.insert(mPartialStringData.end(), data.begin(), data.end()); - break; - - case PPID_STRING: - if (mPartialStringData.empty()) { - mBytesReceived += data.size(); - recv(make_message(std::move(data), Message::String, sid)); - } else { - mPartialStringData.insert(mPartialStringData.end(), data.begin(), data.end()); - mBytesReceived += mPartialStringData.size(); - recv(make_message(std::move(mPartialStringData), Message::String, sid)); - mPartialStringData.clear(); - } - break; - - case PPID_STRING_EMPTY: - recv(make_message(std::move(mPartialStringData), Message::String, sid)); - mPartialStringData.clear(); - break; - - case PPID_BINARY_PARTIAL: // deprecated - mPartialBinaryData.insert(mPartialBinaryData.end(), data.begin(), data.end()); - break; - - case PPID_BINARY: - if (mPartialBinaryData.empty()) { - mBytesReceived += data.size(); - recv(make_message(std::move(data), Message::Binary, sid)); - } else { - mPartialBinaryData.insert(mPartialBinaryData.end(), data.begin(), data.end()); - mBytesReceived += mPartialBinaryData.size(); - recv(make_message(std::move(mPartialBinaryData), Message::Binary, sid)); - mPartialBinaryData.clear(); - } - break; - - case PPID_BINARY_EMPTY: - recv(make_message(std::move(mPartialBinaryData), Message::Binary, sid)); - mPartialBinaryData.clear(); - break; - - default: - // Unknown - COUNTER_UNKNOWN_PPID++; - PLOG_VERBOSE << "Unknown PPID: " << uint32_t(ppid); - return; - } -} - -void SctpTransport::processNotification(const union sctp_notification *notify, size_t len) { - if (len != size_t(notify->sn_header.sn_length)) { - PLOG_WARNING << "Unexpected notification length, expected=" << notify->sn_header.sn_length - << ", actual=" << len; - return; - } - - auto type = notify->sn_header.sn_type; - PLOG_VERBOSE << "Processing notification, type=" << type; - - switch (type) { - case SCTP_ASSOC_CHANGE: { - PLOG_VERBOSE << "SCTP association change event"; - const struct sctp_assoc_change &sac = notify->sn_assoc_change; - if (sac.sac_state == SCTP_COMM_UP) { - PLOG_DEBUG << "SCTP negotiated streams: incoming=" << sac.sac_inbound_streams - << ", outgoing=" << sac.sac_outbound_streams; - mNegotiatedStreamsCount.emplace( - std::min(sac.sac_inbound_streams, sac.sac_outbound_streams)); - - PLOG_INFO << "SCTP connected"; - changeState(State::Connected); - } else { - if (state() == State::Connected) { - PLOG_INFO << "SCTP disconnected"; - changeState(State::Disconnected); - recv(nullptr); - } else { - PLOG_ERROR << "SCTP connection failed"; - changeState(State::Failed); - } - mWrittenCondition.notify_all(); - } - break; - } - - case SCTP_SENDER_DRY_EVENT: { - PLOG_VERBOSE << "SCTP sender dry event"; - // It should not be necessary since the send callback should have been called already, - // but to be sure, let's try to send now. - flush(); - break; - } - - case SCTP_STREAM_RESET_EVENT: { - const struct sctp_stream_reset_event &reset_event = notify->sn_strreset_event; - const int count = (reset_event.strreset_length - sizeof(reset_event)) / sizeof(uint16_t); - const uint16_t flags = reset_event.strreset_flags; - - IF_PLOG(plog::verbose) { - std::ostringstream desc; - desc << "flags="; - if (flags & SCTP_STREAM_RESET_OUTGOING_SSN && flags & SCTP_STREAM_RESET_INCOMING_SSN) - desc << "outgoing|incoming"; - else if (flags & SCTP_STREAM_RESET_OUTGOING_SSN) - desc << "outgoing"; - else if (flags & SCTP_STREAM_RESET_INCOMING_SSN) - desc << "incoming"; - else - desc << "0"; - - desc << ", streams=["; - for (int i = 0; i < count; ++i) { - uint16_t streamId = reset_event.strreset_stream_list[i]; - desc << (i != 0 ? "," : "") << streamId; - } - desc << "]"; - - PLOG_VERBOSE << "SCTP reset event, " << desc.str(); - } - - // RFC 8831 6.7. Closing a Data Channel - // If one side decides to close the data channel, it resets the corresponding outgoing - // stream. When the peer sees that an incoming stream was reset, it also resets its - // corresponding outgoing stream. - // See https://www.rfc-editor.org/rfc/rfc8831.html#section-6.7 - if (flags & SCTP_STREAM_RESET_INCOMING_SSN) { - for (int i = 0; i < count; ++i) { - uint16_t streamId = reset_event.strreset_stream_list[i]; - recv(make_message(0, Message::Reset, streamId)); - } - } - break; - } - - default: - // Ignore - break; - } -} - -void SctpTransport::clearStats() { - mBytesReceived = 0; - mBytesSent = 0; -} - -size_t SctpTransport::bytesSent() { return mBytesSent; } - -size_t SctpTransport::bytesReceived() { return mBytesReceived; } - -optional SctpTransport::rtt() { - if (state() != State::Connected) - return nullopt; - - struct sctp_status status = {}; - socklen_t len = sizeof(status); - if (usrsctp_getsockopt(mSock, IPPROTO_SCTP, SCTP_STATUS, &status, &len)) - return nullopt; - - return milliseconds(status.sstat_primary.spinfo_srtt); -} - -void SctpTransport::UpcallCallback(struct socket *, void *arg, int /* flags */) { - auto *transport = static_cast(arg); - - if (auto locked = Instances->lock(transport)) - transport->handleUpcall(); -} - -int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) { - auto *transport = static_cast(ptr); - - // Set the CRC32 ourselves as we have enabled CRC32 offloading - if (len >= 12) { - uint32_t *checksum = reinterpret_cast(data) + 2; - *checksum = 0; - *checksum = usrsctp_crc32c(data, len); - } - - // Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket - // https://github.com/sctplab/usrsctp/issues/405 - if (auto locked = Instances->lock(transport)) - return transport->handleWrite(static_cast(data), len, tos, set_df); - else - return -1; -} - -void SctpTransport::DebugCallback(const char *format, ...) { - const size_t bufferSize = 1024; - char buffer[bufferSize]; - va_list va; - va_start(va, format); - int len = std::vsnprintf(buffer, bufferSize, format, va); - va_end(va); - if (len <= 0) - return; - - len = std::min(len, int(bufferSize - 1)); - buffer[len - 1] = '\0'; // remove newline - - PLOG_VERBOSE << "usrsctp: " << buffer; // usrsctp debug as verbose -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/sctptransport.hpp b/godot/thirdparty/libdatachannel/src/impl/sctptransport.hpp deleted file mode 100644 index 3d65487a..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/sctptransport.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2019-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_SCTP_TRANSPORT_H -#define RTC_IMPL_SCTP_TRANSPORT_H - -#include "common.hpp" -#include "configuration.hpp" -#include "global.hpp" -#include "processor.hpp" -#include "queue.hpp" -#include "transport.hpp" - -#include -#include -#include -#include - -#include "usrsctp.h" - -namespace rtc::impl { - -class SctpTransport final : public Transport, public std::enable_shared_from_this { -public: - static void Init(); - static RTC_WRAPPED(void) SetSettings(const SctpSettings &s); - static void Cleanup(); - - using amount_callback = std::function; - - struct Ports { - uint16_t local = DEFAULT_SCTP_PORT; - uint16_t remote = DEFAULT_SCTP_PORT; - }; - - SctpTransport(shared_ptr lower, Ports ports, - message_callback recvCallback, amount_callback bufferedAmountCallback, - state_callback stateChangeCallback); - ~SctpTransport(); - RTC_WRAPPED(void) construct(const Configuration &config); - - void onBufferedAmount(amount_callback callback); - - RTC_WRAPPED(void) start() override; - void stop() override; - RTC_WRAPPED(bool) send(message_ptr message) override; // false if buffered - bool flush(); - void closeStream(unsigned int stream); - void close(); - - unsigned int maxStream() const; - - // Stats - void clearStats(); - size_t bytesSent(); - size_t bytesReceived(); - optional rtt(); - -private: - // Order seems wrong but these are the actual values - // See https://datatracker.ietf.org/doc/html/draft-ietf-rtcweb-data-channel-13#section-8 - enum PayloadId : uint32_t { - PPID_CONTROL = 50, - PPID_STRING = 51, - PPID_BINARY_PARTIAL = 52, - PPID_BINARY = 53, - PPID_STRING_PARTIAL = 54, - PPID_STRING_EMPTY = 56, - PPID_BINARY_EMPTY = 57 - }; - - struct sockaddr_conn getSockAddrConn(uint16_t port); - - RTC_WRAPPED(void) connect(); - void shutdown(); - void incoming(message_ptr message) override; - RTC_WRAPPED(bool) outgoing(message_ptr message) override; - - void doRecv(); - void doFlush(); - void enqueueRecv(); - void enqueueFlush(); - RTC_WRAPPED(bool) trySendQueue(); - RTC_WRAPPED(bool) trySendMessage(message_ptr message); - void updateBufferedAmount(uint16_t streamId, ptrdiff_t delta); - void triggerBufferedAmount(uint16_t streamId, size_t amount); - void sendReset(uint16_t streamId); - - void handleUpcall() noexcept; - int handleWrite(byte *data, size_t len, uint8_t tos, uint8_t set_df) noexcept; - - void processData(binary &&data, uint16_t streamId, PayloadId ppid); - void processNotification(const union sctp_notification *notify, size_t len); - - const Ports mPorts; - struct socket *mSock; - std::optional mNegotiatedStreamsCount; - - Processor mProcessor; - std::atomic mPendingRecvCount = 0; - std::atomic mPendingFlushCount = 0; - std::mutex mRecvMutex; - std::recursive_mutex mSendMutex; // buffered amount callback is synchronous - Queue mSendQueue; - bool mSendShutdown = false; - std::map mBufferedAmount; - amount_callback mBufferedAmountCallback; - - std::mutex mWriteMutex; - std::condition_variable mWrittenCondition; - std::atomic mWritten = false; // written outside lock - std::atomic mWrittenOnce = false; // same - - binary mPartialMessage, mPartialNotification; - binary mPartialStringData, mPartialBinaryData; - - // Stats - std::atomic mBytesSent = 0, mBytesReceived = 0; - - static void UpcallCallback(struct socket *sock, void *arg, int flags); - static int WriteCallback(void *sctp_ptr, void *data, size_t len, uint8_t tos, uint8_t set_df); - static void DebugCallback(const char *format, ...); - - class InstancesSet; - static InstancesSet *Instances; -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/sha.hpp b/godot/thirdparty/libdatachannel/src/impl/sha.hpp deleted file mode 100644 index 0ef960ba..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/sha.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_SHA_H -#define RTC_IMPL_SHA_H - -#if RTC_ENABLE_WEBSOCKET - -#include "common.hpp" - -namespace rtc::impl { - -binary Sha1(const binary &input); -binary Sha1(const string &input); - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/socket.hpp b/godot/thirdparty/libdatachannel/src/impl/socket.hpp deleted file mode 100644 index 7ad9b50d..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/socket.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -// This header defines types to allow cross-platform socket API usage. - -#ifndef RTC_SOCKET_H -#define RTC_SOCKET_H - -#ifdef _WIN32 - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 // Windows 7 -#endif -#ifndef __MSVCRT_VERSION__ -#define __MSVCRT_VERSION__ 0x0601 -#endif - -#include -#include -// -#include -#include - -#ifdef __MINGW32__ -#include -#include -#ifndef IPV6_V6ONLY -#define IPV6_V6ONLY 27 -#endif -#endif - -#define NO_IFADDRS -#define NO_PMTUDISC - -typedef SOCKET socket_t; -typedef SOCKADDR sockaddr; -typedef ULONG ctl_t; -typedef DWORD sockopt_t; -#define sockerrno ((int)WSAGetLastError()) -#define IP_DONTFRAG IP_DONTFRAGMENT -#define HOST_NAME_MAX 256 - -#define poll WSAPoll -typedef ULONG nfds_t; - -#define SEADDRINUSE WSAEADDRINUSE -#define SEINTR WSAEINTR -#define SEAGAIN WSAEWOULDBLOCK -#define SEACCES WSAEACCES -#define SEWOULDBLOCK WSAEWOULDBLOCK -#define SEINPROGRESS WSAEINPROGRESS -#define SECONNREFUSED WSAECONNREFUSED -#define SECONNRESET WSAECONNRESET -#define SENETRESET WSAENETRESET - -#else // assume POSIX - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __linux__ -#define NO_PMTUDISC -#endif - -#ifdef __ANDROID__ -#define NO_IFADDRS -#else -#include -#endif - -typedef int socket_t; -typedef int ctl_t; -typedef int sockopt_t; -#define sockerrno errno -#define INVALID_SOCKET -1 -#define ioctlsocket ioctl -#define closesocket close - -#define SEADDRINUSE EADDRINUSE -#define SEINTR EINTR -#define SEAGAIN EAGAIN -#define SEACCES EACCES -#define SEWOULDBLOCK EWOULDBLOCK -#define SEINPROGRESS EINPROGRESS -#define SECONNREFUSED ECONNREFUSED -#define SECONNRESET ECONNRESET -#define SENETRESET ENETRESET - -#endif // _WIN32 - -#ifndef IN6_IS_ADDR_LOOPBACK -#define IN6_IS_ADDR_LOOPBACK(a) \ - (((const uint32_t *)(a))[0] == 0 && ((const uint32_t *)(a))[1] == 0 && \ - ((const uint32_t *)(a))[2] == 0 && ((const uint32_t *)(a))[3] == htonl(1)) -#endif - -#ifndef IN6_IS_ADDR_LINKLOCAL -#define IN6_IS_ADDR_LINKLOCAL(a) \ - ((((const uint32_t *)(a))[0] & htonl(0xffc00000)) == htonl(0xfe800000)) -#endif - -#ifndef IN6_IS_ADDR_SITELOCAL -#define IN6_IS_ADDR_SITELOCAL(a) \ - ((((const uint32_t *)(a))[0] & htonl(0xffc00000)) == htonl(0xfec00000)) -#endif - -#ifndef IN6_IS_ADDR_V4MAPPED -#define IN6_IS_ADDR_V4MAPPED(a) \ - ((((const uint32_t *)(a))[0] == 0) && (((const uint32_t *)(a))[1] == 0) && \ - (((const uint32_t *)(a))[2] == htonl(0xFFFF))) -#endif - -#endif // JUICE_SOCKET_H diff --git a/godot/thirdparty/libdatachannel/src/impl/tcpserver.hpp b/godot/thirdparty/libdatachannel/src/impl/tcpserver.hpp deleted file mode 100644 index e1655755..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/tcpserver.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_TCP_SERVER_H -#define RTC_IMPL_TCP_SERVER_H - -#include "common.hpp" -#include "pollinterrupter.hpp" -#include "queue.hpp" -#include "socket.hpp" -#include "tcptransport.hpp" - -#if RTC_ENABLE_WEBSOCKET - -namespace rtc::impl { - -class TcpServer final { -public: - TcpServer(uint16_t port, const char *bindAddress = nullptr); - ~TcpServer(); - - TcpServer(const TcpServer &other) = delete; - void operator=(const TcpServer &other) = delete; - - shared_ptr accept(); - void close(); - - uint16_t port() const { return mPort; } - -private: - void listen(uint16_t port, const char *bindAddress); - - uint16_t mPort; - socket_t mSock = INVALID_SOCKET; - std::mutex mSockMutex; - PollInterrupter mInterrupter; -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/tcptransport.hpp b/godot/thirdparty/libdatachannel/src/impl/tcptransport.hpp deleted file mode 100644 index 02436ea8..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/tcptransport.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_TCP_TRANSPORT_H -#define RTC_IMPL_TCP_TRANSPORT_H - -#include "common.hpp" -#include "pollservice.hpp" -#include "queue.hpp" -#include "socket.hpp" -#include "transport.hpp" - -#if RTC_ENABLE_WEBSOCKET - -#include -#include -#include -#include - -namespace rtc::impl { - -class TcpTransport final : public Transport, public std::enable_shared_from_this { -public: - using amount_callback = std::function; - - TcpTransport(string hostname, string service, state_callback callback); // active - TcpTransport(socket_t sock, state_callback callback); // passive - ~TcpTransport(); - - void onBufferedAmount(amount_callback callback); - void setReadTimeout(std::chrono::milliseconds readTimeout); - - void start() override; - bool send(message_ptr message) override; - - void incoming(message_ptr message) override; - bool outgoing(message_ptr message) override; - - bool isActive() const; - string remoteAddress() const; - -private: - void connect(); - void resolve(); - void attempt(); - void createSocket(const struct sockaddr *addr, socklen_t addrlen); - void configureSocket(); - void setPoll(PollService::Direction direction); - void close(); - - bool trySendQueue(); - bool trySendMessage(message_ptr &message); - void updateBufferedAmount(ptrdiff_t delta); - void triggerBufferedAmount(size_t amount); - - void process(PollService::Event event); - - const bool mIsActive; - string mHostname, mService; - amount_callback mBufferedAmountCallback; - optional mReadTimeout; - - std::list> mResolved; - - socket_t mSock; - Queue mSendQueue; - size_t mBufferedAmount = 0; - std::mutex mSendMutex; -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/threadpool.cpp b/godot/thirdparty/libdatachannel/src/impl/threadpool.cpp deleted file mode 100644 index 1fda4e26..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/threadpool.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "threadpool.hpp" -#include "utils.hpp" - -namespace rtc::impl { - -ThreadPool &ThreadPool::Instance() { - static ThreadPool *instance = new ThreadPool; - return *instance; -} - -ThreadPool::ThreadPool() {} - -ThreadPool::~ThreadPool() {} - -int ThreadPool::count() const { - std::unique_lock lock(mWorkersMutex); - return int(mWorkers.size()); -} - -void ThreadPool::spawn(int count) { - std::unique_lock lock(mWorkersMutex); - while (count-- > 0) - mWorkers.emplace_back(std::bind(&ThreadPool::run, this)); -} - -void ThreadPool::join() { - { - std::unique_lock lock(mMutex); - mWaitingCondition.wait(lock, [&]() { return mBusyWorkers == 0; }); - mJoining = true; - mTasksCondition.notify_all(); - } - - std::unique_lock lock(mWorkersMutex); - for (auto &w : mWorkers) - w.join(); - - mWorkers.clear(); - - mJoining = false; -} - -void ThreadPool::clear() { - std::unique_lock lock(mMutex); - while (!mTasks.empty()) - mTasks.pop(); -} - -void ThreadPool::run() { - utils::this_thread::set_name("RTC worker"); - ++mBusyWorkers; - scope_guard guard([&]() { --mBusyWorkers; }); - while (runOne()) { - } -} - -bool ThreadPool::runOne() { - if (auto task = dequeue()) { - task(); - return true; - } - return false; -} - -std::function ThreadPool::dequeue() { - std::unique_lock lock(mMutex); - while (!mJoining) { - std::optional time; - if (!mTasks.empty()) { - time = mTasks.top().time; - if (*time <= clock::now()) { - auto func = std::move(mTasks.top().func); - mTasks.pop(); - return func; - } - } - - --mBusyWorkers; - scope_guard guard([&]() { ++mBusyWorkers; }); - mWaitingCondition.notify_all(); - if (time) - mTasksCondition.wait_until(lock, *time); - else - mTasksCondition.wait(lock); - } - return nullptr; -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/threadpool.hpp b/godot/thirdparty/libdatachannel/src/impl/threadpool.hpp deleted file mode 100644 index 0921d9eb..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/threadpool.hpp +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_THREADPOOL_H -#define RTC_IMPL_THREADPOOL_H - -#include "common.hpp" -#include "init.hpp" -#include "internals.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rtc::impl { - -template -using invoke_future_t = std::future, std::decay_t...>>; - -class ThreadPool final { -public: - using clock = std::chrono::steady_clock; - - static ThreadPool &Instance(); - - ThreadPool(const ThreadPool &) = delete; - ThreadPool &operator=(const ThreadPool &) = delete; - ThreadPool(ThreadPool &&) = delete; - ThreadPool &operator=(ThreadPool &&) = delete; - - int count() const; - void spawn(int count = 1); - void join(); - void clear(); - void run(); - bool runOne(); - - template - auto enqueue(F &&f, Args &&...args) noexcept -> invoke_future_t; - - template - auto schedule(clock::duration delay, F &&f, Args &&...args) noexcept - -> invoke_future_t; - - template - auto schedule(clock::time_point time, F &&f, Args &&...args) noexcept - -> invoke_future_t; - -private: - ThreadPool(); - ~ThreadPool(); - - std::function dequeue(); // returns null function if joining - - std::vector mWorkers; - std::atomic mBusyWorkers = 0; - std::atomic mJoining = false; - - struct Task { - clock::time_point time; - std::function func; - bool operator>(const Task &other) const { return time > other.time; } - bool operator<(const Task &other) const { return time < other.time; } - }; - std::priority_queue, std::greater> mTasks; - - std::condition_variable mTasksCondition, mWaitingCondition; - mutable std::mutex mMutex, mWorkersMutex; -}; - -template -auto ThreadPool::enqueue(F &&f, Args &&...args) noexcept -> invoke_future_t { - return schedule(clock::now(), std::forward(f), std::forward(args)...); -} - -template -auto ThreadPool::schedule(clock::duration delay, F &&f, Args &&...args) noexcept - -> invoke_future_t { - return schedule(clock::now() + delay, std::forward(f), std::forward(args)...); -} - -template -auto ThreadPool::schedule(clock::time_point time, F &&f, Args &&...args) noexcept - -> invoke_future_t { - std::unique_lock lock(mMutex); - using R = std::invoke_result_t, std::decay_t...>; - auto bound = std::bind(std::forward(f), std::forward(args)...); - auto task = std::make_shared>([bound = std::move(bound)]() mutable { - return bound(); - }); - std::future result = task->get_future(); - - mTasks.push({time, [task = std::move(task)]() { return (*task)(); }}); - mTasksCondition.notify_one(); - return result; -} - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/tls.cpp b/godot/thirdparty/libdatachannel/src/impl/tls.cpp deleted file mode 100644 index fc096d68..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/tls.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "tls.hpp" - -#include -#include - -#if USE_GNUTLS - -namespace rtc::gnutls { - -// Return false on non-fatal error -RTC_WRAPPED(bool) check(int ret, const string &message) { - if (ret < 0) { - if (!gnutls_error_is_fatal(ret)) { - return false; - } - RTC_THROW RTC_RUNTIME_ERROR(message + ": " + gnutls_strerror(ret)); - } - return true; -} - -gnutls_certificate_credentials_t *new_credentials() { - auto creds = new gnutls_certificate_credentials_t; - gnutls::check(gnutls_certificate_allocate_credentials(creds)); - return creds; -} - -void free_credentials(gnutls_certificate_credentials_t *creds) { - gnutls_certificate_free_credentials(*creds); - delete creds; -} - -gnutls_x509_crt_t *new_crt() { - auto crt = new gnutls_x509_crt_t; - gnutls::check(gnutls_x509_crt_init(crt)); - return crt; -} - -void free_crt(gnutls_x509_crt_t *crt) { - gnutls_x509_crt_deinit(*crt); - delete crt; -} - -gnutls_x509_privkey_t *new_privkey() { - auto privkey = new gnutls_x509_privkey_t; - gnutls::check(gnutls_x509_privkey_init(privkey)); - return privkey; -} - -void free_privkey(gnutls_x509_privkey_t *privkey) { - gnutls_x509_privkey_deinit(*privkey); - delete privkey; -} - -gnutls_datum_t make_datum(char *data, size_t size) { - gnutls_datum_t datum; - datum.data = reinterpret_cast(data); - datum.size = size; - return datum; -} - -} // namespace rtc::gnutls - -#elif USE_MBEDTLS - -#include - -namespace { - -// Safe gmtime -int my_gmtime(const time_t *t, struct tm *buf) { -#ifdef _WIN32 - return ::gmtime_s(buf, t) == 0 ? 0 : -1; -#else // POSIX - return ::gmtime_r(t, buf) != NULL ? 0 : -1; -#endif -} - -// Format time_t as UTC -size_t my_strftme(char *buf, size_t size, const char *format, const time_t *t) { - struct tm g; - if (my_gmtime(t, &g) != 0) - return 0; - - return ::strftime(buf, size, format, &g); -} - -} // namespace - -namespace rtc::mbedtls { - -// Return false on non-fatal error -RTC_WRAPPED(bool) check(int ret, const string &message) { - if (ret < 0) { - if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE || - ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS || ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS || - ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) - return false; - - // const size_t bufferSize = 1024; - // char buffer[bufferSize]; - // mbedtls_strerror(ret, reinterpret_cast(buffer), bufferSize); - RTC_THROW RTC_RUNTIME_ERROR(message + ": Error " + std::to_string(ret)); - } - return true; -} - -RTC_WRAPPED(string) format_time(const std::chrono::system_clock::time_point &tp) { - time_t t = std::chrono::system_clock::to_time_t(tp); - const size_t bufferSize = 256; - char buffer[bufferSize]; - if (my_strftme(buffer, bufferSize, "%Y%m%d%H%M%S", &t) == 0) - RTC_THROW RTC_RUNTIME_ERROR("Time conversion failed"); - - return string(buffer); -}; - -std::shared_ptr new_pk_context() { - return std::shared_ptr{[]() { - auto p = new mbedtls_pk_context; - mbedtls_pk_init(p); - return p; - }(), - [](mbedtls_pk_context *p) { - mbedtls_pk_free(p); - delete p; - }}; -} - -std::shared_ptr new_x509_crt() { - return std::shared_ptr{[]() { - auto p = new mbedtls_x509_crt; - mbedtls_x509_crt_init(p); - return p; - }(), - [](mbedtls_x509_crt *crt) { - mbedtls_x509_crt_free(crt); - delete crt; - }}; -} - -} // namespace rtc::mbedtls - -#else // OPENSSL - -namespace rtc::openssl { - -void init() { - static std::mutex mutex; - static bool done = false; - - std::lock_guard lock(mutex); - if (!std::exchange(done, true)) { - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, nullptr); - OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, nullptr); - } -} - -string error_string(unsigned long error) { - const size_t bufferSize = 256; - char buffer[bufferSize]; - ERR_error_string_n(error, buffer, bufferSize); - return string(buffer); -} - -RTC_WRAPPED(bool) check(int success, const string &message) { - unsigned long last_error = ERR_peek_last_error(); - ERR_clear_error(); - - if (success > 0) - return true; - - RTC_THROW RTC_RUNTIME_ERROR(message + (last_error != 0 ? ": " + error_string(last_error) : "")); -} - -// Return false on recoverable error -RTC_WRAPPED(bool) check_error(int err, const string &message) { - unsigned long last_error = ERR_peek_last_error(); - ERR_clear_error(); - - if (err == SSL_ERROR_NONE) - return true; - - if (err == SSL_ERROR_ZERO_RETURN) - RTC_THROW RTC_RUNTIME_ERROR(message + ": peer closed connection"); - - if (err == SSL_ERROR_SYSCALL) - RTC_THROW RTC_RUNTIME_ERROR(message + ": fatal I/O error"); - - if (err == SSL_ERROR_SSL) - RTC_THROW RTC_RUNTIME_ERROR(message + - (last_error != 0 ? ": " + error_string(last_error) : "")); - - // SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE end up here - return false; -} - -BIO *BIO_new_from_file(const string &filename) { - BIO *bio = nullptr; - RTC_TRY { - std::ifstream ifs(filename, std::ifstream::in | std::ifstream::binary); - if (!ifs.is_open()) - return nullptr; - - bio = BIO_new(BIO_s_mem()); - - const size_t bufferSize = 4096; - char buffer[bufferSize]; - while (ifs.good()) { - ifs.read(buffer, bufferSize); - BIO_write(bio, buffer, int(ifs.gcount())); - } - ifs.close(); - return bio; - - } RTC_CATCH (const RTC_EXCEPTION &) { - BIO_free(bio); - return nullptr; - } -} - -} // namespace rtc::openssl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/tls.hpp b/godot/thirdparty/libdatachannel/src/impl/tls.hpp deleted file mode 100644 index 61c2f08f..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/tls.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_TLS_H -#define RTC_TLS_H - -#include "common.hpp" - -#include - -#if USE_GNUTLS - -#include - -#include -#include -#include - -namespace rtc::gnutls { - -RTC_WRAPPED(bool) check(int ret, const string &message = "GnuTLS error"); - -gnutls_certificate_credentials_t *new_credentials(); -void free_credentials(gnutls_certificate_credentials_t *creds); - -gnutls_x509_crt_t *new_crt(); -void free_crt(gnutls_x509_crt_t *crt); - -gnutls_x509_privkey_t *new_privkey(); -void free_privkey(gnutls_x509_privkey_t *privkey); - -gnutls_datum_t make_datum(char *data, size_t size); - -} // namespace rtc::gnutls - -#elif USE_MBEDTLS - -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/ecdsa.h" -#include "mbedtls/entropy.h" -#include "mbedtls/error.h" -#include "mbedtls/pk.h" -#include "mbedtls/rsa.h" -#include "mbedtls/sha256.h" -#include "mbedtls/ssl.h" -#include "mbedtls/x509_crt.h" - -namespace rtc::mbedtls { - -RTC_WRAPPED(bool) check(int ret, const string &message = "MbedTLS error"); - -RTC_WRAPPED(string) format_time(const std::chrono::system_clock::time_point &tp); - -std::shared_ptr new_pk_context(); -std::shared_ptr new_x509_crt(); - -} // namespace rtc::mbedtls - -#else // OPENSSL - -#ifdef _WIN32 -// Include winsock2.h header first since OpenSSL may include winsock.h -#include -#endif - -#include - -#include -#include -#include -#include - -#ifndef BIO_EOF -#define BIO_EOF -1 -#endif - -namespace rtc::openssl { - -void init(); -string error_string(unsigned long error); - -RTC_WRAPPED(bool) check(int success, const string &message = "OpenSSL error"); -RTC_WRAPPED(bool) check_error(int err, const string &message = "OpenSSL error"); - -BIO *BIO_new_from_file(const string &filename); - -} // namespace rtc::openssl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/tlstransport.hpp b/godot/thirdparty/libdatachannel/src/impl/tlstransport.hpp deleted file mode 100644 index 392bbc08..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/tlstransport.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_TLS_TRANSPORT_H -#define RTC_IMPL_TLS_TRANSPORT_H - -#include "certificate.hpp" -#include "common.hpp" -#include "queue.hpp" -#include "tls.hpp" -#include "transport.hpp" - -#if RTC_ENABLE_WEBSOCKET - -#include -#include - -namespace rtc::impl { - -class TcpTransport; -class HttpProxyTransport; - -class TlsTransport : public Transport, public std::enable_shared_from_this { -public: - static void Init(); - static void Cleanup(); - - TlsTransport(variant, shared_ptr> lower, - optional host, certificate_ptr certificate, state_callback callback); - virtual ~TlsTransport(); - - void start() override; - void stop() override; - bool send(message_ptr message) override; - - bool isClient() const { return mIsClient; } - -protected: - virtual void incoming(message_ptr message) override; - virtual bool outgoing(message_ptr message) override; - virtual void postHandshake(); - - void enqueueRecv(); - void doRecv(); - - const optional mHost; - const bool mIsClient; - - Queue mIncomingQueue; - std::atomic mPendingRecvCount = 0; - std::mutex mRecvMutex; - -#if USE_GNUTLS - gnutls_session_t mSession; - - message_ptr mIncomingMessage; - size_t mIncomingMessagePosition = 0; - std::atomic mOutgoingResult = true; - - static ssize_t WriteCallback(gnutls_transport_ptr_t ptr, const void *data, size_t len); - static ssize_t ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_t maxlen); - static int TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int ms); - -#elif USE_MBEDTLS - mbedtls_entropy_context mEntropy; - mbedtls_ctr_drbg_context mDrbg; - mbedtls_ssl_config mConf; - mbedtls_ssl_context mSsl; - - std::mutex mSslMutex; - std::atomic mOutgoingResult = true; - - message_ptr mIncomingMessage; - size_t mIncomingMessagePosition = 0; - - static int WriteCallback(void *ctx, const unsigned char *buf, size_t len); - static int ReadCallback(void *ctx, unsigned char *buf, size_t len); - -#else - SSL_CTX *mCtx; - SSL *mSsl; - BIO *mInBio, *mOutBio; - std::mutex mSslMutex; - - bool flushOutput(); - - static int TransportExIndex; - - static void InfoCallback(const SSL *ssl, int where, int ret); -#endif -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/track.hpp b/godot/thirdparty/libdatachannel/src/impl/track.hpp deleted file mode 100644 index 8c35ba63..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/track.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_TRACK_H -#define RTC_IMPL_TRACK_H - -#include "channel.hpp" -#include "common.hpp" -#include "description.hpp" -#include "mediahandler.hpp" -#include "queue.hpp" - -#if RTC_ENABLE_MEDIA -#include "dtlssrtptransport.hpp" -#endif - -#include -#include - -namespace rtc::impl { - -struct PeerConnection; - -class Track final : public std::enable_shared_from_this, public Channel { -public: - Track(weak_ptr pc, Description::Media description); - ~Track(); - - void close(); - void incoming(message_ptr message); - bool outgoing(message_ptr message); - - optional receive() override; - optional peek() override; - size_t availableAmount() const override; - - bool isOpen() const; - bool isClosed() const; - size_t maxMessageSize() const; - - string mid() const; - Description::Direction direction() const; - Description::Media description() const; - void setDescription(Description::Media description); - - shared_ptr getMediaHandler(); - void setMediaHandler(shared_ptr handler); - -#if RTC_ENABLE_MEDIA - void open(shared_ptr transport); -#endif - -private: - bool transportSend(message_ptr message); - - const weak_ptr mPeerConnection; -#if RTC_ENABLE_MEDIA - weak_ptr mDtlsSrtpTransport; -#endif - - Description::Media mMediaDescription; - shared_ptr mMediaHandler; - - mutable std::shared_mutex mMutex; - - std::atomic mIsClosed = false; - - Queue mRecvQueue; -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/transport.cpp b/godot/thirdparty/libdatachannel/src/impl/transport.cpp deleted file mode 100644 index 3da1dd48..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/transport.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2019-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "transport.hpp" - -namespace rtc::impl { - -Transport::Transport(shared_ptr lower, state_callback callback) - : mLower(std::move(lower)), mStateChangeCallback(std::move(callback)) {} - -Transport::~Transport() { - unregisterIncoming(); - - if (mLower) { - mLower->stop(); - mLower.reset(); - } -} - -void Transport::registerIncoming() { - if (mLower) { - PLOG_VERBOSE << "Registering incoming callback"; - mLower->onRecv([this](message_ptr message) -> void { - RTC_TRY { - Transport::incoming(message); - } RTC_CATCH(RTC_EXCEPTION e) { - PLOG_WARNING << e.RTC_WHAT(); // FIXME - } - }); - } -} - -void Transport::unregisterIncoming() { - if (mLower) { - PLOG_VERBOSE << "Unregistering incoming callback"; - mLower->onRecv(nullptr); - } -} - -Transport::State Transport::state() const { return mState; } - -void Transport::onRecv(message_callback callback) { mRecvCallback = std::move(callback); } - -void Transport::onStateChange(state_callback callback) { - mStateChangeCallback = std::move(callback); -} - -RTC_WRAPPED(void) Transport::start() { registerIncoming(); RTC_RET; } - -void Transport::stop() { unregisterIncoming(); } - -RTC_WRAPPED(bool) Transport::send(message_ptr message) { return outgoing(message); } - -void Transport::recv(message_ptr message) { - RTC_TRY { - mRecvCallback(message); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void Transport::changeState(State state) { - RTC_TRY { - if (mState.exchange(state) != state) - mStateChangeCallback(state); - } RTC_CATCH (const RTC_EXCEPTION &e) { - PLOG_WARNING << e.RTC_WHAT(); - } -} - -void Transport::incoming(message_ptr message) { recv(message); } - -RTC_WRAPPED(bool) Transport::outgoing(message_ptr message) { - if (mLower) - return mLower->send(message); - else - return false; -} - -} // namespace rtc::impl diff --git a/godot/thirdparty/libdatachannel/src/impl/transport.hpp b/godot/thirdparty/libdatachannel/src/impl/transport.hpp deleted file mode 100644 index 5d8ed725..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/transport.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_TRANSPORT_H -#define RTC_IMPL_TRANSPORT_H - -#include "common.hpp" -#include "init.hpp" -#include "internals.hpp" -#include "message.hpp" - -#include -#include -#include - -namespace rtc::impl { - -class Transport { -public: - enum class State { Disconnected, Connecting, Connected, Completed, Failed }; - using state_callback = std::function; - - Transport(shared_ptr lower = nullptr, state_callback callback = nullptr); - virtual ~Transport(); - - void registerIncoming(); - void unregisterIncoming(); - State state() const; - - void onRecv(message_callback callback); - void onStateChange(state_callback callback); - - virtual RTC_WRAPPED(void) start(); - virtual void stop(); - virtual RTC_WRAPPED(bool) send(message_ptr message); - -protected: - void recv(message_ptr message); - void changeState(State state); - virtual void incoming(message_ptr message); - virtual RTC_WRAPPED(bool) outgoing(message_ptr message); - -private: - const init_token mInitToken = Init::Instance().token(); - - shared_ptr mLower; - synchronized_callback mStateChangeCallback; - synchronized_callback mRecvCallback; - - std::atomic mState = State::Disconnected; -}; - -} // namespace rtc::impl - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/utils.cpp b/godot/thirdparty/libdatachannel/src/impl/utils.cpp deleted file mode 100644 index fefaced0..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/utils.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Copyright (c) 2020-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "utils.hpp" - -#include "impl/internals.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#include - -typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR); -#endif -#if defined(__linux__) -#include // for prctl(PR_SET_NAME) -#endif -#if defined(__FreeBSD__) -#include // for pthread_set_name_np -#endif - -namespace rtc::impl::utils { - -using std::to_integer; - -std::vector explode(const string &str, char delim) { - std::vector result; - std::istringstream ss(str); - string token; - while (std::getline(ss, token, delim)) - result.push_back(token); - - return result; -} - -string implode(const std::vector &tokens, char delim) { - string sdelim(1, delim); - std::ostringstream ss; - std::copy(tokens.begin(), tokens.end(), std::ostream_iterator(ss, sdelim.c_str())); - string result = ss.str(); - if (result.size() > 0) - result.resize(result.size() - 1); - - return result; -} - -string url_decode(const string &str) { - string result; - size_t i = 0; - while (i < str.size()) { - char c = str[i++]; - if (c == '%') { - auto value = str.substr(i, 2); - if (value.size() != 2 || !std::isxdigit(value[0]) || !std::isxdigit(value[1])) { - PLOG_WARNING << "Invalid percent-encoded character in URL: \"%" + value + "\""; - } else { - c = static_cast(std::stoi(value, nullptr, 16)); - i += 2; - } - } - - result.push_back(c); - } - - return result; -} - -string base64_encode(const binary &data) { - static const char tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - string out; - out.reserve(3 * ((data.size() + 3) / 4)); - int i = 0; - while (data.size() - i >= 3) { - auto d0 = to_integer(data[i]); - auto d1 = to_integer(data[i + 1]); - auto d2 = to_integer(data[i + 2]); - out += tab[d0 >> 2]; - out += tab[((d0 & 3) << 4) | (d1 >> 4)]; - out += tab[((d1 & 0x0F) << 2) | (d2 >> 6)]; - out += tab[d2 & 0x3F]; - i += 3; - } - - int left = int(data.size() - i); - if (left) { - auto d0 = to_integer(data[i]); - out += tab[d0 >> 2]; - if (left == 1) { - out += tab[(d0 & 3) << 4]; - out += '='; - } else { // left == 2 - auto d1 = to_integer(data[i + 1]); - out += tab[((d0 & 3) << 4) | (d1 >> 4)]; - out += tab[(d1 & 0x0F) << 2]; - } - out += '='; - } - - return out; -} - -std::seed_seq random_seed() { - std::vector seed; - - // Seed with random device - // On some systems an exception might be thrown if the random_device can't be initialized - std::random_device device; - // 128 bits should be more than enough - std::generate_n(std::back_inserter(seed), 4, std::ref(device)); - - // Seed with high-resolution clock - using std::chrono::high_resolution_clock; - seed.push_back( - static_cast(high_resolution_clock::now().time_since_epoch().count())); - - // Seed with thread id - seed.push_back( - static_cast(std::hash{}(std::this_thread::get_id()))); - - return std::seed_seq(seed.begin(), seed.end()); -} - -namespace { - -void thread_set_name_self(const char *name) { -#if defined(_WIN32) - int name_length = (int)strlen(name); - int wname_length = - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, name, name_length, nullptr, 0); - if (wname_length > 0) { - std::wstring wname(wname_length, L'\0'); - wname_length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, name, name_length, - &wname[0], wname_length + 1); - - HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); - if (kernel32 != nullptr) { - auto pSetThreadDescription = - (pfnSetThreadDescription)GetProcAddress(kernel32, "SetThreadDescription"); - if (pSetThreadDescription != nullptr) { - pSetThreadDescription(GetCurrentThread(), wname.c_str()); - } - } - } -#elif defined(__linux__) - prctl(PR_SET_NAME, name); -#elif defined(__APPLE__) - pthread_setname_np(name); -#elif defined(__FreeBSD__) - pthread_set_name_np(pthread_self(), name); -#else - (void)name; -#endif -} - -} // namespace - -namespace this_thread { - -void set_name(const string &name) { thread_set_name_self(name.c_str()); } - -} // namespace this_thread - -} // namespace rtc::impl::utils diff --git a/godot/thirdparty/libdatachannel/src/impl/utils.hpp b/godot/thirdparty/libdatachannel/src/impl/utils.hpp deleted file mode 100644 index 9e852dd7..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/utils.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2020-2022 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_UTILS_H -#define RTC_IMPL_UTILS_H - -#include "common.hpp" - -#include -#include -#include -#include -#include - -namespace rtc::impl::utils { - -std::vector explode(const string &str, char delim); -string implode(const std::vector &tokens, char delim); - -// Decode URL percent-encoding (RFC 3986) -// See https://www.rfc-editor.org/rfc/rfc3986.html#section-2.1 -string url_decode(const string &str); - -// Encode as base64 (RFC 4648) -// See https://www.rfc-editor.org/rfc/rfc4648.html#section-4 -string base64_encode(const binary &data); - -// Return a random seed sequence -std::seed_seq random_seed(); - -template -struct random_engine_wrapper { - Generator &engine; - using result_type = Result; - static constexpr result_type min() { return static_cast(Generator::min()); } - static constexpr result_type max() { return static_cast(Generator::max()); } - inline result_type operator()() { return static_cast(engine()); } - inline void discard(unsigned long long z) { engine.discard(z); } -}; - -// Return a wrapped thread-local seeded random number generator -template -auto random_engine() { - static thread_local std::seed_seq seed = random_seed(); - static thread_local Generator engine{seed}; - return random_engine_wrapper{engine}; -} - -// Return a wrapped thread-local seeded random bytes generator -template auto random_bytes_engine() { - using char_independent_bits_engine = - std::independent_bits_engine; - static_assert(char_independent_bits_engine::min() == std::numeric_limits::min()); - static_assert(char_independent_bits_engine::max() == std::numeric_limits::max()); - return random_engine(); -} - -namespace this_thread { - -void set_name(const string &name); - -} // namespace this_thread - -} // namespace rtc::impl::utils - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/verifiedtlstransport.hpp b/godot/thirdparty/libdatachannel/src/impl/verifiedtlstransport.hpp deleted file mode 100644 index 352f2a04..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/verifiedtlstransport.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_VERIFIED_TLS_TRANSPORT_H -#define RTC_IMPL_VERIFIED_TLS_TRANSPORT_H - -#include "tlstransport.hpp" - -#if RTC_ENABLE_WEBSOCKET - -namespace rtc::impl { - -class VerifiedTlsTransport final : public TlsTransport { -public: - VerifiedTlsTransport(variant, shared_ptr> lower, - string host, certificate_ptr certificate, state_callback callback); - ~VerifiedTlsTransport(); -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/websocket.hpp b/godot/thirdparty/libdatachannel/src/impl/websocket.hpp deleted file mode 100644 index 9287cf08..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/websocket.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_WEBSOCKET_H -#define RTC_IMPL_WEBSOCKET_H - -#if RTC_ENABLE_WEBSOCKET - -#include "channel.hpp" -#include "common.hpp" -#include "httpproxytransport.hpp" -#include "init.hpp" -#include "message.hpp" -#include "queue.hpp" -#include "tcptransport.hpp" -#include "tlstransport.hpp" -#include "wstransport.hpp" - -#include "rtc/websocket.hpp" - -#include -#include - -namespace rtc::impl { - -struct WebSocket final : public Channel, public std::enable_shared_from_this { - using State = rtc::WebSocket::State; - using Configuration = rtc::WebSocket::Configuration; - - WebSocket(optional optConfig = nullopt, certificate_ptr certificate = nullptr); - ~WebSocket(); - - void open(const string &url); - void close(); - void remoteClose(); - bool outgoing(message_ptr message); - void incoming(message_ptr message); - - optional receive() override; - optional peek() override; - size_t availableAmount() const override; - - bool isOpen() const; - bool isClosed() const; - size_t maxMessageSize() const; - - bool changeState(State state); - - shared_ptr setTcpTransport(shared_ptr transport); - shared_ptr initProxyTransport(); - shared_ptr initTlsTransport(); - shared_ptr initWsTransport(); - shared_ptr getTcpTransport() const; - shared_ptr getTlsTransport() const; - shared_ptr getWsTransport() const; - shared_ptr getWsHandshake() const; - - void closeTransports(); - - const Configuration config; - - std::atomic state = State::Closed; - -private: - void scheduleConnectionTimeout(); - - const init_token mInitToken = Init::Instance().token(); - - const certificate_ptr mCertificate; - bool mIsSecure; - - optional mHostname; // for TLS SNI and Proxy - optional mService; // for Proxy - - shared_ptr mTcpTransport; - shared_ptr mProxyTransport; - shared_ptr mTlsTransport; - shared_ptr mWsTransport; - shared_ptr mWsHandshake; - - Queue mRecvQueue; -}; - -} // namespace rtc::impl - -#endif - -#endif // RTC_IMPL_WEBSOCKET_H diff --git a/godot/thirdparty/libdatachannel/src/impl/websocketserver.hpp b/godot/thirdparty/libdatachannel/src/impl/websocketserver.hpp deleted file mode 100644 index 09e082a4..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/websocketserver.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_WEBSOCKETSERVER_H -#define RTC_IMPL_WEBSOCKETSERVER_H - -#if RTC_ENABLE_WEBSOCKET - -#include "certificate.hpp" -#include "common.hpp" -#include "init.hpp" -#include "message.hpp" -#include "tcpserver.hpp" -#include "websocket.hpp" - -#include "rtc/websocket.hpp" -#include "rtc/websocketserver.hpp" - -#include -#include - -namespace rtc::impl { - -struct WebSocketServer final : public std::enable_shared_from_this { - using Configuration = rtc::WebSocketServer::Configuration; - - WebSocketServer(Configuration config_); - ~WebSocketServer(); - - void stop(); - - const Configuration config; - unique_ptr tcpServer; - synchronized_callback> clientCallback; - -private: - const init_token mInitToken = Init::Instance().token(); - - void runLoop(); - - certificate_ptr mCertificate; - std::thread mThread; - std::atomic mStopped; -}; - -} // namespace rtc::impl - -#endif - -#endif // RTC_IMPL_WEBSOCKET_H diff --git a/godot/thirdparty/libdatachannel/src/impl/wshandshake.hpp b/godot/thirdparty/libdatachannel/src/impl/wshandshake.hpp deleted file mode 100644 index d5923742..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/wshandshake.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_WS_HANDSHAKE_H -#define RTC_IMPL_WS_HANDSHAKE_H - -#include "common.hpp" - -#if RTC_ENABLE_WEBSOCKET - -#include -#include -#include -#include - -namespace rtc::impl { - -class WsHandshake final { -public: - WsHandshake(); - WsHandshake(string host, string path = "/", std::vector protocols = {}); - - string host() const; - string path() const; - std::vector protocols() const; - - string generateHttpRequest(); - string generateHttpResponse(); - string generateHttpError(int responseCode = 400); - - class Error : public std::runtime_error { - public: - explicit Error(const string &w); - }; - - class RequestError : public Error { - public: - explicit RequestError(const string &w, int responseCode = 400); - int responseCode() const; - - private: - const int mResponseCode; - }; - - size_t parseHttpRequest(const byte *buffer, size_t size); - size_t parseHttpResponse(const byte *buffer, size_t size); - -private: - static string generateKey(); - static string computeAcceptKey(const string &key); - - string mHost; - string mPath; - std::vector mProtocols; - string mKey; - mutable std::mutex mMutex; -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/impl/wstransport.hpp b/godot/thirdparty/libdatachannel/src/impl/wstransport.hpp deleted file mode 100644 index 9f17eeec..00000000 --- a/godot/thirdparty/libdatachannel/src/impl/wstransport.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) 2020-2021 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_IMPL_WS_TRANSPORT_H -#define RTC_IMPL_WS_TRANSPORT_H - -#include "common.hpp" -#include "transport.hpp" -#include "wshandshake.hpp" - -#if RTC_ENABLE_WEBSOCKET - -#include - -namespace rtc::impl { - -class HttpProxyTransport; -class TcpTransport; -class TlsTransport; - -class WsTransport final : public Transport, public std::enable_shared_from_this { -public: - WsTransport( - variant, shared_ptr, shared_ptr> - lower, - shared_ptr handshake, int maxOutstandingPings, message_callback recvCallback, - state_callback stateCallback); - ~WsTransport(); - - void start() override; - void stop() override; - bool send(message_ptr message) override; - void close(); - void incoming(message_ptr message) override; - - bool isClient() const { return mIsClient; } - -private: - enum Opcode : uint8_t { - CONTINUATION = 0, - TEXT_FRAME = 1, - BINARY_FRAME = 2, - CLOSE = 8, - PING = 9, - PONG = 10, - }; - - struct Frame { - Opcode opcode = BINARY_FRAME; - byte *payload = nullptr; - size_t length = 0; - bool fin = true; - bool mask = true; - }; - - bool sendHttpRequest(); - bool sendHttpError(int code); - bool sendHttpResponse(); - - size_t readFrame(byte *buffer, size_t size, Frame &frame); - void recvFrame(const Frame &frame); - bool sendFrame(const Frame &frame); - - void addOutstandingPing(); - - const shared_ptr mHandshake; - const bool mIsClient; - const int mMaxOutstandingPings; - - binary mBuffer; - binary mPartial; - Opcode mPartialOpcode; - std::mutex mSendMutex; - int mOutstandingPings = 0; - std::atomic mCloseSent = false; -}; - -} // namespace rtc::impl - -#endif - -#endif diff --git a/godot/thirdparty/libdatachannel/src/message.cpp b/godot/thirdparty/libdatachannel/src/message.cpp deleted file mode 100644 index 39a9be2c..00000000 --- a/godot/thirdparty/libdatachannel/src/message.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "message.hpp" - -namespace rtc { - -message_ptr make_message(size_t size, Message::Type type, unsigned int stream, - shared_ptr reliability) { - auto message = std::make_shared(size, type); - message->stream = stream; - message->reliability = reliability; - return message; -} - -message_ptr make_message(binary &&data, Message::Type type, unsigned int stream, - shared_ptr reliability) { - auto message = std::make_shared(std::move(data), type); - message->stream = stream; - message->reliability = reliability; - return message; -} - -message_ptr make_message(message_variant data) { - return std::visit( // - overloaded{ - [&](binary data) { return make_message(std::move(data), Message::Binary); }, - [&](string data) { - auto b = reinterpret_cast(data.data()); - return make_message(b, b + data.size(), Message::String); - }, - }, - std::move(data)); -} - -#if RTC_ENABLE_MEDIA - -message_ptr make_message_from_opaque_ptr(rtcMessage *&&message) { - auto ptr = std::unique_ptr(reinterpret_cast(message)); - return message_ptr(std::move(ptr)); -} - -#endif - -message_variant to_variant(Message &&message) { - switch (message.type) { - case Message::String: - return string(reinterpret_cast(message.data()), message.size()); - default: - return std::move(message); - } -} - -message_variant to_variant(const Message &message) { - switch (message.type) { - case Message::String: - return string(reinterpret_cast(message.data()), message.size()); - default: - return message; - } -} - -} // namespace rtc diff --git a/godot/thirdparty/libdatachannel/src/peerconnection.cpp b/godot/thirdparty/libdatachannel/src/peerconnection.cpp deleted file mode 100644 index 7c5e17d1..00000000 --- a/godot/thirdparty/libdatachannel/src/peerconnection.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "peerconnection.hpp" -#include "common.hpp" -#include "rtp.hpp" - -#include "impl/certificate.hpp" -#include "impl/dtlstransport.hpp" -#include "impl/icetransport.hpp" -#include "impl/internals.hpp" -#include "impl/peerconnection.hpp" -#include "impl/sctptransport.hpp" -#include "impl/threadpool.hpp" -#include "impl/track.hpp" - -#if RTC_ENABLE_MEDIA -#include "impl/dtlssrtptransport.hpp" -#endif - -#include -#include -#include - -using namespace std::placeholders; - -namespace rtc { - -PeerConnection::PeerConnection() : PeerConnection(Configuration()) {} - -PeerConnection::PeerConnection(Configuration config) - : CheshireCat(std::move(config)) {} - -PeerConnection::~PeerConnection() { - impl()->remoteClose(); -} - -void PeerConnection::close() { impl()->close(); } - -const Configuration *PeerConnection::config() const { return &impl()->config; } - -PeerConnection::State PeerConnection::state() const { return impl()->state; } - -PeerConnection::IceState PeerConnection::iceState() const { return impl()->iceState; } - -PeerConnection::GatheringState PeerConnection::gatheringState() const { - return impl()->gatheringState; -} - -PeerConnection::SignalingState PeerConnection::signalingState() const { - return impl()->signalingState; -} - -optional PeerConnection::localDescription() const { - return impl()->localDescription(); -} - -optional PeerConnection::remoteDescription() const { - return impl()->remoteDescription(); -} - -bool PeerConnection::hasMedia() const { - auto local = localDescription(); - return local && local->hasAudioOrVideo(); -} - -RTC_WRAPPED(void) PeerConnection::setLocalDescription(Description::Type type) { - RTC_BEGIN; - std::unique_lock signalingLock(impl()->signalingMutex); - PLOG_VERBOSE << "Setting local description, type=" << Description::typeToString(type); - - SignalingState signalingState = impl()->signalingState.load(); - if (type == Description::Type::Rollback) { - if (signalingState == SignalingState::HaveLocalOffer || - signalingState == SignalingState::HaveLocalPranswer) { - impl()->rollbackLocalDescription(); - impl()->changeSignalingState(SignalingState::Stable); - } - RTC_RET; - } - - // Guess the description type if unspecified - if (type == Description::Type::Unspec) { - if (signalingState == SignalingState::HaveRemoteOffer) - type = Description::Type::Answer; - else - type = Description::Type::Offer; - } - - // Only a local offer resets the negotiation needed flag - if (type == Description::Type::Offer && !impl()->negotiationNeeded.exchange(false)) { - PLOG_DEBUG << "No negotiation needed"; - RTC_RET; - } - - // Get the new signaling state - SignalingState newSignalingState; - switch (signalingState) { - case SignalingState::Stable: - if (type != Description::Type::Offer) { - std::ostringstream oss; - oss << "Unexpected local desciption type " << type << " in signaling state " - << signalingState; - RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::HaveLocalOffer; - break; - - case SignalingState::HaveRemoteOffer: - case SignalingState::HaveLocalPranswer: - if (type != Description::Type::Answer && type != Description::Type::Pranswer) { - std::ostringstream oss; - oss << "Unexpected local description type " << type - << " description in signaling state " << signalingState; - RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::Stable; - break; - - default: { - std::ostringstream oss; - oss << "Unexpected local description in signaling state " << signalingState << ", ignoring"; - LOG_WARNING << oss.str(); - RTC_RET; - } - } - - RTC_UNWRAP_RETHROW_DECL(auto, iceTransport, impl()->initIceTransport()); - if (!iceTransport) - RTC_RET; // closed - - RTC_UNWRAP_RETHROW_DECL(Description, local, iceTransport->getLocalDescription(type)); - RTC_UNWRAP_RETHROW(impl()->processLocalDescription(std::move(local))); - - impl()->changeSignalingState(newSignalingState); - signalingLock.unlock(); - - if (impl()->gatheringState == GatheringState::New) { - RTC_UNWRAP_RETHROW(iceTransport->gatherLocalCandidates(impl()->localBundleMid())); - } - RTC_RET; -} - -RTC_WRAPPED(void) PeerConnection::setRemoteDescription(Description description) { - RTC_BEGIN; - std::unique_lock signalingLock(impl()->signalingMutex); - PLOG_VERBOSE << "Setting remote description: " << string(description); - - if (description.type() == Description::Type::Rollback) { - // This is mostly useless because we accept any offer - PLOG_VERBOSE << "Rolling back pending remote description"; - impl()->changeSignalingState(SignalingState::Stable); - RTC_RET; - } - - RTC_UNWRAP_RETHROW(impl()->validateRemoteDescription(description)); - - // Get the new signaling state - SignalingState signalingState = impl()->signalingState.load(); - SignalingState newSignalingState; - switch (signalingState) { - case SignalingState::Stable: - description.hintType(Description::Type::Offer); - if (description.type() != Description::Type::Offer) { - std::ostringstream oss; - oss << "Unexpected remote " << description.type() << " description in signaling state " - << signalingState; - RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::HaveRemoteOffer; - break; - - case SignalingState::HaveLocalOffer: - description.hintType(Description::Type::Answer); - if (description.type() == Description::Type::Offer) { - // The ICE agent will automatically initiate a rollback when a peer that had previously - // created an offer receives an offer from the remote peer - impl()->rollbackLocalDescription(); - impl()->changeSignalingState(SignalingState::Stable); - signalingState = SignalingState::Stable; - newSignalingState = SignalingState::HaveRemoteOffer; - break; - } - if (description.type() != Description::Type::Answer && - description.type() != Description::Type::Pranswer) { - std::ostringstream oss; - oss << "Unexpected remote " << description.type() << " description in signaling state " - << signalingState; - RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::Stable; - break; - - case SignalingState::HaveRemotePranswer: - description.hintType(Description::Type::Answer); - if (description.type() != Description::Type::Answer && - description.type() != Description::Type::Pranswer) { - std::ostringstream oss; - oss << "Unexpected remote " << description.type() << " description in signaling state " - << signalingState; - RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - newSignalingState = SignalingState::Stable; - break; - - default: { - std::ostringstream oss; - oss << "Unexpected remote description in signaling state " << signalingState; - RTC_THROW RTC_LOGIC_ERROR(oss.str()); - } - } - - // Candidates will be added at the end, extract them for now - auto remoteCandidates = description.extractCandidates(); - auto type = description.type(); - - RTC_UNWRAP_RETHROW_DECL(auto, iceTransport, impl()->initIceTransport()); - if (!iceTransport) - RTC_RET; // closed - - RTC_UNWRAP_RETHROW(iceTransport->setRemoteDescription(description)); // ICE transport might reject the description - - RTC_UNWRAP_RETHROW(impl()->processRemoteDescription(std::move(description))); - impl()->changeSignalingState(newSignalingState); - signalingLock.unlock(); - - if (type == Description::Type::Offer) { - // This is an offer, we need to answer - if (!impl()->config.disableAutoNegotiation) - RTC_UNWRAP_RETHROW(setLocalDescription(Description::Type::Answer)); - } - - for (const auto &candidate : remoteCandidates) - RTC_UNWRAP_RETHROW(addRemoteCandidate(candidate)); - RTC_RET; -} - -RTC_WRAPPED(void) PeerConnection::addRemoteCandidate(Candidate candidate) { - std::unique_lock signalingLock(impl()->signalingMutex); - PLOG_VERBOSE << "Adding remote candidate: " << string(candidate); - return impl()->processRemoteCandidate(std::move(candidate)); -} - -#if RTC_ENABLE_MEDIA -void PeerConnection::setMediaHandler(shared_ptr handler) { - impl()->setMediaHandler(std::move(handler)); -}; - -shared_ptr PeerConnection::getMediaHandler() { return impl()->getMediaHandler(); }; -#endif - -optional PeerConnection::localAddress() const { - auto iceTransport = impl()->getIceTransport(); - return iceTransport ? iceTransport->getLocalAddress() : nullopt; -} - -optional PeerConnection::remoteAddress() const { - auto iceTransport = impl()->getIceTransport(); - return iceTransport ? iceTransport->getRemoteAddress() : nullopt; -} - -uint16_t PeerConnection::maxDataChannelId() const { return impl()->maxDataChannelStream(); } - -RTC_WRAPPED(shared_ptr) PeerConnection::createDataChannel(string label, DataChannelInit init) { - RTC_BEGIN; - RTC_UNWRAP_RETHROW_DECL(auto, channelImpl, impl()->emplaceDataChannel(std::move(label), std::move(init))); - auto channel = std::make_shared(channelImpl); - - // Renegotiation is needed iff the current local description does not have application - auto local = impl()->localDescription(); - if (!local || !local->hasApplication()) - impl()->negotiationNeeded = true; - - if (!impl()->config.disableAutoNegotiation) - RTC_UNWRAP_RETHROW(setLocalDescription()); - - return channel; -} - -void PeerConnection::onDataChannel( - std::function dataChannel)> callback) { - impl()->dataChannelCallback = callback; - impl()->flushPendingDataChannels(); -} - -#if RTC_ENABLE_MEDIA -std::shared_ptr PeerConnection::addTrack(Description::Media description) { - auto trackImpl = impl()->emplaceTrack(std::move(description)); - auto track = std::make_shared(trackImpl); - - // Renegotiation is needed for the new or updated track - impl()->negotiationNeeded = true; - - return track; -} - -void PeerConnection::onTrack(std::function)> callback) { - impl()->trackCallback = callback; - impl()->flushPendingTracks(); -} -#endif - -void PeerConnection::onLocalDescription(std::function callback) { - impl()->localDescriptionCallback = callback; -} - -void PeerConnection::onLocalCandidate(std::function callback) { - impl()->localCandidateCallback = callback; -} - -void PeerConnection::onStateChange(std::function callback) { - impl()->stateChangeCallback = callback; -} - -void PeerConnection::onIceStateChange(std::function callback) { - impl()->iceStateChangeCallback = callback; -} - -void PeerConnection::onGatheringStateChange(std::function callback) { - impl()->gatheringStateChangeCallback = callback; -} - -void PeerConnection::onSignalingStateChange(std::function callback) { - impl()->signalingStateChangeCallback = callback; -} - -void PeerConnection::resetCallbacks() { impl()->resetCallbacks(); } - -RTC_WRAPPED(bool) PeerConnection::getSelectedCandidatePair(Candidate *local, Candidate *remote) { - RTC_BEGIN; - auto iceTransport = impl()->getIceTransport(); - if (iceTransport) { - RTC_UNWRAP_RETHROW(iceTransport->getSelectedCandidatePair(local, remote)); - } - return false; -} - -void PeerConnection::clearStats() { - if (auto sctpTransport = impl()->getSctpTransport()) - return sctpTransport->clearStats(); -} - -size_t PeerConnection::bytesSent() { - auto sctpTransport = impl()->getSctpTransport(); - return sctpTransport ? sctpTransport->bytesSent() : 0; -} - -size_t PeerConnection::bytesReceived() { - auto sctpTransport = impl()->getSctpTransport(); - return sctpTransport ? sctpTransport->bytesReceived() : 0; -} - -optional PeerConnection::rtt() { - auto sctpTransport = impl()->getSctpTransport(); - return sctpTransport ? sctpTransport->rtt() : nullopt; -} - -} // namespace rtc - -std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::State state) { - using State = rtc::PeerConnection::State; - const char *str; - switch (state) { - case State::New: - str = "new"; - break; - case State::Connecting: - str = "connecting"; - break; - case State::Connected: - str = "connected"; - break; - case State::Disconnected: - str = "disconnected"; - break; - case State::Failed: - str = "failed"; - break; - case State::Closed: - str = "closed"; - break; - default: - str = "unknown"; - break; - } - return out << str; -} - -std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::IceState state) { - using IceState = rtc::PeerConnection::IceState; - const char *str; - switch (state) { - case IceState::New: - str = "new"; - break; - case IceState::Checking: - str = "checking"; - break; - case IceState::Connected: - str = "connected"; - break; - case IceState::Completed: - str = "completed"; - break; - case IceState::Failed: - str = "failed"; - break; - case IceState::Disconnected: - str = "disconnected"; - break; - case IceState::Closed: - str = "closed"; - break; - default: - str = "unknown"; - break; - } - return out << str; -} - -std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::GatheringState state) { - using GatheringState = rtc::PeerConnection::GatheringState; - const char *str; - switch (state) { - case GatheringState::New: - str = "new"; - break; - case GatheringState::InProgress: - str = "in-progress"; - break; - case GatheringState::Complete: - str = "complete"; - break; - default: - str = "unknown"; - break; - } - return out << str; -} - -std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::SignalingState state) { - using SignalingState = rtc::PeerConnection::SignalingState; - const char *str; - switch (state) { - case SignalingState::Stable: - str = "stable"; - break; - case SignalingState::HaveLocalOffer: - str = "have-local-offer"; - break; - case SignalingState::HaveRemoteOffer: - str = "have-remote-offer"; - break; - case SignalingState::HaveLocalPranswer: - str = "have-local-pranswer"; - break; - case SignalingState::HaveRemotePranswer: - str = "have-remote-pranswer"; - break; - default: - str = "unknown"; - break; - } - return out << str; -} diff --git a/godot/thirdparty/linuxbsd_headers/alsa/asoundlib.h b/godot/thirdparty/linuxbsd_headers/alsa/asoundlib.h index a5461943..59817540 100644 --- a/godot/thirdparty/linuxbsd_headers/alsa/asoundlib.h +++ b/godot/thirdparty/linuxbsd_headers/alsa/asoundlib.h @@ -38,7 +38,11 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#else #include +#endif // __FreeBSD__ #ifndef __GNUC__ #define __inline__ inline diff --git a/godot/thirdparty/linuxbsd_headers/alsa/patches/freebsd_endian.diff b/godot/thirdparty/linuxbsd_headers/alsa/patches/freebsd_endian.diff new file mode 100644 index 00000000..f104d9df --- /dev/null +++ b/godot/thirdparty/linuxbsd_headers/alsa/patches/freebsd_endian.diff @@ -0,0 +1,16 @@ +diff --git a/thirdparty/linuxbsd_headers/alsa/asoundlib.h b/thirdparty/linuxbsd_headers/alsa/asoundlib.h +index a546194382..598175403c 100644 +--- a/thirdparty/linuxbsd_headers/alsa/asoundlib.h ++++ b/thirdparty/linuxbsd_headers/alsa/asoundlib.h +@@ -38,7 +38,11 @@ + #include + #include + #include ++#ifdef __FreeBSD__ ++#include ++#else + #include ++#endif // __FreeBSD__ + + #ifndef __GNUC__ + #define __inline__ inline diff --git a/godot/thirdparty/misc/patches/qoa-min-fix.patch b/godot/thirdparty/misc/patches/qoa-min-fix.patch deleted file mode 100644 index 6008b5f8..00000000 --- a/godot/thirdparty/misc/patches/qoa-min-fix.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff --git a/qoa.h b/qoa.h -index cfed266bef..23612bb0bf 100644 ---- a/qoa.h -+++ b/qoa.h -@@ -140,14 +140,14 @@ typedef struct { - #endif - } qoa_desc; - --unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes); --unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes); --void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len); -+inline unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes); -+inline unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes); -+inline void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len); - --unsigned int qoa_max_frame_size(qoa_desc *qoa); --unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa); --unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len); --short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file); -+inline unsigned int qoa_max_frame_size(qoa_desc *qoa); -+inline unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa); -+inline unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len); -+inline short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file); - - #ifndef QOA_NO_STDIO - -@@ -395,7 +395,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned - qoa_uint64_t best_error = -1; - #endif - qoa_uint64_t best_slice = 0; -- qoa_lms_t best_lms; -+ qoa_lms_t best_lms = {}; - int best_scalefactor = 0; - - for (int sfi = 0; sfi < 16; sfi++) { -@@ -500,7 +500,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) - num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */ - num_slices * 8 * qoa->channels; /* 8 byte slices */ - -- unsigned char *bytes = QOA_MALLOC(encoded_size); -+ unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size); - - for (unsigned int c = 0; c < qoa->channels; c++) { - /* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the -@@ -655,7 +655,7 @@ short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) { - - /* Calculate the required size of the sample buffer and allocate */ - int total_samples = qoa->samples * qoa->channels; -- short *sample_data = QOA_MALLOC(total_samples * sizeof(short)); -+ short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short)); - - unsigned int sample_index = 0; - unsigned int frame_len; diff --git a/godot/thirdparty/misc/qoa.c b/godot/thirdparty/misc/qoa.c new file mode 100644 index 00000000..7f7d366d --- /dev/null +++ b/godot/thirdparty/misc/qoa.c @@ -0,0 +1,4 @@ +#define QOA_IMPLEMENTATION +#define QOA_NO_STDIO + +#include "qoa.h" diff --git a/godot/thirdparty/misc/qoa.h b/godot/thirdparty/misc/qoa.h index 23612bb0..f0f44214 100644 --- a/godot/thirdparty/misc/qoa.h +++ b/godot/thirdparty/misc/qoa.h @@ -140,14 +140,14 @@ typedef struct { #endif } qoa_desc; -inline unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes); -inline unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes); -inline void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len); +unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes); +unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes); +void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len); -inline unsigned int qoa_max_frame_size(qoa_desc *qoa); -inline unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa); -inline unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len); -inline short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file); +unsigned int qoa_max_frame_size(qoa_desc *qoa); +unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa); +unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len); +short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file); #ifndef QOA_NO_STDIO @@ -395,7 +395,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned qoa_uint64_t best_error = -1; #endif qoa_uint64_t best_slice = 0; - qoa_lms_t best_lms = {}; + qoa_lms_t best_lms; int best_scalefactor = 0; for (int sfi = 0; sfi < 16; sfi++) { @@ -500,7 +500,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */ num_slices * 8 * qoa->channels; /* 8 byte slices */ - unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size); + unsigned char *bytes = QOA_MALLOC(encoded_size); for (unsigned int c = 0; c < qoa->channels; c++) { /* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the @@ -626,12 +626,14 @@ unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa qoa_uint64_t slice = qoa_read_u64(bytes, &p); int scalefactor = (slice >> 60) & 0xf; + slice <<= 4; + int slice_start = sample_index * channels + c; int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c; for (int si = slice_start; si < slice_end; si += channels) { int predicted = qoa_lms_predict(&qoa->lms[c]); - int quantized = (slice >> 57) & 0x7; + int quantized = (slice >> 61) & 0x7; int dequantized = qoa_dequant_tab[scalefactor][quantized]; int reconstructed = qoa_clamp_s16(predicted + dequantized); @@ -655,7 +657,7 @@ short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) { /* Calculate the required size of the sample buffer and allocate */ int total_samples = qoa->samples * qoa->channels; - short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short)); + short *sample_data = QOA_MALLOC(total_samples * sizeof(short)); unsigned int sample_index = 0; unsigned int frame_len; diff --git a/godot/thirdparty/thorvg/inc/config.h b/godot/thirdparty/thorvg/inc/config.h index da87707c..6df6f52d 100644 --- a/godot/thirdparty/thorvg/inc/config.h +++ b/godot/thirdparty/thorvg/inc/config.h @@ -15,5 +15,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.15.3" +#define THORVG_VERSION_STRING "0.15.5" #endif diff --git a/godot/thirdparty/thorvg/inc/thorvg.h b/godot/thirdparty/thorvg/inc/thorvg.h index 28bd7602..1ee898ca 100644 --- a/godot/thirdparty/thorvg/inc/thorvg.h +++ b/godot/thirdparty/thorvg/inc/thorvg.h @@ -216,7 +216,8 @@ enum class BlendMethod : uint8_t enum class SceneEffect : uint8_t { ClearAll = 0, ///< Reset all previously applied scene effects, restoring the scene to its original state. - GaussianBlur ///< Apply a blur effect with a Gaussian filter. Param(3) = {sigma(float)[> 0], direction(int)[both: 0 / horizontal: 1 / vertical: 2], border(int)[duplicate: 0 / wrap: 1], quality(int)[0 - 100]} + GaussianBlur, ///< Apply a blur effect with a Gaussian filter. Param(3) = {sigma(float)[> 0], direction(int)[both: 0 / horizontal: 1 / vertical: 2], border(int)[duplicate: 0 / wrap: 1], quality(int)[0 - 100]} + DropShadow ///< Apply a drop shadow effect with a Gaussian Blur filter. Param(8) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255], angle(float)[0 - 360], distance(float), blur_sigma(float)[> 0], quality(int)[0 - 100]} }; diff --git a/godot/thirdparty/thorvg/patches/pr2740-renderer-crash-hotfix.patch b/godot/thirdparty/thorvg/patches/pr2740-renderer-crash-hotfix.patch new file mode 100644 index 00000000..50b1e1e4 --- /dev/null +++ b/godot/thirdparty/thorvg/patches/pr2740-renderer-crash-hotfix.patch @@ -0,0 +1,45 @@ +From 8009c75465e5b35da2d5f53532bc65f6df202a3a Mon Sep 17 00:00:00 2001 +From: Hermet Park +Date: Tue, 17 Sep 2024 11:35:48 +0900 +Subject: [PATCH] renderer: hotfix a crash + +prevent a nullptr memory access +regression by f5337015e971d24379d2ee664895503ab8945e13 + +issue: https://github.com/godotengine/godot/issues/97078 +--- + src/renderer/tvgShape.h | 6 ++++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/renderer/tvgShape.h b/src/renderer/tvgShape.h +index 221931dee..e120a85c6 100644 +--- a/src/renderer/tvgShape.h ++++ b/src/renderer/tvgShape.h +@@ -51,8 +51,9 @@ struct Shape::Impl + + bool render(RenderMethod* renderer) + { ++ if (!rd) return false; ++ + Compositor* cmp = nullptr; +- bool ret; + + renderer->blend(shape->blend()); + +@@ -61,7 +62,7 @@ struct Shape::Impl + renderer->beginComposite(cmp, CompositeMethod::None, opacity); + } + +- ret = renderer->renderShape(rd); ++ auto ret = renderer->renderShape(rd); + if (cmp) renderer->endComposite(cmp); + return ret; + } +@@ -117,6 +118,7 @@ struct Shape::Impl + + RenderRegion bounds(RenderMethod* renderer) + { ++ if (!rd) return {0, 0, 0, 0}; + return renderer->region(rd); + } + diff --git a/godot/thirdparty/thorvg/patches/revert-tvgLines-bezier-precision-change.patch b/godot/thirdparty/thorvg/patches/revert-tvgLines-bezier-precision-change.patch new file mode 100644 index 00000000..dd6c8ba5 --- /dev/null +++ b/godot/thirdparty/thorvg/patches/revert-tvgLines-bezier-precision-change.patch @@ -0,0 +1,13 @@ +diff --git a/thirdparty/thorvg/src/common/tvgLines.cpp b/thirdparty/thorvg/src/common/tvgLines.cpp +index 49d992f127..9d704900a5 100644 +--- a/thirdparty/thorvg/src/common/tvgLines.cpp ++++ b/thirdparty/thorvg/src/common/tvgLines.cpp +@@ -79,7 +79,7 @@ float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc + Bezier left; + bezSplitLeft(right, t, left); + length = _bezLength(left, lineLengthFunc); +- if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < 1e-3f) { ++ if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) { + break; + } + if (length < at) { diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/allocators.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/allocators.h deleted file mode 100644 index 35650aff..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/allocators.h +++ /dev/null @@ -1,693 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ALLOCATORS_H_ -#define RAPIDJSON_ALLOCATORS_H_ - -#include "rapidjson.h" -#include "internal/meta.h" - -#include -#include - -#if RAPIDJSON_HAS_CXX11 -#include -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Allocator - -/*! \class rapidjson::Allocator - \brief Concept for allocating, resizing and freeing memory block. - - Note that Malloc() and Realloc() are non-static but Free() is static. - - So if an allocator need to support Free(), it needs to put its pointer in - the header of memory block. - -\code -concept Allocator { - static const bool kNeedFree; //!< Whether this allocator needs to call Free(). - - // Allocate a memory block. - // \param size of the memory block in bytes. - // \returns pointer to the memory block. - void* Malloc(size_t size); - - // Resize a memory block. - // \param originalPtr The pointer to current memory block. Null pointer is permitted. - // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) - // \param newSize the new size in bytes. - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); - - // Free a memory block. - // \param pointer to the memory block. Null pointer is permitted. - static void Free(void *ptr); -}; -\endcode -*/ - - -/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY - \ingroup RAPIDJSON_CONFIG - \brief User-defined kDefaultChunkCapacity definition. - - User can define this as any \c size that is a power of 2. -*/ - -#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY -#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// CrtAllocator - -//! C-runtime library allocator. -/*! This class is just wrapper for standard C library memory routines. - \note implements Allocator concept -*/ -class CrtAllocator { -public: - static const bool kNeedFree = true; - void* Malloc(size_t size) { - if (size) // behavior of malloc(0) is implementation defined. - return RAPIDJSON_MALLOC(size); - else - return NULL; // standardize to returning NULL. - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - (void)originalSize; - if (newSize == 0) { - RAPIDJSON_FREE(originalPtr); - return NULL; - } - return RAPIDJSON_REALLOC(originalPtr, newSize); - } - static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); } - - bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { - return true; - } - bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { - return false; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// MemoryPoolAllocator - -//! Default memory allocator used by the parser and DOM. -/*! This allocator allocate memory blocks from pre-allocated memory chunks. - - It does not free memory blocks. And Realloc() only allocate new memory. - - The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. - - User may also supply a buffer as the first chunk. - - If the user-buffer is full then additional chunks are allocated by BaseAllocator. - - The user-buffer is not deallocated by this allocator. - - \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. - \note implements Allocator concept -*/ -template -class MemoryPoolAllocator { - //! Chunk header for perpending to each chunk. - /*! Chunks are stored as a singly linked list. - */ - struct ChunkHeader { - size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). - size_t size; //!< Current size of allocated memory in bytes. - ChunkHeader *next; //!< Next chunk in the linked list. - }; - - struct SharedData { - ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation. - BaseAllocator* ownBaseAllocator; //!< base allocator created by this object. - size_t refcount; - bool ownBuffer; - }; - - static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData)); - static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader)); - - static inline ChunkHeader *GetChunkHead(SharedData *shared) - { - return reinterpret_cast(reinterpret_cast(shared) + SIZEOF_SHARED_DATA); - } - static inline uint8_t *GetChunkBuffer(SharedData *shared) - { - return reinterpret_cast(shared->chunkHead) + SIZEOF_CHUNK_HEADER; - } - - static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. - -public: - static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) - static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy - - //! Constructor with chunkSize. - /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - explicit - MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunk_capacity_(chunkSize), - baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()), - shared_(static_cast(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0)) - { - RAPIDJSON_ASSERT(baseAllocator_ != 0); - RAPIDJSON_ASSERT(shared_ != 0); - if (baseAllocator) { - shared_->ownBaseAllocator = 0; - } - else { - shared_->ownBaseAllocator = baseAllocator_; - } - shared_->chunkHead = GetChunkHead(shared_); - shared_->chunkHead->capacity = 0; - shared_->chunkHead->size = 0; - shared_->chunkHead->next = 0; - shared_->ownBuffer = true; - shared_->refcount = 1; - } - - //! Constructor with user-supplied buffer. - /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. - - The user buffer will not be deallocated when this allocator is destructed. - - \param buffer User supplied buffer. - \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). - \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunk_capacity_(chunkSize), - baseAllocator_(baseAllocator), - shared_(static_cast(AlignBuffer(buffer, size))) - { - RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER); - shared_->chunkHead = GetChunkHead(shared_); - shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER; - shared_->chunkHead->size = 0; - shared_->chunkHead->next = 0; - shared_->ownBaseAllocator = 0; - shared_->ownBuffer = false; - shared_->refcount = 1; - } - - MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : - chunk_capacity_(rhs.chunk_capacity_), - baseAllocator_(rhs.baseAllocator_), - shared_(rhs.shared_) - { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - ++shared_->refcount; - } - MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT - { - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - ++rhs.shared_->refcount; - this->~MemoryPoolAllocator(); - baseAllocator_ = rhs.baseAllocator_; - chunk_capacity_ = rhs.chunk_capacity_; - shared_ = rhs.shared_; - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : - chunk_capacity_(rhs.chunk_capacity_), - baseAllocator_(rhs.baseAllocator_), - shared_(rhs.shared_) - { - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - rhs.shared_ = 0; - } - MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT - { - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - this->~MemoryPoolAllocator(); - baseAllocator_ = rhs.baseAllocator_; - chunk_capacity_ = rhs.chunk_capacity_; - shared_ = rhs.shared_; - rhs.shared_ = 0; - return *this; - } -#endif - - //! Destructor. - /*! This deallocates all memory chunks, excluding the user-supplied buffer. - */ - ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT { - if (!shared_) { - // do nothing if moved - return; - } - if (shared_->refcount > 1) { - --shared_->refcount; - return; - } - Clear(); - BaseAllocator *a = shared_->ownBaseAllocator; - if (shared_->ownBuffer) { - baseAllocator_->Free(shared_); - } - RAPIDJSON_DELETE(a); - } - - //! Deallocates all memory chunks, excluding the first/user one. - void Clear() RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - for (;;) { - ChunkHeader* c = shared_->chunkHead; - if (!c->next) { - break; - } - shared_->chunkHead = c->next; - baseAllocator_->Free(c); - } - shared_->chunkHead->size = 0; - } - - //! Computes the total capacity of allocated memory chunks. - /*! \return total capacity in bytes. - */ - size_t Capacity() const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - size_t capacity = 0; - for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) - capacity += c->capacity; - return capacity; - } - - //! Computes the memory blocks allocated. - /*! \return total used bytes. - */ - size_t Size() const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - size_t size = 0; - for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) - size += c->size; - return size; - } - - //! Whether the allocator is shared. - /*! \return true or false. - */ - bool Shared() const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - return shared_->refcount > 1; - } - - //! Allocates a memory block. (concept Allocator) - void* Malloc(size_t size) { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - if (!size) - return NULL; - - size = RAPIDJSON_ALIGN(size); - if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity)) - if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) - return NULL; - - void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size; - shared_->chunkHead->size += size; - return buffer; - } - - //! Resizes a memory block (concept Allocator) - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - if (originalPtr == 0) - return Malloc(newSize); - - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - if (newSize == 0) - return NULL; - - originalSize = RAPIDJSON_ALIGN(originalSize); - newSize = RAPIDJSON_ALIGN(newSize); - - // Do not shrink if new size is smaller than original - if (originalSize >= newSize) - return originalPtr; - - // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) { - size_t increment = static_cast(newSize - originalSize); - if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) { - shared_->chunkHead->size += increment; - return originalPtr; - } - } - - // Realloc process: allocate and copy memory, do not free original buffer. - if (void* newBuffer = Malloc(newSize)) { - if (originalSize) - std::memcpy(newBuffer, originalPtr, originalSize); - return newBuffer; - } - else - return NULL; - } - - //! Frees a memory block (concept Allocator) - static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing - - //! Compare (equality) with another MemoryPoolAllocator - bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - return shared_ == rhs.shared_; - } - //! Compare (inequality) with another MemoryPoolAllocator - bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { - return !operator==(rhs); - } - -private: - //! Creates a new chunk. - /*! \param capacity Capacity of the chunk in bytes. - \return true if success. - */ - bool AddChunk(size_t capacity) { - if (!baseAllocator_) - shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); - if (ChunkHeader* chunk = static_cast(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) { - chunk->capacity = capacity; - chunk->size = 0; - chunk->next = shared_->chunkHead; - shared_->chunkHead = chunk; - return true; - } - else - return false; - } - - static inline void* AlignBuffer(void* buf, size_t &size) - { - RAPIDJSON_NOEXCEPT_ASSERT(buf != 0); - const uintptr_t mask = sizeof(void*) - 1; - const uintptr_t ubuf = reinterpret_cast(buf); - if (RAPIDJSON_UNLIKELY(ubuf & mask)) { - const uintptr_t abuf = (ubuf + mask) & ~mask; - RAPIDJSON_ASSERT(size >= abuf - ubuf); - buf = reinterpret_cast(abuf); - size -= abuf - ubuf; - } - return buf; - } - - size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. - BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. - SharedData *shared_; //!< The shared data of the allocator -}; - -namespace internal { - template - struct IsRefCounted : - public FalseType - { }; - template - struct IsRefCounted::Type> : - public TrueType - { }; -} - -template -inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) -{ - RAPIDJSON_NOEXCEPT_ASSERT(old_n <= (std::numeric_limits::max)() / sizeof(T) && new_n <= (std::numeric_limits::max)() / sizeof(T)); - return static_cast(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); -} - -template -inline T *Malloc(A& a, size_t n = 1) -{ - return Realloc(a, NULL, 0, n); -} - -template -inline void Free(A& a, T *p, size_t n = 1) -{ - static_cast(Realloc(a, p, n, 0)); -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited -#endif - -template -class StdAllocator : - public std::allocator -{ - typedef std::allocator allocator_type; -#if RAPIDJSON_HAS_CXX11 - typedef std::allocator_traits traits_type; -#else - typedef allocator_type traits_type; -#endif - -public: - typedef BaseAllocator BaseAllocatorType; - - StdAllocator() RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_() - { } - - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - - template - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(std::move(rhs)), - baseAllocator_(std::move(rhs.baseAllocator_)) - { } -#endif -#if RAPIDJSON_HAS_CXX11 - using propagate_on_container_move_assignment = std::true_type; - using propagate_on_container_swap = std::true_type; -#endif - - /* implicit */ - StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_(allocator) - { } - - ~StdAllocator() RAPIDJSON_NOEXCEPT - { } - - template - struct rebind { - typedef StdAllocator other; - }; - - typedef typename traits_type::size_type size_type; - typedef typename traits_type::difference_type difference_type; - - typedef typename traits_type::value_type value_type; - typedef typename traits_type::pointer pointer; - typedef typename traits_type::const_pointer const_pointer; - -#if RAPIDJSON_HAS_CXX11 - - typedef typename std::add_lvalue_reference::type &reference; - typedef typename std::add_lvalue_reference::type>::type &const_reference; - - pointer address(reference r) const RAPIDJSON_NOEXCEPT - { - return std::addressof(r); - } - const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT - { - return std::addressof(r); - } - - size_type max_size() const RAPIDJSON_NOEXCEPT - { - return traits_type::max_size(*this); - } - - template - void construct(pointer p, Args&&... args) - { - traits_type::construct(*this, p, std::forward(args)...); - } - void destroy(pointer p) - { - traits_type::destroy(*this, p); - } - -#else // !RAPIDJSON_HAS_CXX11 - - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - - pointer address(reference r) const RAPIDJSON_NOEXCEPT - { - return allocator_type::address(r); - } - const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT - { - return allocator_type::address(r); - } - - size_type max_size() const RAPIDJSON_NOEXCEPT - { - return allocator_type::max_size(); - } - - void construct(pointer p, const_reference r) - { - allocator_type::construct(p, r); - } - void destroy(pointer p) - { - allocator_type::destroy(p); - } - -#endif // !RAPIDJSON_HAS_CXX11 - - template - U* allocate(size_type n = 1, const void* = 0) - { - return RAPIDJSON_NAMESPACE::Malloc(baseAllocator_, n); - } - template - void deallocate(U* p, size_type n = 1) - { - RAPIDJSON_NAMESPACE::Free(baseAllocator_, p, n); - } - - pointer allocate(size_type n = 1, const void* = 0) - { - return allocate(n); - } - void deallocate(pointer p, size_type n = 1) - { - deallocate(p, n); - } - -#if RAPIDJSON_HAS_CXX11 - using is_always_equal = std::is_empty; -#endif - - template - bool operator==(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT - { - return baseAllocator_ == rhs.baseAllocator_; - } - template - bool operator!=(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT - { - return !operator==(rhs); - } - - //! rapidjson Allocator concept - static const bool kNeedFree = BaseAllocator::kNeedFree; - static const bool kRefCounted = internal::IsRefCounted::Value; - void* Malloc(size_t size) - { - return baseAllocator_.Malloc(size); - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) - { - return baseAllocator_.Realloc(originalPtr, originalSize, newSize); - } - static void Free(void *ptr) RAPIDJSON_NOEXCEPT - { - BaseAllocator::Free(ptr); - } - -private: - template - friend class StdAllocator; // access to StdAllocator.* - - BaseAllocator baseAllocator_; -}; - -#if !RAPIDJSON_HAS_CXX17 // std::allocator deprecated in C++17 -template -class StdAllocator : - public std::allocator -{ - typedef std::allocator allocator_type; - -public: - typedef BaseAllocator BaseAllocatorType; - - StdAllocator() RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_() - { } - - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - - template - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - - /* implicit */ - StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_(baseAllocator) - { } - - ~StdAllocator() RAPIDJSON_NOEXCEPT - { } - - template - struct rebind { - typedef StdAllocator other; - }; - - typedef typename allocator_type::value_type value_type; - -private: - template - friend class StdAllocator; // access to StdAllocator.* - - BaseAllocator baseAllocator_; -}; -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/cursorstreamwrapper.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/cursorstreamwrapper.h deleted file mode 100644 index fd6513db..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/cursorstreamwrapper.h +++ /dev/null @@ -1,78 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ -#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ - -#include "stream.h" - -#if defined(__GNUC__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4702) // unreachable code -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - - -//! Cursor stream wrapper for counting line and column number if error exists. -/*! - \tparam InputStream Any stream that implements Stream Concept -*/ -template > -class CursorStreamWrapper : public GenericStreamWrapper { -public: - typedef typename Encoding::Ch Ch; - - CursorStreamWrapper(InputStream& is): - GenericStreamWrapper(is), line_(1), col_(0) {} - - // counting line and column number - Ch Take() { - Ch ch = this->is_.Take(); - if(ch == '\n') { - line_ ++; - col_ = 0; - } else { - col_ ++; - } - return ch; - } - - //! Get the error line number, if error exists. - size_t GetLine() const { return line_; } - //! Get the error column number, if error exists. - size_t GetColumn() const { return col_; } - -private: - size_t line_; //!< Current Line - size_t col_; //!< Current Column -}; - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_POP -#endif - -#if defined(__GNUC__) -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/document.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/document.h deleted file mode 100644 index 1edb547c..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/document.h +++ /dev/null @@ -1,3043 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_DOCUMENT_H_ -#define RAPIDJSON_DOCUMENT_H_ - -/*! \file document.h */ - -#include "reader.h" -#include "internal/meta.h" -#include "internal/strfunc.h" -#include "memorystream.h" -#include "encodedstream.h" -#include // placement new -#include -#ifdef __cpp_lib_three_way_comparison -#include -#endif - -RAPIDJSON_DIAG_PUSH -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(c++98-compat) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_OFF(effc++) -#endif // __GNUC__ - -#ifdef GetObject -// see https://github.com/Tencent/rapidjson/issues/1448 -// a former included windows.h might have defined a macro called GetObject, which affects -// GetObject defined here. This ensures the macro does not get applied -#pragma push_macro("GetObject") -#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED -#undef GetObject -#endif - -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::random_access_iterator_tag -#endif - -#if RAPIDJSON_USE_MEMBERSMAP -#include // std::multimap -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -// Forward declaration. -template -class GenericValue; - -template -class GenericDocument; - -/*! \def RAPIDJSON_DEFAULT_ALLOCATOR - \ingroup RAPIDJSON_CONFIG - \brief Allows to choose default allocator. - - User can define this to use CrtAllocator or MemoryPoolAllocator. -*/ -#ifndef RAPIDJSON_DEFAULT_ALLOCATOR -#define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator> -#endif - -/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR - \ingroup RAPIDJSON_CONFIG - \brief Allows to choose default stack allocator for Document. - - User can define this to use CrtAllocator or MemoryPoolAllocator. -*/ -#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR -#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR ::RAPIDJSON_NAMESPACE::CrtAllocator -#endif - -/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY - \ingroup RAPIDJSON_CONFIG - \brief User defined kDefaultObjectCapacity value. - - User can define this as any natural number. -*/ -#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY -// number of objects that rapidjson::Value allocates memory for by default -#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16 -#endif - -/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY - \ingroup RAPIDJSON_CONFIG - \brief User defined kDefaultArrayCapacity value. - - User can define this as any natural number. -*/ -#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY -// number of array elements that rapidjson::Value allocates memory for by default -#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16 -#endif - -//! Name-value pair in a JSON object value. -/*! - This class was internal to GenericValue. It used to be a inner struct. - But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. - https://code.google.com/p/rapidjson/issues/detail?id=64 -*/ -template -class GenericMember { -public: - GenericValue name; //!< name of member (must be a string) - GenericValue value; //!< value of member. - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT - : name(std::move(rhs.name)), - value(std::move(rhs.value)) - { - } - - //! Move assignment in C++11 - GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT { - return *this = static_cast(rhs); - } -#endif - - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment. - */ - GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT { - if (RAPIDJSON_LIKELY(this != &rhs)) { - name = rhs.name; - value = rhs.value; - } - return *this; - } - - // swap() for std::sort() and other potential use in STL. - friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { - a.name.Swap(b.name); - a.value.Swap(b.value); - } - -private: - //! Copy constructor is not permitted. - GenericMember(const GenericMember& rhs); -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericMemberIterator - -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS - -//! (Constant) member iterator for a JSON object value -/*! - \tparam Const Is this a constant iterator? - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. - - This class implements a Random Access Iterator for GenericMember elements - of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. - - \note This iterator implementation is mainly intended to avoid implicit - conversions from iterator values to \c NULL, - e.g. from GenericValue::FindMember. - - \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a - pointer-based implementation, if your platform doesn't provide - the C++ header. - - \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator - */ -template -class GenericMemberIterator { - - friend class GenericValue; - template friend class GenericMemberIterator; - - typedef GenericMember PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - -public: - //! Iterator type itself - typedef GenericMemberIterator Iterator; - //! Constant iterator type - typedef GenericMemberIterator ConstIterator; - //! Non-constant iterator type - typedef GenericMemberIterator NonConstIterator; - - /** \name std::iterator_traits support */ - //@{ - typedef ValueType value_type; - typedef ValueType * pointer; - typedef ValueType & reference; - typedef std::ptrdiff_t difference_type; - typedef std::random_access_iterator_tag iterator_category; - //@} - - //! Pointer to (const) GenericMember - typedef pointer Pointer; - //! Reference to (const) GenericMember - typedef reference Reference; - //! Signed integer type (e.g. \c ptrdiff_t) - typedef difference_type DifferenceType; - - //! Default constructor (singular value) - /*! Creates an iterator pointing to no element. - \note All operations, except for comparisons, are undefined on such values. - */ - GenericMemberIterator() : ptr_() {} - - //! Iterator conversions to more const - /*! - \param it (Non-const) iterator to copy from - - Allows the creation of an iterator from another GenericMemberIterator - that is "less const". Especially, creating a non-constant iterator - from a constant iterator are disabled: - \li const -> non-const (not ok) - \li const -> const (ok) - \li non-const -> const (ok) - \li non-const -> non-const (ok) - - \note If the \c Const template parameter is already \c false, this - constructor effectively defines a regular copy-constructor. - Otherwise, the copy constructor is implicitly defined. - */ - GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} - Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } - - //! @name stepping - //@{ - Iterator& operator++(){ ++ptr_; return *this; } - Iterator& operator--(){ --ptr_; return *this; } - Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } - Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } - //@} - - //! @name increment/decrement - //@{ - Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } - Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } - - Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } - Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } - //@} - - //! @name relations - //@{ - template bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } - template bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } - template bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } - template bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } - template bool operator< (const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } - template bool operator> (const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } - -#ifdef __cpp_lib_three_way_comparison - template std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } -#endif - //@} - - //! @name dereference - //@{ - Reference operator*() const { return *ptr_; } - Pointer operator->() const { return ptr_; } - Reference operator[](DifferenceType n) const { return ptr_[n]; } - //@} - - //! Distance - DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } - -private: - //! Internal constructor from plain pointer - explicit GenericMemberIterator(Pointer p) : ptr_(p) {} - - Pointer ptr_; //!< raw pointer -}; - -#else // RAPIDJSON_NOMEMBERITERATORCLASS - -// class-based member iterator implementation disabled, use plain pointers - -template -class GenericMemberIterator; - -//! non-const GenericMemberIterator -template -class GenericMemberIterator { -public: - //! use plain pointer as iterator type - typedef GenericMember* Iterator; -}; -//! const GenericMemberIterator -template -class GenericMemberIterator { -public: - //! use plain const pointer as iterator type - typedef const GenericMember* Iterator; -}; - -#endif // RAPIDJSON_NOMEMBERITERATORCLASS - -/////////////////////////////////////////////////////////////////////////////// -// GenericStringRef - -//! Reference to a constant string (not taking a copy) -/*! - \tparam CharType character type of the string - - This helper class is used to automatically infer constant string - references for string literals, especially from \c const \b (!) - character arrays. - - The main use is for creating JSON string values without copying the - source string via an \ref Allocator. This requires that the referenced - string pointers have a sufficient lifetime, which exceeds the lifetime - of the associated GenericValue. - - \b Example - \code - Value v("foo"); // ok, no need to copy & calculate length - const char foo[] = "foo"; - v.SetString(foo); // ok - - const char* bar = foo; - // Value x(bar); // not ok, can't rely on bar's lifetime - Value x(StringRef(bar)); // lifetime explicitly guaranteed by user - Value y(StringRef(bar, 3)); // ok, explicitly pass length - \endcode - - \see StringRef, GenericValue::SetString -*/ -template -struct GenericStringRef { - typedef CharType Ch; //!< character type of the string - - //! Create string reference from \c const character array -#ifndef __clang__ // -Wdocumentation - /*! - This constructor implicitly creates a constant string reference from - a \c const character array. It has better performance than - \ref StringRef(const CharType*) by inferring the string \ref length - from the array length, and also supports strings containing null - characters. - - \tparam N length of the string, automatically inferred - - \param str Constant character array, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue - - \post \ref s == str - - \note Constant complexity. - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ -#endif - template - GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT - : s(str), length(N-1) {} - - //! Explicitly create string reference from \c const character pointer -#ifndef __clang__ // -Wdocumentation - /*! - This constructor can be used to \b explicitly create a reference to - a constant string pointer. - - \see StringRef(const CharType*) - - \param str Constant character pointer, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue - - \post \ref s == str - - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ -#endif - explicit GenericStringRef(const CharType* str) - : s(str), length(NotNullStrLen(str)) {} - - //! Create constant string reference from pointer and length -#ifndef __clang__ // -Wdocumentation - /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param len length of the string, excluding the trailing NULL terminator - - \post \ref s == str && \ref length == len - \note Constant complexity. - */ -#endif - GenericStringRef(const CharType* str, SizeType len) - : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } - - GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} - - //! implicit conversion to plain CharType pointer - operator const Ch *() const { return s; } - - const Ch* const s; //!< plain CharType pointer - const SizeType length; //!< length of the string (excluding the trailing NULL terminator) - -private: - SizeType NotNullStrLen(const CharType* str) { - RAPIDJSON_ASSERT(str != 0); - return internal::StrLen(str); - } - - /// Empty string - used when passing in a NULL pointer - static const Ch emptyString[]; - - //! Disallow construction from non-const array - template - GenericStringRef(CharType (&str)[N]) /* = delete */; - //! Copy assignment operator not permitted - immutable type - GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; -}; - -template -const CharType GenericStringRef::emptyString[] = { CharType() }; - -//! Mark a character pointer as constant string -/*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - \tparam CharType Character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef - - \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember -*/ -template -inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str); -} - -//! Mark a character pointer as constant string -/*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - - This version has better performance with supplied length, and also - supports string containing null characters. - - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param length The length of source string. - \return GenericStringRef string reference object - \relatesalso GenericStringRef -*/ -template -inline GenericStringRef StringRef(const CharType* str, size_t length) { - return GenericStringRef(str, SizeType(length)); -} - -#if RAPIDJSON_HAS_STDSTRING -//! Mark a string object as constant string -/*! Mark a string object (e.g. \c std::string) as a "string literal". - This function can be used to avoid copying a string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. -*/ -template -inline GenericStringRef StringRef(const std::basic_string& str) { - return GenericStringRef(str.data(), SizeType(str.size())); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -// GenericValue type traits -namespace internal { - -template -struct IsGenericValueImpl : FalseType {}; - -// select candidates according to nested encoding and allocator types -template struct IsGenericValueImpl::Type, typename Void::Type> - : IsBaseOf, T>::Type {}; - -// helper to match arbitrary GenericValue instantiations, including derived classes -template struct IsGenericValue : IsGenericValueImpl::Type {}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// TypeHelper - -namespace internal { - -template -struct TypeHelper {}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsBool(); } - static bool Get(const ValueType& v) { return v.GetBool(); } - static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } - static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static int Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; - -#ifdef _MSC_VER -RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static long Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; - -RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned long Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; -#endif - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt64(); } - static int64_t Get(const ValueType& v) { return v.GetInt64(); } - static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } - static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint64(); } - static uint64_t Get(const ValueType& v) { return v.GetUint64(); } - static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } - static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsDouble(); } - static double Get(const ValueType& v) { return v.GetDouble(); } - static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } - static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsFloat(); } - static float Get(const ValueType& v) { return v.GetFloat(); } - static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } - static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } -}; - -template -struct TypeHelper { - typedef const typename ValueType::Ch* StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return v.GetString(); } - static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } - static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; - -#if RAPIDJSON_HAS_STDSTRING -template -struct TypeHelper > { - typedef std::basic_string StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } - static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; -#endif - -template -struct TypeHelper { - typedef typename ValueType::Array ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(ValueType& v) { return v.GetArray(); } - static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } - static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } -}; - -template -struct TypeHelper { - typedef typename ValueType::ConstArray ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(const ValueType& v) { return v.GetArray(); } -}; - -template -struct TypeHelper { - typedef typename ValueType::Object ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(ValueType& v) { return v.GetObject(); } - static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } -}; - -template -struct TypeHelper { - typedef typename ValueType::ConstObject ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(const ValueType& v) { return v.GetObject(); } -}; - -} // namespace internal - -// Forward declarations -template class GenericArray; -template class GenericObject; - -/////////////////////////////////////////////////////////////////////////////// -// GenericValue - -//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. -/*! - A JSON value can be one of 7 types. This class is a variant type supporting - these types. - - Use the Value if UTF8 and default allocator - - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. -*/ -template -class GenericValue { -public: - //! Name-value pair in an object. - typedef GenericMember Member; - typedef Encoding EncodingType; //!< Encoding type from template parameter. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericStringRef StringRefType; //!< Reference to a constant string - typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. - typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. - typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. - typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. - typedef GenericValue ValueType; //!< Value type of itself. - typedef GenericArray Array; - typedef GenericArray ConstArray; - typedef GenericObject Object; - typedef GenericObject ConstObject; - - //!@name Constructors and destructor. - //@{ - - //! Default constructor creates a null value. - GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { - rhs.data_.f.flags = kNullFlag; // give up contents - } -#endif - -private: - //! Copy constructor is not permitted. - GenericValue(const GenericValue& rhs); - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Moving from a GenericDocument is not permitted. - template - GenericValue(GenericDocument&& rhs); - - //! Move assignment from a GenericDocument is not permitted. - template - GenericValue& operator=(GenericDocument&& rhs); -#endif - -public: - - //! Constructor with JSON value type. - /*! This creates a Value of specified type with default content. - \param type Type of the value. - \note Default content for number is zero. - */ - explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[] = { - kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, - kNumberAnyFlag - }; - RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); - data_.f.flags = defaultFlags[type]; - - // Use ShortString to store empty string. - if (type == kStringType) - data_.ss.SetLength(0); - } - - //! Explicit copy constructor (with allocator) - /*! Creates a copy of a Value by using the given Allocator - \tparam SourceAllocator allocator of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). - \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) - \see CopyFrom() - */ - template - GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { - switch (rhs.GetType()) { - case kObjectType: - DoCopyMembers(rhs, allocator, copyConstStrings); - break; - case kArrayType: { - SizeType count = rhs.data_.a.size; - GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); - const GenericValue* re = rhs.GetElementsPointer(); - for (SizeType i = 0; i < count; i++) - new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); - data_.f.flags = kArrayFlag; - data_.a.size = data_.a.capacity = count; - SetElementsPointer(le); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - } - else - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - break; - default: - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - break; - } - } - - //! Constructor for boolean value. - /*! \param b Boolean value - \note This constructor is limited to \em real boolean values and rejects - implicitly converted types like arbitrary pointers. Use an explicit cast - to \c bool, if you want to construct a boolean JSON value in such cases. - */ -#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen - template - explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 -#else - explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT -#endif - : data_() { - // safe-guard against failing SFINAE - RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); - data_.f.flags = b ? kTrueFlag : kFalseFlag; - } - - //! Constructor for int value. - explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i; - data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; - } - - //! Constructor for unsigned value. - explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u; - data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); - } - - //! Constructor for int64_t value. - explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i64; - data_.f.flags = kNumberInt64Flag; - if (i64 >= 0) { - data_.f.flags |= kNumberUint64Flag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - - //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u64; - data_.f.flags = kNumberUint64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) - data_.f.flags |= kInt64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - - //! Constructor for double value. - explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } - - //! Constructor for float value. - explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } - - //! Constructor for constant string (i.e. do not make a copy of string) - GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } - - //! Constructor for constant string (i.e. do not make a copy of string) - explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } - -#if RAPIDJSON_HAS_STDSTRING - //! Constructor for copy-string from a string object (i.e. do make a copy of string) - /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } -#endif - - //! Constructor for Array. - /*! - \param a An array obtained by \c GetArray(). - \note \c Array is always pass-by-value. - \note the source array is moved into this value and the source array becomes empty. - */ - GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { - a.value_.data_ = Data(); - a.value_.data_.f.flags = kArrayFlag; - } - - //! Constructor for Object. - /*! - \param o An object obtained by \c GetObject(). - \note \c Object is always pass-by-value. - \note the source object is moved into this value and the source object becomes empty. - */ - GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { - o.value_.data_ = Data(); - o.value_.data_.f.flags = kObjectFlag; - } - - //! Destructor. - /*! Need to destruct elements of array, members of object, or copy-string. - */ - ~GenericValue() { - // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release - // their Allocator if it's refcounted (e.g. MemoryPoolAllocator). - if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 && - internal::IsRefCounted::Value)) { - switch(data_.f.flags) { - case kArrayFlag: - { - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - Allocator::Free(e); - } - } - break; - - case kObjectFlag: - DoFreeMembers(); - break; - - case kCopyStringFlag: - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - Allocator::Free(const_cast(GetStringPointer())); - } - break; - - default: - break; // Do nothing for other types. - } - } - } - - //@} - - //!@name Assignment operators - //@{ - - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. It will become a null value after assignment. - */ - GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - if (RAPIDJSON_LIKELY(this != &rhs)) { - // Can't destroy "this" before assigning "rhs", otherwise "rhs" - // could be used after free if it's an sub-Value of "this", - // hence the temporary dance. - GenericValue temp; - temp.RawAssign(rhs); - this->~GenericValue(); - RawAssign(temp); - } - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { - return *this = rhs.Move(); - } -#endif - - //! Assignment of constant string reference (no copy) - /*! \param str Constant string reference to be assigned - \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. - \see GenericStringRef, operator=(T) - */ - GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { - GenericValue s(str); - return *this = s; - } - - //! Assignment with primitive types. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value The value to be assigned. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref SetString(const Ch*, Allocator&) (for copying) or - \ref StringRef() (to explicitly mark the pointer as constant) instead. - All other pointer types would implicitly convert to \c bool, - use \ref SetBool() instead. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) - operator=(T value) { - GenericValue v(value); - return *this = v; - } - - //! Deep-copy assignment from Value - /*! Assigns a \b copy of the Value to the current Value object - \tparam SourceAllocator Allocator type of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator to use for copying - \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) - */ - template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { - RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); - this->~GenericValue(); - new (this) GenericValue(rhs, allocator, copyConstStrings); - return *this; - } - - //! Exchange the contents of this value with those of other. - /*! - \param other Another value. - \note Constant complexity. - */ - GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { - GenericValue temp; - temp.RawAssign(*this); - RawAssign(other); - other.RawAssign(temp); - return *this; - } - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.value, b.value); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //! Prepare Value for move semantics - /*! \return *this */ - GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } - //@} - - //!@name Equal-to and not-equal-to operators - //@{ - //! Equal-to operator - /*! - \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). - */ - template - bool operator==(const GenericValue& rhs) const { - typedef GenericValue RhsType; - if (GetType() != rhs.GetType()) - return false; - - switch (GetType()) { - case kObjectType: // Warning: O(n^2) inner-loop - if (data_.o.size != rhs.data_.o.size) - return false; - for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { - typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); - if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) - return false; - } - return true; - - case kArrayType: - if (data_.a.size != rhs.data_.a.size) - return false; - for (SizeType i = 0; i < data_.a.size; i++) - if ((*this)[i] != rhs[i]) - return false; - return true; - - case kStringType: - return StringEqual(rhs); - - case kNumberType: - if (IsDouble() || rhs.IsDouble()) { - double a = GetDouble(); // May convert from integer to double. - double b = rhs.GetDouble(); // Ditto - return a >= b && a <= b; // Prevent -Wfloat-equal - } - else - return data_.n.u64 == rhs.data_.n.u64; - - default: - return true; - } - } - - //! Equal-to operator with const C-string pointer - bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } - -#if RAPIDJSON_HAS_STDSTRING - //! Equal-to operator with string object - /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } -#endif - - //! Equal-to operator with primitive types - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false - */ - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } - -#ifndef __cpp_impl_three_way_comparison - //! Not-equal-to operator - /*! \return !(*this == rhs) - */ - template - bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } - - //! Not-equal-to operator with const C-string pointer - bool operator!=(const Ch* rhs) const { return !(*this == rhs); } - - //! Not-equal-to operator with arbitrary types - /*! \return !(*this == rhs) - */ - template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } - - //! Equal-to operator with arbitrary types (symmetric version) - /*! \return (rhs == lhs) - */ - template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } - - //! Not-Equal-to operator with arbitrary types (symmetric version) - /*! \return !(rhs == lhs) - */ - template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } - //@} -#endif - - //!@name Type - //@{ - - Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } - bool IsNull() const { return data_.f.flags == kNullFlag; } - bool IsFalse() const { return data_.f.flags == kFalseFlag; } - bool IsTrue() const { return data_.f.flags == kTrueFlag; } - bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } - bool IsObject() const { return data_.f.flags == kObjectFlag; } - bool IsArray() const { return data_.f.flags == kArrayFlag; } - bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } - bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } - bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } - bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } - bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } - bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } - bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } - - // Checks whether a number can be losslessly converted to a double. - bool IsLosslessDouble() const { - if (!IsNumber()) return false; - if (IsUint64()) { - uint64_t u = GetUint64(); - volatile double d = static_cast(u); - return (d >= 0.0) - && (d < static_cast((std::numeric_limits::max)())) - && (u == static_cast(d)); - } - if (IsInt64()) { - int64_t i = GetInt64(); - volatile double d = static_cast(i); - return (d >= static_cast((std::numeric_limits::min)())) - && (d < static_cast((std::numeric_limits::max)())) - && (i == static_cast(d)); - } - return true; // double, int, uint are always lossless - } - - // Checks whether a number is a float (possible lossy). - bool IsFloat() const { - if ((data_.f.flags & kDoubleFlag) == 0) - return false; - double d = GetDouble(); - return d >= -3.4028234e38 && d <= 3.4028234e38; - } - // Checks whether a number can be losslessly converted to a float. - bool IsLosslessFloat() const { - if (!IsNumber()) return false; - double a = GetDouble(); - if (a < static_cast(-(std::numeric_limits::max)()) - || a > static_cast((std::numeric_limits::max)())) - return false; - double b = static_cast(static_cast(a)); - return a >= b && a <= b; // Prevent -Wfloat-equal - } - - //@} - - //!@name Null - //@{ - - GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } - - //@} - - //!@name Bool - //@{ - - bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } - //!< Set boolean value - /*! \post IsBool() == true */ - GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } - - //@} - - //!@name Object - //@{ - - //! Set this value as an empty object. - /*! \post IsObject() == true */ - GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } - - //! Get the number of members in the object. - SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } - - //! Get the capacity of object. - SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } - - //! Check whether the object is empty. - bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } - - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) - \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. - Since 0.2, if the name is not correct, it will assert. - If user is unsure whether a member exists, user should use HasMember() first. - A better approach is to use FindMember(). - \note Linear time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { - GenericValue n(StringRef(name)); - return (*this)[n]; - } - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } - - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam SourceAllocator Allocator of the \c name value - - \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). - And it can also handle strings with embedded null characters. - - \note Linear time complexity. - */ - template - GenericValue& operator[](const GenericValue& name) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value; - else { - RAPIDJSON_ASSERT(false); // see above note - -#if RAPIDJSON_HAS_CXX11 - // Use thread-local storage to prevent races between threads. - // Use static buffer and placement-new to prevent destruction, with - // alignas() to ensure proper alignment. - alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)]; - return *new (buffer) GenericValue(); -#elif defined(_MSC_VER) && _MSC_VER < 1900 - // There's no way to solve both thread locality and proper alignment - // simultaneously. - __declspec(thread) static char buffer[sizeof(GenericValue)]; - return *new (buffer) GenericValue(); -#elif defined(__GNUC__) || defined(__clang__) - // This will generate -Wexit-time-destructors in clang, but that's - // better than having under-alignment. - __thread static GenericValue buffer; - return buffer; -#else - // Don't know what compiler this is, so don't know how to ensure - // thread-locality. - static GenericValue buffer; - return buffer; -#endif - } - } - template - const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } - -#if RAPIDJSON_HAS_STDSTRING - //! Get a value from an object associated with name (string object). - GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } - const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } -#endif - - //! Const member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } - //! Const \em past-the-end member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } - //! Member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } - //! \em Past-the-end member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } - - //! Request the object to have enough capacity to store members. - /*! \param newCapacity The capacity that the object at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { - RAPIDJSON_ASSERT(IsObject()); - DoReserveMembers(newCapacity, allocator); - return *this; - } - - //! Check whether a member exists in the object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } - -#if RAPIDJSON_HAS_STDSTRING - //! Check whether a member exists in the object with string object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } -#endif - - //! Check whether a member exists in the object with GenericValue name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - template - bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } - - //! Find member by name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - MemberIterator FindMember(const Ch* name) { - GenericValue n(StringRef(name)); - return FindMember(n); - } - - ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } - - //! Find member by name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - template - MemberIterator FindMember(const GenericValue& name) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - return DoFindMember(name); - } - template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } - -#if RAPIDJSON_HAS_STDSTRING - //! Find member by string object name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - */ - MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } - ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } -#endif - - //! Add a member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c name and \c value will be transferred to this object on success. - \pre IsObject() && name.IsString() - \post name.IsNull() && value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - DoAddMember(name, value, allocator); - return *this; - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Add a string object as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { - GenericValue v(value, allocator); - return AddMember(name, v, allocator); - } -#endif - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A string value as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(GenericValue& name, T value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - - - //! Add a member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this object on success. - \pre IsObject() - \post value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A constant string reference as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(StringRefType name, T value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Remove all members in the object. - /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void RemoveAllMembers() { - RAPIDJSON_ASSERT(IsObject()); - DoClearMembers(); - } - - //! Remove a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Linear time complexity. - */ - bool RemoveMember(const Ch* name) { - GenericValue n(StringRef(name)); - return RemoveMember(n); - } - -#if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } -#endif - - template - bool RemoveMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - RemoveMember(m); - return true; - } - else - return false; - } - - //! Remove a member in object by iterator. - /*! \param m member iterator (obtained by FindMember() or MemberBegin()). - \return the new iterator after removal. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Constant time complexity. - */ - MemberIterator RemoveMember(MemberIterator m) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(GetMembersPointer() != 0); - RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - return DoRemoveMember(m); - } - - //! Remove a member from an object by iterator. - /*! \param pos iterator to the member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() - \return Iterator following the removed element. - If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. - \note This function preserves the relative order of the remaining object - members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator pos) { - return EraseMember(pos, pos +1); - } - - //! Remove members in the range [first, last) from an object. - /*! \param first iterator to the first member to remove - \param last iterator following the last member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() - \return Iterator following the last removed element. - \note This function preserves the relative order of the remaining object - members. - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(GetMembersPointer() != 0); - RAPIDJSON_ASSERT(first >= MemberBegin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= MemberEnd()); - return DoEraseMembers(first, last); - } - - //! Erase a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note Linear time complexity. - */ - bool EraseMember(const Ch* name) { - GenericValue n(StringRef(name)); - return EraseMember(n); - } - -#if RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } -#endif - - template - bool EraseMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - EraseMember(m); - return true; - } - else - return false; - } - - Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } - ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } - - //@} - - //!@name Array - //@{ - - //! Set this value as an empty array. - /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } - - //! Get the number of elements in array. - SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } - - //! Get the capacity of array. - SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } - - //! Check whether the array is empty. - bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } - - //! Remove all elements in the array. - /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void Clear() { - RAPIDJSON_ASSERT(IsArray()); - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - data_.a.size = 0; - } - - //! Get an element from array by index. - /*! \pre IsArray() == true - \param index Zero-based index of element. - \see operator[](T*) - */ - GenericValue& operator[](SizeType index) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(index < data_.a.size); - return GetElementsPointer()[index]; - } - const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } - - //! Element iterator - /*! \pre IsArray() == true */ - ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } - //! \em Past-the-end element iterator - /*! \pre IsArray() == true */ - ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } - //! Constant element iterator - /*! \pre IsArray() == true */ - ConstValueIterator Begin() const { return const_cast(*this).Begin(); } - //! Constant \em past-the-end element iterator - /*! \pre IsArray() == true */ - ConstValueIterator End() const { return const_cast(*this).End(); } - - //! Request the array to have enough capacity to store elements. - /*! \param newCapacity The capacity that the array at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (newCapacity > data_.a.capacity) { - SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); - data_.a.capacity = newCapacity; - } - return *this; - } - - //! Append a GenericValue at the end of the array. - /*! \param value Value to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \post value.IsNull() == true - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this array on success. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - */ - GenericValue& PushBack(GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (data_.a.size >= data_.a.capacity) - Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); - GetElementsPointer()[data_.a.size++].RawAssign(value); - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { - return PushBack(value, allocator); - } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - - //! Append a constant string reference at the end of the array. - /*! \param value Constant string reference to be appended. - \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - \see GenericStringRef - */ - GenericValue& PushBack(StringRefType value, Allocator& allocator) { - return (*this).template PushBack(value, allocator); - } - - //! Append a primitive value at the end of the array. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value Value of primitive type T to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref PushBack(GenericValue&, Allocator&) or \ref - PushBack(StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - PushBack(T value, Allocator& allocator) { - GenericValue v(value); - return PushBack(v, allocator); - } - - //! Remove the last element in the array. - /*! - \note Constant time complexity. - */ - GenericValue& PopBack() { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(!Empty()); - GetElementsPointer()[--data_.a.size].~GenericValue(); - return *this; - } - - //! Remove an element of array by iterator. - /*! - \param pos iterator to the element to remove - \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() - \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator pos) { - return Erase(pos, pos + 1); - } - - //! Remove elements in the range [first, last) of the array. - /*! - \param first iterator to the first element to remove - \param last iterator following the last element to remove - \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() - \return Iterator following the last removed element. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(data_.a.size > 0); - RAPIDJSON_ASSERT(GetElementsPointer() != 0); - RAPIDJSON_ASSERT(first >= Begin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= End()); - ValueIterator pos = Begin() + (first - Begin()); - for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); - data_.a.size -= static_cast(last - first); - return pos; - } - - Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } - ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } - - //@} - - //!@name Number - //@{ - - int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } - - //! Get the value as double type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the conversion is lossless. - */ - double GetDouble() const { - RAPIDJSON_ASSERT(IsNumber()); - if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. - if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double - if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) - RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) - } - - //! Get the value as float type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the conversion is lossless. - */ - float GetFloat() const { - return static_cast(GetDouble()); - } - - GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } - GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } - GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } - GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } - GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } - - //@} - - //!@name String - //@{ - - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); } - - //! Get the length of string. - /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). - */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); } - - //! Set this value as a string without copying source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string pointer. - \param length The length of source string, excluding the trailing null terminator. - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == length - \see SetString(StringRefType) - */ - GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } - - //! Set this value as a string without copying source string. - /*! \param s source string reference - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == s.length - */ - GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } - - //! Set this value as a string by copying from source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string. - \param length The length of source string, excluding the trailing null terminator. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } - - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } - - //! Set this value as a string by copying from source string. - /*! \param s source string reference - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } - -#if RAPIDJSON_HAS_STDSTRING - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } -#endif - - //@} - - //!@name Array - //@{ - - //! Templated version for checking whether this value is type T. - /*! - \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string - */ - template - bool Is() const { return internal::TypeHelper::Is(*this); } - - template - T Get() const { return internal::TypeHelper::Get(*this); } - - template - T Get() { return internal::TypeHelper::Get(*this); } - - template - ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } - - template - ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } - - //@} - - //! Generate events of this value to a Handler. - /*! This function adopts the GoF visitor pattern. - Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. - It can also be used to deep clone this value via GenericDocument, which is also a Handler. - \tparam Handler type of handler. - \param handler An object implementing concept Handler. - */ - template - bool Accept(Handler& handler) const { - switch(GetType()) { - case kNullType: return handler.Null(); - case kFalseType: return handler.Bool(false); - case kTrueType: return handler.Bool(true); - - case kObjectType: - if (RAPIDJSON_UNLIKELY(!handler.StartObject())) - return false; - for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. - if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) - return false; - if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) - return false; - } - return handler.EndObject(data_.o.size); - - case kArrayType: - if (RAPIDJSON_UNLIKELY(!handler.StartArray())) - return false; - for (ConstValueIterator v = Begin(); v != End(); ++v) - if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) - return false; - return handler.EndArray(data_.a.size); - - case kStringType: - return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); - - default: - RAPIDJSON_ASSERT(GetType() == kNumberType); - if (IsDouble()) return handler.Double(data_.n.d); - else if (IsInt()) return handler.Int(data_.n.i.i); - else if (IsUint()) return handler.Uint(data_.n.u.u); - else if (IsInt64()) return handler.Int64(data_.n.i64); - else return handler.Uint64(data_.n.u64); - } - } - -private: - template friend class GenericValue; - template friend class GenericDocument; - - enum { - kBoolFlag = 0x0008, - kNumberFlag = 0x0010, - kIntFlag = 0x0020, - kUintFlag = 0x0040, - kInt64Flag = 0x0080, - kUint64Flag = 0x0100, - kDoubleFlag = 0x0200, - kStringFlag = 0x0400, - kCopyFlag = 0x0800, - kInlineStrFlag = 0x1000, - - // Initial flags of different types. - kNullFlag = kNullType, - // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types. - kTrueFlag = static_cast(kTrueType) | static_cast(kBoolFlag), - kFalseFlag = static_cast(kFalseType) | static_cast(kBoolFlag), - kNumberIntFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag), - kNumberUintFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag), - kNumberInt64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kInt64Flag), - kNumberUint64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kUint64Flag), - kNumberDoubleFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kDoubleFlag), - kNumberAnyFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag), - kConstStringFlag = static_cast(kStringType) | static_cast(kStringFlag), - kCopyStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag), - kShortStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag | kInlineStrFlag), - kObjectFlag = kObjectType, - kArrayFlag = kArrayType, - - kTypeMask = 0x07 - }; - - static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; - static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; - - struct Flag { -#if RAPIDJSON_48BITPOINTER_OPTIMIZATION - char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer -#elif RAPIDJSON_64BIT - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes -#else - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes -#endif - uint16_t flags; - }; - - struct String { - SizeType length; - SizeType hashcode; //!< reserved - const Ch* str; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars - // (excluding the terminating zero) and store a value to determine the length of the contained - // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string - // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as - // the string terminator as well. For getting the string length back from that value just use - // "MaxSize - str[LenPos]". - // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, - // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). - struct ShortString { - enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; - Ch str[MaxChars]; - - inline static bool Usable(SizeType len) { return (MaxSize >= len); } - inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } - inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } - }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - // By using proper binary layout, retrieval of different integer types do not need conversions. - union Number { -#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN - struct I { - int i; - char padding[4]; - }i; - struct U { - unsigned u; - char padding2[4]; - }u; -#else - struct I { - char padding[4]; - int i; - }i; - struct U { - char padding2[4]; - unsigned u; - }u; -#endif - int64_t i64; - uint64_t u64; - double d; - }; // 8 bytes - - struct ObjectData { - SizeType size; - SizeType capacity; - Member* members; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - struct ArrayData { - SizeType size; - SizeType capacity; - GenericValue* elements; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - union Data { - String s; - ShortString ss; - Number n; - ObjectData o; - ArrayData a; - Flag f; - }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION - - static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) { - return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str); - } - static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) { - return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length; - } - - RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } - RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } - RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } - RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } - RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } - RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } - -#if RAPIDJSON_USE_MEMBERSMAP - - struct MapTraits { - struct Less { - bool operator()(const Data& s1, const Data& s2) const { - SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2); - int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2)); - return cmp < 0 || (cmp == 0 && n1 < n2); - } - }; - typedef std::pair Pair; - typedef std::multimap > Map; - typedef typename Map::iterator Iterator; - }; - typedef typename MapTraits::Map Map; - typedef typename MapTraits::Less MapLess; - typedef typename MapTraits::Pair MapPair; - typedef typename MapTraits::Iterator MapIterator; - - // - // Layout of the members' map/array, re(al)located according to the needed capacity: - // - // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]} - // - // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed) - // - - static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) { - return RAPIDJSON_ALIGN(sizeof(Map*)) + - RAPIDJSON_ALIGN(sizeof(SizeType)) + - RAPIDJSON_ALIGN(capacity * sizeof(Member)) + - capacity * sizeof(MapIterator); - } - - static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) { - return *reinterpret_cast(reinterpret_cast(&map) + - RAPIDJSON_ALIGN(sizeof(Map*))); - } - - static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) { - return reinterpret_cast(reinterpret_cast(&map) + - RAPIDJSON_ALIGN(sizeof(Map*)) + - RAPIDJSON_ALIGN(sizeof(SizeType))); - } - - static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) { - return reinterpret_cast(reinterpret_cast(&map) + - RAPIDJSON_ALIGN(sizeof(Map*)) + - RAPIDJSON_ALIGN(sizeof(SizeType)) + - RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member))); - } - - static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) { - RAPIDJSON_ASSERT(members != 0); - return *reinterpret_cast(reinterpret_cast(members) - - RAPIDJSON_ALIGN(sizeof(SizeType)) - - RAPIDJSON_ALIGN(sizeof(Map*))); - } - - // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting.. - RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) { -#if RAPIDJSON_HAS_CXX11 - MapIterator ret = std::move(rhs); -#else - MapIterator ret = rhs; -#endif - rhs.~MapIterator(); - return ret; - } - - Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) { - Map **newMap = static_cast(allocator.Malloc(GetMapLayoutSize(newCapacity))); - GetMapCapacity(*newMap) = newCapacity; - if (!oldMap) { - *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator); - } - else { - *newMap = *oldMap; - size_t count = (*oldMap)->size(); - std::memcpy(static_cast(GetMapMembers(*newMap)), - static_cast(GetMapMembers(*oldMap)), - count * sizeof(Member)); - MapIterator *oldIt = GetMapIterators(*oldMap), - *newIt = GetMapIterators(*newMap); - while (count--) { - new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count])); - } - Allocator::Free(oldMap); - } - return *newMap; - } - - RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { - return GetMapMembers(DoReallocMap(0, capacity, allocator)); - } - - void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { - ObjectData& o = data_.o; - if (newCapacity > o.capacity) { - Member* oldMembers = GetMembersPointer(); - Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0, - *&newMap = DoReallocMap(oldMap, newCapacity, allocator); - RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap)); - o.capacity = newCapacity; - } - } - - template - MemberIterator DoFindMember(const GenericValue& name) { - if (Member* members = GetMembersPointer()) { - Map* &map = GetMap(members); - MapIterator mit = map->find(reinterpret_cast(name.data_)); - if (mit != map->end()) { - return MemberIterator(&members[mit->second]); - } - } - return MemberEnd(); - } - - void DoClearMembers() { - if (Member* members = GetMembersPointer()) { - Map* &map = GetMap(members); - MapIterator* mit = GetMapIterators(map); - for (SizeType i = 0; i < data_.o.size; i++) { - map->erase(DropMapIterator(mit[i])); - members[i].~Member(); - } - data_.o.size = 0; - } - } - - void DoFreeMembers() { - if (Member* members = GetMembersPointer()) { - GetMap(members)->~Map(); - for (SizeType i = 0; i < data_.o.size; i++) { - members[i].~Member(); - } - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - Map** map = &GetMap(members); - Allocator::Free(*map); - Allocator::Free(map); - } - } - } - -#else // !RAPIDJSON_USE_MEMBERSMAP - - RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { - return Malloc(allocator, capacity); - } - - void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { - ObjectData& o = data_.o; - if (newCapacity > o.capacity) { - Member* newMembers = Realloc(allocator, GetMembersPointer(), o.capacity, newCapacity); - RAPIDJSON_SETPOINTER(Member, o.members, newMembers); - o.capacity = newCapacity; - } - } - - template - MemberIterator DoFindMember(const GenericValue& name) { - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; - } - - void DoClearMembers() { - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; - } - - void DoFreeMembers() { - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); - } - -#endif // !RAPIDJSON_USE_MEMBERSMAP - - void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - ObjectData& o = data_.o; - if (o.size >= o.capacity) - DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator); - Member* members = GetMembersPointer(); - Member* m = members + o.size; - m->name.RawAssign(name); - m->value.RawAssign(value); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(members); - MapIterator* mit = GetMapIterators(map); - new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size))); -#endif - ++o.size; - } - - MemberIterator DoRemoveMember(MemberIterator m) { - ObjectData& o = data_.o; - Member* members = GetMembersPointer(); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(members); - MapIterator* mit = GetMapIterators(map); - SizeType mpos = static_cast(&*m - members); - map->erase(DropMapIterator(mit[mpos])); -#endif - MemberIterator last(members + (o.size - 1)); - if (o.size > 1 && m != last) { -#if RAPIDJSON_USE_MEMBERSMAP - new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members])); - mit[mpos]->second = mpos; -#endif - *m = *last; // Move the last one to this place - } - else { - m->~Member(); // Only one left, just destroy - } - --o.size; - return m; - } - - MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) { - ObjectData& o = data_.o; - MemberIterator beg = MemberBegin(), - pos = beg + (first - beg), - end = MemberEnd(); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(GetMembersPointer()); - MapIterator* mit = GetMapIterators(map); -#endif - for (MemberIterator itr = pos; itr != last; ++itr) { -#if RAPIDJSON_USE_MEMBERSMAP - map->erase(DropMapIterator(mit[itr - beg])); -#endif - itr->~Member(); - } -#if RAPIDJSON_USE_MEMBERSMAP - if (first != last) { - // Move remaining members/iterators - MemberIterator next = pos + (last - first); - for (MemberIterator itr = pos; next != end; ++itr, ++next) { - std::memcpy(static_cast(&*itr), &*next, sizeof(Member)); - SizeType mpos = static_cast(itr - beg); - new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg])); - mit[mpos]->second = mpos; - } - } -#else - std::memmove(static_cast(&*pos), &*last, - static_cast(end - last) * sizeof(Member)); -#endif - o.size -= static_cast(last - first); - return pos; - } - - template - void DoCopyMembers(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings) { - RAPIDJSON_ASSERT(rhs.GetType() == kObjectType); - - data_.f.flags = kObjectFlag; - SizeType count = rhs.data_.o.size; - Member* lm = DoAllocMembers(count, allocator); - const typename GenericValue::Member* rm = rhs.GetMembersPointer(); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(lm); - MapIterator* mit = GetMapIterators(map); -#endif - for (SizeType i = 0; i < count; i++) { - new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); - new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); -#if RAPIDJSON_USE_MEMBERSMAP - new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i))); -#endif - } - data_.o.size = data_.o.capacity = count; - SetMembersPointer(lm); - } - - // Initialize this value as array with initial data, without calling destructor. - void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { - data_.f.flags = kArrayFlag; - if (count) { - GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); - SetElementsPointer(e); - std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); - } - else - SetElementsPointer(0); - data_.a.size = data_.a.capacity = count; - } - - //! Initialize this value as object with initial data, without calling destructor. - void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { - data_.f.flags = kObjectFlag; - if (count) { - Member* m = DoAllocMembers(count, allocator); - SetMembersPointer(m); - std::memcpy(static_cast(m), members, count * sizeof(Member)); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(m); - MapIterator* mit = GetMapIterators(map); - for (SizeType i = 0; i < count; i++) { - new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i))); - } -#endif - } - else - SetMembersPointer(0); - data_.o.size = data_.o.capacity = count; - } - - //! Initialize this value as constant string, without calling destructor. - void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { - data_.f.flags = kConstStringFlag; - SetStringPointer(s); - data_.s.length = s.length; - } - - //! Initialize this value as copy string with initial data, without calling destructor. - void SetStringRaw(StringRefType s, Allocator& allocator) { - Ch* str = 0; - if (ShortString::Usable(s.length)) { - data_.f.flags = kShortStringFlag; - data_.ss.SetLength(s.length); - str = data_.ss.str; - } else { - data_.f.flags = kCopyStringFlag; - data_.s.length = s.length; - str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); - SetStringPointer(str); - } - std::memcpy(str, s, s.length * sizeof(Ch)); - str[s.length] = '\0'; - } - - //! Assignment without calling destructor - void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - data_ = rhs.data_; - // data_.f.flags = rhs.data_.f.flags; - rhs.data_.f.flags = kNullFlag; - } - - template - bool StringEqual(const GenericValue& rhs) const { - RAPIDJSON_ASSERT(IsString()); - RAPIDJSON_ASSERT(rhs.IsString()); - - const SizeType len1 = GetStringLength(); - const SizeType len2 = rhs.GetStringLength(); - if(len1 != len2) { return false; } - - const Ch* const str1 = GetString(); - const Ch* const str2 = rhs.GetString(); - if(str1 == str2) { return true; } // fast path for constant string - - return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); - } - - Data data_; -}; - -//! GenericValue with UTF8 encoding -typedef GenericValue > Value; - -/////////////////////////////////////////////////////////////////////////////// -// GenericDocument - -//! A document for parsing JSON text as DOM. -/*! - \note implements Handler concept - \tparam Encoding Encoding for both parsing and string storage. - \tparam Allocator Allocator for allocating memory for the DOM - \tparam StackAllocator Allocator for allocating memory for stack during parsing. - \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. -*/ -template -class GenericDocument : public GenericValue { -public: - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericValue ValueType; //!< Value type of the document. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter. - - //! Constructor - /*! Creates an empty document of specified type. - \param type Mandatory type of object to create. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - } - - //! Constructor - /*! Creates an empty document which type is Null. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(std::move(rhs.stack_)), - parseResult_(rhs.parseResult_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - } -#endif - - ~GenericDocument() { - // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType() - // runs last and may access its elements or members which would be freed - // with an allocator like MemoryPoolAllocator (CrtAllocator does not - // free its data when destroyed, but MemoryPoolAllocator does). - if (ownAllocator_) { - ValueType::SetNull(); - } - Destroy(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - { - // The cast to ValueType is necessary here, because otherwise it would - // attempt to call GenericValue's templated assignment operator. - ValueType::operator=(std::forward(rhs)); - - // Calling the destructor here would prematurely call stack_'s destructor - Destroy(); - - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = std::move(rhs.stack_); - parseResult_ = rhs.parseResult_; - - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - - return *this; - } -#endif - - //! Exchange the contents of this document with those of another. - /*! - \param rhs Another document. - \note Constant complexity. - \see GenericValue::Swap - */ - GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { - ValueType::Swap(rhs); - stack_.Swap(rhs.stack_); - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(parseResult_, rhs.parseResult_); - return *this; - } - - // Allow Swap with ValueType. - // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. - using ValueType::Swap; - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.doc, b.doc); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //! Populate this document by a generator which produces SAX events. - /*! \tparam Generator A functor with bool f(Handler) prototype. - \param g Generator functor which sends SAX events to the parameter. - \return The document itself for fluent API. - */ - template - GenericDocument& Populate(Generator& g) { - ClearStackOnExit scope(*this); - if (g(*this)) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } - - //!@name Parse from stream - //!@{ - - //! Parse JSON text from an input stream (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Encoding of input stream - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - GenericReader reader( - stack_.HasAllocator() ? &stack_.GetAllocator() : 0); - ClearStackOnExit scope(*this); - parseResult_ = reader.template Parse(is, *this); - if (parseResult_) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } - - //! Parse JSON text from an input stream - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - - //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - //!@} - - //!@name Parse in-place from mutable string - //!@{ - - //! Parse JSON text from a mutable string - /*! \tparam parseFlags Combination of \ref ParseFlag. - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - GenericInsituStringStream s(str); - return ParseStream(s); - } - - //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) - /*! \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); - } - //!@} - - //!@name Parse from read-only string - //!@{ - - //! Parse JSON text from a read-only string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \tparam SourceEncoding Transcoding from input Encoding - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - GenericStringStream s(str); - return ParseStream(s); - } - - //! Parse JSON text from a read-only string - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - - //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) - /*! \param str Read-only zero-terminated string to be parsed. - */ - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); - EncodedInputStream is(ms); - ParseStream(is); - return *this; - } - - template - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } - - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } - -#if RAPIDJSON_HAS_STDSTRING - template - GenericDocument& Parse(const std::basic_string& str) { - // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) - return Parse(str.c_str()); - } - - template - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str.c_str()); - } - - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str); - } -#endif // RAPIDJSON_HAS_STDSTRING - - //!@} - - //!@name Handling parse errors - //!@{ - - //! Whether a parse error has occurred in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseError() const { return parseResult_.Code(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } - - //! Implicit conversion to get the last parse result -#ifndef __clang // -Wdocumentation - /*! \return \ref ParseResult of the last parse operation - - \code - Document doc; - ParseResult ok = doc.Parse(json); - if (!ok) - printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); - \endcode - */ -#endif - operator ParseResult() const { return parseResult_; } - //!@} - - //! Get the allocator of this document. - Allocator& GetAllocator() { - RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } - - //! Get the capacity of stack in bytes. - size_t GetStackCapacity() const { return stack_.GetCapacity(); } - -private: - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} - ~ClearStackOnExit() { d_.ClearStack(); } - private: - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - GenericDocument& d_; - }; - - // callers of the following private Handler functions - // template friend class GenericReader; // for parsing - template friend class GenericValue; // for deep copying - -public: - // Implementation of Handler - bool Null() { new (stack_.template Push()) ValueType(); return true; } - bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } - bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } - bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } - - bool RawNumber(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } - - bool String(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } - - bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } - - bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } - - bool EndObject(SizeType memberCount) { - typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); - return true; - } - - bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } - - bool EndArray(SizeType elementCount) { - ValueType* elements = stack_.template Pop(elementCount); - stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); - return true; - } - -private: - //! Prohibit copying - GenericDocument(const GenericDocument&); - //! Prohibit assignment - GenericDocument& operator=(const GenericDocument&); - - void ClearStack() { - if (Allocator::kNeedFree) - while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) - (stack_.template Pop(1))->~ValueType(); - else - stack_.Clear(); - stack_.ShrinkToFit(); - } - - void Destroy() { - RAPIDJSON_DELETE(ownAllocator_); - } - - static const size_t kDefaultStackCapacity = 1024; - Allocator* allocator_; - Allocator* ownAllocator_; - internal::Stack stack_; - ParseResult parseResult_; -}; - -//! GenericDocument with UTF8 encoding -typedef GenericDocument > Document; - - -//! Helper class for accessing Value of array type. -/*! - Instance of this helper class is obtained by \c GenericValue::GetArray(). - In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. -*/ -template -class GenericArray { -public: - typedef GenericArray ConstArray; - typedef GenericArray Array; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef ValueType* ValueIterator; // This may be const or non-const iterator - typedef const ValueT* ConstValueIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - - template - friend class GenericValue; - - GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} - GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } - ~GenericArray() {} - - operator ValueType&() const { return value_; } - SizeType Size() const { return value_.Size(); } - SizeType Capacity() const { return value_.Capacity(); } - bool Empty() const { return value_.Empty(); } - void Clear() const { value_.Clear(); } - ValueType& operator[](SizeType index) const { return value_[index]; } - ValueIterator Begin() const { return value_.Begin(); } - ValueIterator End() const { return value_.End(); } - GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } - GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - GenericArray PopBack() const { value_.PopBack(); return *this; } - ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } - -#if RAPIDJSON_HAS_CXX11_RANGE_FOR - ValueIterator begin() const { return value_.Begin(); } - ValueIterator end() const { return value_.End(); } -#endif - -private: - GenericArray(); - GenericArray(ValueType& value) : value_(value) {} - ValueType& value_; -}; - -//! Helper class for accessing Value of object type. -/*! - Instance of this helper class is obtained by \c GenericValue::GetObject(). - In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. -*/ -template -class GenericObject { -public: - typedef GenericObject ConstObject; - typedef GenericObject Object; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator - typedef GenericMemberIterator ConstMemberIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename ValueType::Ch Ch; - - template - friend class GenericValue; - - GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} - GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } - ~GenericObject() {} - - operator ValueType&() const { return value_; } - SizeType MemberCount() const { return value_.MemberCount(); } - SizeType MemberCapacity() const { return value_.MemberCapacity(); } - bool ObjectEmpty() const { return value_.ObjectEmpty(); } - template ValueType& operator[](T* name) const { return value_[name]; } - template ValueType& operator[](const GenericValue& name) const { return value_[name]; } -#if RAPIDJSON_HAS_STDSTRING - ValueType& operator[](const std::basic_string& name) const { return value_[name]; } -#endif - MemberIterator MemberBegin() const { return value_.MemberBegin(); } - MemberIterator MemberEnd() const { return value_.MemberEnd(); } - GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } - bool HasMember(const Ch* name) const { return value_.HasMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } -#endif - template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } - MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } - template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } -#if RAPIDJSON_HAS_STDSTRING - MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } -#endif - GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if RAPIDJSON_HAS_STDSTRING - GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#endif - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { value_.RemoveAllMembers(); } - bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } -#endif - template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } - MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } - MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } - bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } -#endif - template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } - -#if RAPIDJSON_HAS_CXX11_RANGE_FOR - MemberIterator begin() const { return value_.MemberBegin(); } - MemberIterator end() const { return value_.MemberEnd(); } -#endif - -private: - GenericObject(); - GenericObject(ValueType& value) : value_(value) {} - ValueType& value_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED -#pragma pop_macro("GetObject") -#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED -#endif - -#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodedstream.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodedstream.h deleted file mode 100644 index cf046b89..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodedstream.h +++ /dev/null @@ -1,299 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ENCODEDSTREAM_H_ -#define RAPIDJSON_ENCODEDSTREAM_H_ - -#include "stream.h" -#include "memorystream.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Input byte stream wrapper with a statically bound encoding. -/*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam InputByteStream Type of input byte stream. For example, FileReadStream. -*/ -template -class EncodedInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); -public: - typedef typename Encoding::Ch Ch; - - EncodedInputStream(InputByteStream& is) : is_(is) { - current_ = Encoding::TakeBOM(is_); - } - - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } - size_t Tell() const { return is_.Tell(); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); - - InputByteStream& is_; - Ch current_; -}; - -//! Specialized for UTF8 MemoryStream. -template <> -class EncodedInputStream, MemoryStream> { -public: - typedef UTF8<>::Ch Ch; - - EncodedInputStream(MemoryStream& is) : is_(is) { - if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); - if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); - if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); - } - Ch Peek() const { return is_.Peek(); } - Ch Take() { return is_.Take(); } - size_t Tell() const { return is_.Tell(); } - - // Not implemented - void Put(Ch) {} - void Flush() {} - Ch* PutBegin() { return 0; } - size_t PutEnd(Ch*) { return 0; } - - MemoryStream& is_; - -private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); -}; - -//! Output byte stream wrapper with statically bound encoding. -/*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. -*/ -template -class EncodedOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); -public: - typedef typename Encoding::Ch Ch; - - EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { - if (putBOM) - Encoding::PutBOM(os_); - } - - void Put(Ch c) { Encoding::Put(os_, c); } - void Flush() { os_.Flush(); } - - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - EncodedOutputStream(const EncodedOutputStream&); - EncodedOutputStream& operator=(const EncodedOutputStream&); - - OutputByteStream& os_; -}; - -#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - -//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. -/*! - \tparam CharType Type of character for reading. - \tparam InputByteStream type of input byte stream to be wrapped. -*/ -template -class AutoUTFInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); -public: - typedef CharType Ch; - - //! Constructor. - /*! - \param is input stream to be wrapped. - \param type UTF encoding type if it is not detected from the stream. - */ - AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { - RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); - DetectType(); - static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; - takeFunc_ = f[type_]; - current_ = takeFunc_(*is_); - } - - UTFType GetType() const { return type_; } - bool HasBOM() const { return hasBOM_; } - - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } - size_t Tell() const { return is_->Tell(); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - AutoUTFInputStream(const AutoUTFInputStream&); - AutoUTFInputStream& operator=(const AutoUTFInputStream&); - - // Detect encoding type with BOM or RFC 4627 - void DetectType() { - // BOM (Byte Order Mark): - // 00 00 FE FF UTF-32BE - // FF FE 00 00 UTF-32LE - // FE FF UTF-16BE - // FF FE UTF-16LE - // EF BB BF UTF-8 - - const unsigned char* c = reinterpret_cast(is_->Peek4()); - if (!c) - return; - - unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); - hasBOM_ = false; - if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } - - // RFC 4627: Section 3 - // "Since the first two characters of a JSON text will always be ASCII - // characters [RFC0020], it is possible to determine whether an octet - // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking - // at the pattern of nulls in the first four octets." - // 00 00 00 xx UTF-32BE - // 00 xx 00 xx UTF-16BE - // xx 00 00 00 UTF-32LE - // xx 00 xx 00 UTF-16LE - // xx xx xx xx UTF-8 - - if (!hasBOM_) { - int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); - switch (pattern) { - case 0x08: type_ = kUTF32BE; break; - case 0x0A: type_ = kUTF16BE; break; - case 0x01: type_ = kUTF32LE; break; - case 0x05: type_ = kUTF16LE; break; - case 0x0F: type_ = kUTF8; break; - default: break; // Use type defined by user. - } - } - - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - } - - typedef Ch (*TakeFunc)(InputByteStream& is); - InputByteStream* is_; - UTFType type_; - Ch current_; - TakeFunc takeFunc_; - bool hasBOM_; -}; - -//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. -/*! - \tparam CharType Type of character for writing. - \tparam OutputByteStream type of output byte stream to be wrapped. -*/ -template -class AutoUTFOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); -public: - typedef CharType Ch; - - //! Constructor. - /*! - \param os output stream to be wrapped. - \param type UTF encoding type. - \param putBOM Whether to write BOM at the beginning of the stream. - */ - AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { - RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); - - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - - static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; - putFunc_ = f[type_]; - - if (putBOM) - PutBOM(); - } - - UTFType GetType() const { return type_; } - - void Put(Ch c) { putFunc_(*os_, c); } - void Flush() { os_->Flush(); } - - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - AutoUTFOutputStream(const AutoUTFOutputStream&); - AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); - - void PutBOM() { - typedef void (*PutBOMFunc)(OutputByteStream&); - static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; - f[type_](*os_); - } - - typedef void (*PutFunc)(OutputByteStream&, Ch); - - OutputByteStream* os_; - UTFType type_; - PutFunc putFunc_; -}; - -#undef RAPIDJSON_ENCODINGS_FUNC - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodings.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodings.h deleted file mode 100644 index dbb0a4e4..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/encodings.h +++ /dev/null @@ -1,716 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ENCODINGS_H_ -#define RAPIDJSON_ENCODINGS_H_ - -#include "rapidjson.h" - -#if defined(_MSC_VER) && !defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#elif defined(__GNUC__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -RAPIDJSON_DIAG_OFF(overflow) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Encoding - -/*! \class rapidjson::Encoding - \brief Concept for encoding of Unicode characters. - -\code -concept Encoding { - typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. - - enum { supportUnicode = 1 }; // or 0 if not supporting unicode - - //! \brief Encode a Unicode codepoint to an output stream. - //! \param os Output stream. - //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. - template - static void Encode(OutputStream& os, unsigned codepoint); - - //! \brief Decode a Unicode codepoint from an input stream. - //! \param is Input stream. - //! \param codepoint Output of the unicode codepoint. - //! \return true if a valid codepoint can be decoded from the stream. - template - static bool Decode(InputStream& is, unsigned* codepoint); - - //! \brief Validate one Unicode codepoint from an encoded stream. - //! \param is Input stream to obtain codepoint. - //! \param os Output for copying one codepoint. - //! \return true if it is valid. - //! \note This function just validating and copying the codepoint without actually decode it. - template - static bool Validate(InputStream& is, OutputStream& os); - - // The following functions are deal with byte streams. - - //! Take a character from input byte stream, skip BOM if exist. - template - static CharType TakeBOM(InputByteStream& is); - - //! Take a character from input byte stream. - template - static Ch Take(InputByteStream& is); - - //! Put BOM to output byte stream. - template - static void PutBOM(OutputByteStream& os); - - //! Put a character to output byte stream. - template - static void Put(OutputByteStream& os, Ch c); -}; -\endcode -*/ - -/////////////////////////////////////////////////////////////////////////////// -// UTF8 - -//! UTF-8 encoding. -/*! http://en.wikipedia.org/wiki/UTF-8 - http://tools.ietf.org/html/rfc3629 - \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. - \note implements Encoding concept -*/ -template -struct UTF8 { - typedef CharType Ch; - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - os.Put(static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - PutUnsafe(os, static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); - } - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { -#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) -#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) - typename InputStream::Ch c = is.Take(); - if (!(c & 0x80)) { - *codepoint = static_cast(c); - return true; - } - - unsigned char type = GetRange(static_cast(c)); - if (type >= 32) { - *codepoint = 0; - } else { - *codepoint = (0xFFu >> type) & static_cast(c); - } - bool result = true; - switch (type) { - case 2: RAPIDJSON_TAIL(); return result; - case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; - case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; - case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - default: return false; - } -#undef RAPIDJSON_COPY -#undef RAPIDJSON_TRANS -#undef RAPIDJSON_TAIL - } - - template - static bool Validate(InputStream& is, OutputStream& os) { -#define RAPIDJSON_COPY() os.Put(c = is.Take()) -#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) - Ch c; - RAPIDJSON_COPY(); - if (!(c & 0x80)) - return true; - - bool result = true; - switch (GetRange(static_cast(c))) { - case 2: RAPIDJSON_TAIL(); return result; - case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; - case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; - case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - default: return false; - } -#undef RAPIDJSON_COPY -#undef RAPIDJSON_TRANS -#undef RAPIDJSON_TAIL - } - - static unsigned char GetRange(unsigned char c) { - // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. - static const unsigned char type[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - }; - return type[c]; - } - - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - typename InputByteStream::Ch c = Take(is); - if (static_cast(c) != 0xEFu) return c; - c = is.Take(); - if (static_cast(c) != 0xBBu) return c; - c = is.Take(); - if (static_cast(c) != 0xBFu) return c; - c = is.Take(); - return c; - } - - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return static_cast(is.Take()); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xEFu)); - os.Put(static_cast(0xBBu)); - os.Put(static_cast(0xBFu)); - } - - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// UTF16 - -//! UTF-16 encoding. -/*! http://en.wikipedia.org/wiki/UTF-16 - http://tools.ietf.org/html/rfc2781 - \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. - \note implements Encoding concept - - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF16LE and UTF16BE, which handle endianness. -*/ -template -struct UTF16 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - os.Put(static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - os.Put(static_cast((v >> 10) | 0xD800)); - os.Put(static_cast((v & 0x3FF) | 0xDC00)); - } - } - - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - PutUnsafe(os, static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - PutUnsafe(os, static_cast((v >> 10) | 0xD800)); - PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); - } - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - typename InputStream::Ch c = is.Take(); - if (c < 0xD800 || c > 0xDFFF) { - *codepoint = static_cast(c); - return true; - } - else if (c <= 0xDBFF) { - *codepoint = (static_cast(c) & 0x3FF) << 10; - c = is.Take(); - *codepoint |= (static_cast(c) & 0x3FF); - *codepoint += 0x10000; - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - typename InputStream::Ch c; - os.Put(static_cast(c = is.Take())); - if (c < 0xD800 || c > 0xDFFF) - return true; - else if (c <= 0xDBFF) { - os.Put(c = is.Take()); - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } -}; - -//! UTF-16 little endian encoding. -template -struct UTF16LE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0xFEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(is.Take()); - c |= static_cast(static_cast(is.Take())) << 8; - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFFu)); - os.Put(static_cast(0xFEu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(static_cast(c) & 0xFFu)); - os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); - } -}; - -//! UTF-16 big endian encoding. -template -struct UTF16BE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0xFEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())); - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0xFFu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); - os.Put(static_cast(static_cast(c) & 0xFFu)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// UTF32 - -//! UTF-32 encoding. -/*! http://en.wikipedia.org/wiki/UTF-32 - \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. - \note implements Encoding concept - - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF32LE and UTF32BE, which handle endianness. -*/ -template -struct UTF32 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(codepoint); - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - PutUnsafe(os, codepoint); - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c = is.Take(); - *codepoint = c; - return c <= 0x10FFFF; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c; - os.Put(c = is.Take()); - return c <= 0x10FFFF; - } -}; - -//! UTF-32 little endian encoding. -template -struct UTF32LE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0x0000FEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(is.Take()); - c |= static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())) << 16; - c |= static_cast(static_cast(is.Take())) << 24; - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFFu)); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0x00u)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c & 0xFFu)); - os.Put(static_cast((c >> 8) & 0xFFu)); - os.Put(static_cast((c >> 16) & 0xFFu)); - os.Put(static_cast((c >> 24) & 0xFFu)); - } -}; - -//! UTF-32 big endian encoding. -template -struct UTF32BE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0x0000FEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(static_cast(is.Take())) << 24; - c |= static_cast(static_cast(is.Take())) << 16; - c |= static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())); - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0xFFu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast((c >> 24) & 0xFFu)); - os.Put(static_cast((c >> 16) & 0xFFu)); - os.Put(static_cast((c >> 8) & 0xFFu)); - os.Put(static_cast(c & 0xFFu)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// ASCII - -//! ASCII encoding. -/*! http://en.wikipedia.org/wiki/ASCII - \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. - \note implements Encoding concept -*/ -template -struct ASCII { - typedef CharType Ch; - - enum { supportUnicode = 0 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - os.Put(static_cast(codepoint & 0xFF)); - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - PutUnsafe(os, static_cast(codepoint & 0xFF)); - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - uint8_t c = static_cast(is.Take()); - *codepoint = c; - return c <= 0X7F; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - uint8_t c = static_cast(is.Take()); - os.Put(static_cast(c)); - return c <= 0x7F; - } - - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - uint8_t c = static_cast(Take(is)); - return static_cast(c); - } - - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return static_cast(is.Take()); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - (void)os; - } - - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// AutoUTF - -//! Runtime-specified UTF encoding type of a stream. -enum UTFType { - kUTF8 = 0, //!< UTF-8. - kUTF16LE = 1, //!< UTF-16 little endian. - kUTF16BE = 2, //!< UTF-16 big endian. - kUTF32LE = 3, //!< UTF-32 little endian. - kUTF32BE = 4 //!< UTF-32 big endian. -}; - -//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. -/*! \note This class can be used with AutoUTFInputStream and AutoUTFOutputStream, which provides GetType(). -*/ -template -struct AutoUTF { - typedef CharType Ch; - - enum { supportUnicode = 1 }; - -#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - - template - static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; - (*f[os.GetType()])(os, codepoint); - } - - template - static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; - (*f[os.GetType()])(os, codepoint); - } - - template - static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { - typedef bool (*DecodeFunc)(InputStream&, unsigned*); - static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; - return (*f[is.GetType()])(is, codepoint); - } - - template - static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { - typedef bool (*ValidateFunc)(InputStream&, OutputStream&); - static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; - return (*f[is.GetType()])(is, os); - } - -#undef RAPIDJSON_ENCODINGS_FUNC -}; - -/////////////////////////////////////////////////////////////////////////////// -// Transcoder - -//! Encoding conversion. -template -struct Transcoder { - //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. - template - static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::Encode(os, codepoint); - return true; - } - - template - static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::EncodeUnsafe(os, codepoint); - return true; - } - - //! Validate one Unicode codepoint from an encoded stream. - template - static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { - return Transcode(is, os); // Since source/target encoding is different, must transcode. - } -}; - -// Forward declaration. -template -inline void PutUnsafe(Stream& stream, typename Stream::Ch c); - -//! Specialization of Transcoder with same source and target encoding. -template -struct Transcoder { - template - static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { - os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { - PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { - return Encoding::Validate(is, os); // source/target encoding are the same - } -}; - -RAPIDJSON_NAMESPACE_END - -#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/en.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/en.h deleted file mode 100644 index c87b04eb..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/en.h +++ /dev/null @@ -1,176 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_EN_H_ -#define RAPIDJSON_ERROR_EN_H_ - -#include "error.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(covered-switch-default) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Maps error code of parsing into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param parseErrorCode Error code obtained in parsing. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { - switch (parseErrorCode) { - case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); - - case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - - case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); - case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); - case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); - - case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); - - case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); - case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); - case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); - case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); - - case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); - case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); - case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); - - case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); - case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -//! Maps error code of validation into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param validateErrorCode Error code obtained from validator. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) { - switch (validateErrorCode) { - case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); - case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); - case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); - case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); - case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); - case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); - - case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); - case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); - case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); - - case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); - case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); - case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); - case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); - - case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); - case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); - case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); - case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); - case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); - case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); - - case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); - case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); - - case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); - case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf', indices '%matches'."); - case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); - case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); - case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); - - case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing."); - case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -//! Maps error code of schema document compilation into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param schemaErrorCode Error code obtained from compiling the schema document. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ - inline const RAPIDJSON_ERROR_CHARTYPE* GetSchemaError_En(SchemaErrorCode schemaErrorCode) { - switch (schemaErrorCode) { - case kSchemaErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kSchemaErrorStartUnknown: return RAPIDJSON_ERROR_STRING("Pointer '%value' to start of schema does not resolve to a location in the document."); - case kSchemaErrorRefPlainName: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' must be a JSON pointer."); - case kSchemaErrorRefInvalid: return RAPIDJSON_ERROR_STRING("$ref must not be an empty string."); - case kSchemaErrorRefPointerInvalid: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' is not a valid JSON pointer at offset '%offset'."); - case kSchemaErrorRefUnknown: return RAPIDJSON_ERROR_STRING("$ref '%value' does not resolve to a location in the target document."); - case kSchemaErrorRefCyclical: return RAPIDJSON_ERROR_STRING("$ref '%value' is cyclical."); - case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider."); - case kSchemaErrorRefNoRemoteSchema: return RAPIDJSON_ERROR_STRING("$ref '%value' is remote but the remote provider did not return a schema."); - case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'."); - case kSchemaErrorSpecUnknown: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not recognized."); - case kSchemaErrorSpecUnsupported: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not supported."); - case kSchemaErrorSpecIllegal: return RAPIDJSON_ERROR_STRING("Both JSON schema draft and OpenAPI version found in document."); - case kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } - } - -//! Maps error code of pointer parse into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param pointerParseErrorCode Error code obtained from pointer parse. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetPointerParseError_En(PointerParseErrorCode pointerParseErrorCode) { - switch (pointerParseErrorCode) { - case kPointerParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kPointerParseErrorTokenMustBeginWithSolidus: return RAPIDJSON_ERROR_STRING("A token must begin with a '/'."); - case kPointerParseErrorInvalidEscape: return RAPIDJSON_ERROR_STRING("Invalid escape."); - case kPointerParseErrorInvalidPercentEncoding: return RAPIDJSON_ERROR_STRING("Invalid percent encoding in URI fragment."); - case kPointerParseErrorCharacterMustPercentEncode: return RAPIDJSON_ERROR_STRING("A character must be percent encoded in a URI fragment."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/error.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/error.h deleted file mode 100644 index cae345db..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/error/error.h +++ /dev/null @@ -1,285 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_ERROR_H_ -#define RAPIDJSON_ERROR_ERROR_H_ - -#include "../rapidjson.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -/*! \file error.h */ - -/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_CHARTYPE - -//! Character type of error messages. -/*! \ingroup RAPIDJSON_ERRORS - The default character type is \c char. - On Windows, user can define this macro as \c TCHAR for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_CHARTYPE -#define RAPIDJSON_ERROR_CHARTYPE char -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_STRING - -//! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[]. -/*! \ingroup RAPIDJSON_ERRORS - By default this conversion macro does nothing. - On Windows, user can define this macro as \c _T(x) for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_STRING -#define RAPIDJSON_ERROR_STRING(x) x -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseErrorCode - -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericReader::Parse, GenericReader::GetParseErrorCode -*/ -enum ParseErrorCode { - kParseErrorNone = 0, //!< No error. - - kParseErrorDocumentEmpty, //!< The document is empty. - kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. - - kParseErrorValueInvalid, //!< Invalid value. - - kParseErrorObjectMissName, //!< Missing a name for object member. - kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. - kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. - - kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. - - kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. - kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. - kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. - kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. - - kParseErrorNumberTooBig, //!< Number too big to be stored in double. - kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent, //!< Miss exponent in number. - - kParseErrorTermination, //!< Parsing was terminated. - kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. -}; - -//! Result of parsing (wraps ParseErrorCode) -/*! - \ingroup RAPIDJSON_ERRORS - \code - Document doc; - ParseResult ok = doc.Parse("[42]"); - if (!ok) { - fprintf(stderr, "JSON parse error: %s (%u)", - GetParseError_En(ok.Code()), ok.Offset()); - exit(EXIT_FAILURE); - } - \endcode - \see GenericReader::Parse, GenericDocument::Parse -*/ -struct ParseResult { - //!! Unspecified boolean type - typedef bool (ParseResult::*BooleanType)() const; -public: - //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} - //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} - - //! Get the error code. - ParseErrorCode Code() const { return code_; } - //! Get the error offset, if \ref IsError(), 0 otherwise. - size_t Offset() const { return offset_; } - - //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). - operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } - //! Whether the result is an error. - bool IsError() const { return code_ != kParseErrorNone; } - - bool operator==(const ParseResult& that) const { return code_ == that.code_; } - bool operator==(ParseErrorCode code) const { return code_ == code; } - friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } - - bool operator!=(const ParseResult& that) const { return !(*this == that); } - bool operator!=(ParseErrorCode code) const { return !(*this == code); } - friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } - - //! Reset error code. - void Clear() { Set(kParseErrorNone); } - //! Update error code and offset. - void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } - -private: - ParseErrorCode code_; - size_t offset_; -}; - -//! Function pointer type of GetParseError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetParseError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetParseErrorFunc GetParseError = GetParseError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); - -/////////////////////////////////////////////////////////////////////////////// -// ValidateErrorCode - -//! Error codes when validating. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericSchemaValidator -*/ -enum ValidateErrorCode { - kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set. - kValidateErrorNone = 0, //!< No error. - - kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value. - kValidateErrorMaximum, //!< Number is greater than the 'maximum' value. - kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value. - kValidateErrorMinimum, //!< Number is less than the 'minimum' value. - kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value. - - kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value. - kValidateErrorMinLength, //!< String is longer than the 'maxLength' value. - kValidateErrorPattern, //!< String does not match the 'pattern' regular expression. - - kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value. - kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value. - kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true. - kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema. - - kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value. - kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value. - kValidateErrorRequired, //!< Object is missing one or more members required by the schema. - kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema. - kValidateErrorPatternProperties, //!< See other errors. - kValidateErrorDependencies, //!< Object has missing property or schema dependencies. - - kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values. - kValidateErrorType, //!< Property has a type that is not allowed by the schema. - - kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. - kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. - kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. - kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. - kValidateErrorNot, //!< Property matched the sub-schema specified by 'not'. - - kValidateErrorReadOnly, //!< Property is read-only but has been provided when validation is for writing - kValidateErrorWriteOnly //!< Property is write-only but has been provided when validation is for reading -}; - -//! Function pointer type of GetValidateError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetValidateError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); - -/////////////////////////////////////////////////////////////////////////////// -// SchemaErrorCode - -//! Error codes when validating. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericSchemaValidator -*/ -enum SchemaErrorCode { - kSchemaErrorNone = 0, //!< No error. - - kSchemaErrorStartUnknown, //!< Pointer to start of schema does not resolve to a location in the document - kSchemaErrorRefPlainName, //!< $ref fragment must be a JSON pointer - kSchemaErrorRefInvalid, //!< $ref must not be an empty string - kSchemaErrorRefPointerInvalid, //!< $ref fragment is not a valid JSON pointer at offset - kSchemaErrorRefUnknown, //!< $ref does not resolve to a location in the target document - kSchemaErrorRefCyclical, //!< $ref is cyclical - kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider - kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema - kSchemaErrorRegexInvalid, //!< Invalid regular expression in 'pattern' or 'patternProperties' - kSchemaErrorSpecUnknown, //!< JSON schema draft or OpenAPI version is not recognized - kSchemaErrorSpecUnsupported, //!< JSON schema draft or OpenAPI version is not supported - kSchemaErrorSpecIllegal, //!< Both JSON schema draft and OpenAPI version found in document - kSchemaErrorReadOnlyAndWriteOnly //!< Property must not be both 'readOnly' and 'writeOnly' -}; - -//! Function pointer type of GetSchemaError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetSchemaError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetSchemaErrorFunc GetSchemaError = GetSchemaError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetSchemaError(validator.GetInvalidSchemaCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetSchemaErrorFunc)(SchemaErrorCode); - -/////////////////////////////////////////////////////////////////////////////// -// PointerParseErrorCode - -//! Error code of JSON pointer parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode -*/ -enum PointerParseErrorCode { - kPointerParseErrorNone = 0, //!< The parse is successful - - kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' - kPointerParseErrorInvalidEscape, //!< Invalid escape - kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment - kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment -}; - -//! Function pointer type of GetPointerParseError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetPointerParseError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetPointerParseErrorFunc GetPointerParseError = GetPointerParseError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetPointerParseError(pointer.GetParseErrorCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetPointerParseErrorFunc)(PointerParseErrorCode); - - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filereadstream.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filereadstream.h deleted file mode 100644 index f8bb43cb..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filereadstream.h +++ /dev/null @@ -1,99 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILEREADSTREAM_H_ -#define RAPIDJSON_FILEREADSTREAM_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(missing-noreturn) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! File byte stream for input using fread(). -/*! - \note implements Stream concept -*/ -class FileReadStream { -public: - typedef char Ch; //!< Character type (byte). - - //! Constructor. - /*! - \param fp File pointer opened for read. - \param buffer user-supplied buffer. - \param bufferSize size of buffer in bytes. Must >=4 bytes. - */ - FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(fp_ != 0); - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); - } - - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; - } - -private: - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; - - if (readCount_ < bufferSize_) { - buffer_[readCount_] = '\0'; - ++bufferLast_; - eof_ = true; - } - } - } - - std::FILE* fp_; - Ch *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filewritestream.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filewritestream.h deleted file mode 100644 index 5d89588c..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/filewritestream.h +++ /dev/null @@ -1,104 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILEWRITESTREAM_H_ -#define RAPIDJSON_FILEWRITESTREAM_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(unreachable-code) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of C file stream for output using fwrite(). -/*! - \note implements Stream concept -*/ -class FileWriteStream { -public: - typedef char Ch; //!< Character type. Only support char. - - FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { - RAPIDJSON_ASSERT(fp_ != 0); - } - - void Put(char c) { - if (current_ >= bufferEnd_) - Flush(); - - *current_++ = c; - } - - void PutN(char c, size_t n) { - size_t avail = static_cast(bufferEnd_ - current_); - while (n > avail) { - std::memset(current_, c, avail); - current_ += avail; - Flush(); - n -= avail; - avail = static_cast(bufferEnd_ - current_); - } - - if (n > 0) { - std::memset(current_, c, n); - current_ += n; - } - } - - void Flush() { - if (current_ != buffer_) { - size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); - if (result < static_cast(current_ - buffer_)) { - // failure deliberately ignored at this time - // added to avoid warn_unused_result build errors - } - current_ = buffer_; - } - } - - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - // Prohibit copy constructor & assignment operator. - FileWriteStream(const FileWriteStream&); - FileWriteStream& operator=(const FileWriteStream&); - - std::FILE* fp_; - char *buffer_; - char *bufferEnd_; - char *current_; -}; - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(FileWriteStream& stream, char c, size_t n) { - stream.PutN(c, n); -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/fwd.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/fwd.h deleted file mode 100644 index d62f77f0..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/fwd.h +++ /dev/null @@ -1,151 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FWD_H_ -#define RAPIDJSON_FWD_H_ - -#include "rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN - -// encodings.h - -template struct UTF8; -template struct UTF16; -template struct UTF16BE; -template struct UTF16LE; -template struct UTF32; -template struct UTF32BE; -template struct UTF32LE; -template struct ASCII; -template struct AutoUTF; - -template -struct Transcoder; - -// allocators.h - -class CrtAllocator; - -template -class MemoryPoolAllocator; - -// stream.h - -template -struct GenericStringStream; - -typedef GenericStringStream > StringStream; - -template -struct GenericInsituStringStream; - -typedef GenericInsituStringStream > InsituStringStream; - -// stringbuffer.h - -template -class GenericStringBuffer; - -typedef GenericStringBuffer, CrtAllocator> StringBuffer; - -// filereadstream.h - -class FileReadStream; - -// filewritestream.h - -class FileWriteStream; - -// memorybuffer.h - -template -struct GenericMemoryBuffer; - -typedef GenericMemoryBuffer MemoryBuffer; - -// memorystream.h - -struct MemoryStream; - -// reader.h - -template -struct BaseReaderHandler; - -template -class GenericReader; - -typedef GenericReader, UTF8, CrtAllocator> Reader; - -// writer.h - -template -class Writer; - -// prettywriter.h - -template -class PrettyWriter; - -// document.h - -template -class GenericMember; - -template -class GenericMemberIterator; - -template -struct GenericStringRef; - -template -class GenericValue; - -typedef GenericValue, MemoryPoolAllocator > Value; - -template -class GenericDocument; - -typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; - -// pointer.h - -template -class GenericPointer; - -typedef GenericPointer Pointer; - -// schema.h - -template -class IGenericRemoteSchemaDocumentProvider; - -template -class GenericSchemaDocument; - -typedef GenericSchemaDocument SchemaDocument; -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -template < - typename SchemaDocumentType, - typename OutputHandler, - typename StateAllocator> -class GenericSchemaValidator; - -typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/biginteger.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/biginteger.h deleted file mode 100644 index 4930043d..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/biginteger.h +++ /dev/null @@ -1,297 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_BIGINTEGER_H_ -#define RAPIDJSON_BIGINTEGER_H_ - -#include "../rapidjson.h" - -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) -#include // for _umul128 -#if !defined(_ARM64EC_) -#pragma intrinsic(_umul128) -#else -#pragma comment(lib,"softintrin") -#endif -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -class BigInteger { -public: - typedef uint64_t Type; - - BigInteger(const BigInteger& rhs) : count_(rhs.count_) { - std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); - } - - explicit BigInteger(uint64_t u) : count_(1) { - digits_[0] = u; - } - - template - BigInteger(const Ch* decimals, size_t length) : count_(1) { - RAPIDJSON_ASSERT(length > 0); - digits_[0] = 0; - size_t i = 0; - const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 - while (length >= kMaxDigitPerIteration) { - AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); - length -= kMaxDigitPerIteration; - i += kMaxDigitPerIteration; - } - - if (length > 0) - AppendDecimal64(decimals + i, decimals + i + length); - } - - BigInteger& operator=(const BigInteger &rhs) - { - if (this != &rhs) { - count_ = rhs.count_; - std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); - } - return *this; - } - - BigInteger& operator=(uint64_t u) { - digits_[0] = u; - count_ = 1; - return *this; - } - - BigInteger& operator+=(uint64_t u) { - Type backup = digits_[0]; - digits_[0] += u; - for (size_t i = 0; i < count_ - 1; i++) { - if (digits_[i] >= backup) - return *this; // no carry - backup = digits_[i + 1]; - digits_[i + 1] += 1; - } - - // Last carry - if (digits_[count_ - 1] < backup) - PushBack(1); - - return *this; - } - - BigInteger& operator*=(uint64_t u) { - if (u == 0) return *this = 0; - if (u == 1) return *this; - if (*this == 1) return *this = u; - - uint64_t k = 0; - for (size_t i = 0; i < count_; i++) { - uint64_t hi; - digits_[i] = MulAdd64(digits_[i], u, k, &hi); - k = hi; - } - - if (k > 0) - PushBack(k); - - return *this; - } - - BigInteger& operator*=(uint32_t u) { - if (u == 0) return *this = 0; - if (u == 1) return *this; - if (*this == 1) return *this = u; - - uint64_t k = 0; - for (size_t i = 0; i < count_; i++) { - const uint64_t c = digits_[i] >> 32; - const uint64_t d = digits_[i] & 0xFFFFFFFF; - const uint64_t uc = u * c; - const uint64_t ud = u * d; - const uint64_t p0 = ud + k; - const uint64_t p1 = uc + (p0 >> 32); - digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); - k = p1 >> 32; - } - - if (k > 0) - PushBack(k); - - return *this; - } - - BigInteger& operator<<=(size_t shift) { - if (IsZero() || shift == 0) return *this; - - size_t offset = shift / kTypeBit; - size_t interShift = shift % kTypeBit; - RAPIDJSON_ASSERT(count_ + offset <= kCapacity); - - if (interShift == 0) { - std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); - count_ += offset; - } - else { - digits_[count_] = 0; - for (size_t i = count_; i > 0; i--) - digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); - digits_[offset] = digits_[0] << interShift; - count_ += offset; - if (digits_[count_]) - count_++; - } - - std::memset(digits_, 0, offset * sizeof(Type)); - - return *this; - } - - bool operator==(const BigInteger& rhs) const { - return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; - } - - bool operator==(const Type rhs) const { - return count_ == 1 && digits_[0] == rhs; - } - - BigInteger& MultiplyPow5(unsigned exp) { - static const uint32_t kPow5[12] = { - 5, - 5 * 5, - 5 * 5 * 5, - 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 - }; - if (exp == 0) return *this; - for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 - for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 - if (exp > 0) *this *= kPow5[exp - 1]; - return *this; - } - - // Compute absolute difference of this and rhs. - // Assume this != rhs - bool Difference(const BigInteger& rhs, BigInteger* out) const { - int cmp = Compare(rhs); - RAPIDJSON_ASSERT(cmp != 0); - const BigInteger *a, *b; // Makes a > b - bool ret; - if (cmp < 0) { a = &rhs; b = this; ret = true; } - else { a = this; b = &rhs; ret = false; } - - Type borrow = 0; - for (size_t i = 0; i < a->count_; i++) { - Type d = a->digits_[i] - borrow; - if (i < b->count_) - d -= b->digits_[i]; - borrow = (d > a->digits_[i]) ? 1 : 0; - out->digits_[i] = d; - if (d != 0) - out->count_ = i + 1; - } - - return ret; - } - - int Compare(const BigInteger& rhs) const { - if (count_ != rhs.count_) - return count_ < rhs.count_ ? -1 : 1; - - for (size_t i = count_; i-- > 0;) - if (digits_[i] != rhs.digits_[i]) - return digits_[i] < rhs.digits_[i] ? -1 : 1; - - return 0; - } - - size_t GetCount() const { return count_; } - Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } - bool IsZero() const { return count_ == 1 && digits_[0] == 0; } - -private: - template - void AppendDecimal64(const Ch* begin, const Ch* end) { - uint64_t u = ParseUint64(begin, end); - if (IsZero()) - *this = u; - else { - unsigned exp = static_cast(end - begin); - (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u - } - } - - void PushBack(Type digit) { - RAPIDJSON_ASSERT(count_ < kCapacity); - digits_[count_++] = digit; - } - - template - static uint64_t ParseUint64(const Ch* begin, const Ch* end) { - uint64_t r = 0; - for (const Ch* p = begin; p != end; ++p) { - RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9')); - r = r * 10u + static_cast(*p - Ch('0')); - } - return r; - } - - // Assume a * b + k < 2^128 - static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t low = _umul128(a, b, outHigh) + k; - if (low < k) - (*outHigh)++; - return low; -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - __extension__ typedef unsigned __int128 uint128; - uint128 p = static_cast(a) * static_cast(b); - p += k; - *outHigh = static_cast(p >> 64); - return static_cast(p); -#else - const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; - uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; - x1 += (x0 >> 32); // can't give carry - x1 += x2; - if (x1 < x2) - x3 += (static_cast(1) << 32); - uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); - uint64_t hi = x3 + (x1 >> 32); - - lo += k; - if (lo < k) - hi++; - *outHigh = hi; - return lo; -#endif - } - - static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 - static const size_t kCapacity = kBitCount / sizeof(Type); - static const size_t kTypeBit = sizeof(Type) * 8; - - Type digits_[kCapacity]; - size_t count_; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/clzll.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/clzll.h deleted file mode 100644 index 8fc5118a..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/clzll.h +++ /dev/null @@ -1,71 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_CLZLL_H_ -#define RAPIDJSON_CLZLL_H_ - -#include "../rapidjson.h" - -#if defined(_MSC_VER) && !defined(UNDER_CE) -#include -#if defined(_WIN64) -#pragma intrinsic(_BitScanReverse64) -#else -#pragma intrinsic(_BitScanReverse) -#endif -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline uint32_t clzll(uint64_t x) { - // Passing 0 to __builtin_clzll is UB in GCC and results in an - // infinite loop in the software implementation. - RAPIDJSON_ASSERT(x != 0); - -#if defined(_MSC_VER) && !defined(UNDER_CE) - unsigned long r = 0; -#if defined(_WIN64) - _BitScanReverse64(&r, x); -#else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); -#endif // _WIN64 - - return 63 - r; -#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) - // __builtin_clzll wrapper - return static_cast(__builtin_clzll(x)); -#else - // naive version - uint32_t r = 0; - while (!(x & (static_cast(1) << 63))) { - x <<= 1; - ++r; - } - - return r; -#endif // _MSC_VER -} - -#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_CLZLL_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/diyfp.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/diyfp.h deleted file mode 100644 index 1f60fb60..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/diyfp.h +++ /dev/null @@ -1,261 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// This is a C++ header-only implementation of Grisu2 algorithm from the publication: -// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with -// integers." ACM Sigplan Notices 45.6 (2010): 233-243. - -#ifndef RAPIDJSON_DIYFP_H_ -#define RAPIDJSON_DIYFP_H_ - -#include "../rapidjson.h" -#include "clzll.h" -#include - -#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) -#include -#if !defined(_ARM64EC_) -#pragma intrinsic(_umul128) -#else -#pragma comment(lib,"softintrin") -#endif -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -struct DiyFp { - DiyFp() : f(), e() {} - - DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} - - explicit DiyFp(double d) { - union { - double d; - uint64_t u64; - } u = { d }; - - int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); - uint64_t significand = (u.u64 & kDpSignificandMask); - if (biased_e != 0) { - f = significand + kDpHiddenBit; - e = biased_e - kDpExponentBias; - } - else { - f = significand; - e = kDpMinExponent + 1; - } - } - - DiyFp operator-(const DiyFp& rhs) const { - return DiyFp(f - rhs.f, e); - } - - DiyFp operator*(const DiyFp& rhs) const { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t h; - uint64_t l = _umul128(f, rhs.f, &h); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - __extension__ typedef unsigned __int128 uint128; - uint128 p = static_cast(f) * static_cast(rhs.f); - uint64_t h = static_cast(p >> 64); - uint64_t l = static_cast(p); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#else - const uint64_t M32 = 0xFFFFFFFF; - const uint64_t a = f >> 32; - const uint64_t b = f & M32; - const uint64_t c = rhs.f >> 32; - const uint64_t d = rhs.f & M32; - const uint64_t ac = a * c; - const uint64_t bc = b * c; - const uint64_t ad = a * d; - const uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); - tmp += 1U << 31; /// mult_round - return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); -#endif - } - - DiyFp Normalize() const { - int s = static_cast(clzll(f)); - return DiyFp(f << s, e - s); - } - - DiyFp NormalizeBoundary() const { - DiyFp res = *this; - while (!(res.f & (kDpHiddenBit << 1))) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); - return res; - } - - void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { - DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); - DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); - mi.f <<= mi.e - pl.e; - mi.e = pl.e; - *plus = pl; - *minus = mi; - } - - double ToDouble() const { - union { - double d; - uint64_t u64; - }u; - RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); - if (e < kDpDenormalExponent) { - // Underflow. - return 0.0; - } - if (e >= kDpMaxExponent) { - // Overflow. - return std::numeric_limits::infinity(); - } - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : - static_cast(e + kDpExponentBias); - u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); - return u.d; - } - - static const int kDiySignificandSize = 64; - static const int kDpSignificandSize = 52; - static const int kDpExponentBias = 0x3FF + kDpSignificandSize; - static const int kDpMaxExponent = 0x7FF - kDpExponentBias; - static const int kDpMinExponent = -kDpExponentBias; - static const int kDpDenormalExponent = -kDpExponentBias + 1; - static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - - uint64_t f; - int e; -}; - -inline DiyFp GetCachedPowerByIndex(size_t index) { - // 10^-348, 10^-340, ..., 10^340 - static const uint64_t kCachedPowers_F[] = { - RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), - RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), - RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), - RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), - RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), - RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), - RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), - RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), - RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), - RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), - RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), - RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), - RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), - RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), - RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), - RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), - RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), - RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), - RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), - RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), - RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), - RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), - RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), - RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), - RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), - RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), - RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), - RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), - RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), - RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), - RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), - RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), - RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), - RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), - RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), - RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), - RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), - RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), - RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), - RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), - RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), - RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), - RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), - RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) - }; - static const int16_t kCachedPowers_E[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, - -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, - -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, - -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, - -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, - 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, - 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, - 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, - 907, 933, 960, 986, 1013, 1039, 1066 - }; - RAPIDJSON_ASSERT(index < 87); - return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); -} - -inline DiyFp GetCachedPower(int e, int* K) { - - //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; - double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive - int k = static_cast(dk); - if (dk - k > 0.0) - k++; - - unsigned index = static_cast((k >> 3) + 1); - *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table - - return GetCachedPowerByIndex(index); -} - -inline DiyFp GetCachedPower10(int exp, int *outExp) { - RAPIDJSON_ASSERT(exp >= -348); - unsigned index = static_cast(exp + 348) / 8u; - *outExp = -348 + static_cast(index) * 8; - return GetCachedPowerByIndex(index); -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -RAPIDJSON_DIAG_OFF(padded) -#endif - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_DIYFP_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/dtoa.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/dtoa.h deleted file mode 100644 index cd456721..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/dtoa.h +++ /dev/null @@ -1,249 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// This is a C++ header-only implementation of Grisu2 algorithm from the publication: -// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with -// integers." ACM Sigplan Notices 45.6 (2010): 233-243. - -#ifndef RAPIDJSON_DTOA_ -#define RAPIDJSON_DTOA_ - -#include "itoa.h" // GetDigitsLut() -#include "diyfp.h" -#include "ieee754.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 -#endif - -inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { - while (rest < wp_w && delta - rest >= ten_kappa && - (rest + ten_kappa < wp_w || /// closer - wp_w - rest > rest + ten_kappa - wp_w)) { - buffer[len - 1]--; - rest += ten_kappa; - } -} - -inline int CountDecimalDigit32(uint32_t n) { - // Simple pure C++ implementation was faster than __builtin_clz version in this situation. - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1000) return 3; - if (n < 10000) return 4; - if (n < 100000) return 5; - if (n < 1000000) return 6; - if (n < 10000000) return 7; - if (n < 100000000) return 8; - // Will not reach 10 digits in DigitGen() - //if (n < 1000000000) return 9; - //return 10; - return 9; -} - -inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { - static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, - 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL, - 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, - 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, - 10000000000000000000ULL }; - const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); - const DiyFp wp_w = Mp - W; - uint32_t p1 = static_cast(Mp.f >> -one.e); - uint64_t p2 = Mp.f & (one.f - 1); - int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] - *len = 0; - - while (kappa > 0) { - uint32_t d = 0; - switch (kappa) { - case 9: d = p1 / 100000000; p1 %= 100000000; break; - case 8: d = p1 / 10000000; p1 %= 10000000; break; - case 7: d = p1 / 1000000; p1 %= 1000000; break; - case 6: d = p1 / 100000; p1 %= 100000; break; - case 5: d = p1 / 10000; p1 %= 10000; break; - case 4: d = p1 / 1000; p1 %= 1000; break; - case 3: d = p1 / 100; p1 %= 100; break; - case 2: d = p1 / 10; p1 %= 10; break; - case 1: d = p1; p1 = 0; break; - default:; - } - if (d || *len) - buffer[(*len)++] = static_cast('0' + static_cast(d)); - kappa--; - uint64_t tmp = (static_cast(p1) << -one.e) + p2; - if (tmp <= delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f); - return; - } - } - - // kappa = 0 - for (;;) { - p2 *= 10; - delta *= 10; - char d = static_cast(p2 >> -one.e); - if (d || *len) - buffer[(*len)++] = static_cast('0' + d); - p2 &= one.f - 1; - kappa--; - if (p2 < delta) { - *K += kappa; - int index = -kappa; - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0)); - return; - } - } -} - -inline void Grisu2(double value, char* buffer, int* length, int* K) { - const DiyFp v(value); - DiyFp w_m, w_p; - v.NormalizedBoundaries(&w_m, &w_p); - - const DiyFp c_mk = GetCachedPower(w_p.e, K); - const DiyFp W = v.Normalize() * c_mk; - DiyFp Wp = w_p * c_mk; - DiyFp Wm = w_m * c_mk; - Wm.f++; - Wp.f--; - DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); -} - -inline char* WriteExponent(int K, char* buffer) { - if (K < 0) { - *buffer++ = '-'; - K = -K; - } - - if (K >= 100) { - *buffer++ = static_cast('0' + static_cast(K / 100)); - K %= 100; - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else if (K >= 10) { - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else - *buffer++ = static_cast('0' + static_cast(K)); - - return buffer; -} - -inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { - const int kk = length + k; // 10^(kk-1) <= v < 10^kk - - if (0 <= k && kk <= 21) { - // 1234e7 -> 12340000000 - for (int i = length; i < kk; i++) - buffer[i] = '0'; - buffer[kk] = '.'; - buffer[kk + 1] = '0'; - return &buffer[kk + 2]; - } - else if (0 < kk && kk <= 21) { - // 1234e-2 -> 12.34 - std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); - buffer[kk] = '.'; - if (0 > k + maxDecimalPlaces) { - // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 - // Remove extra trailing zeros (at least one) after truncation. - for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) - if (buffer[i] != '0') - return &buffer[i + 1]; - return &buffer[kk + 2]; // Reserve one zero - } - else - return &buffer[length + 1]; - } - else if (-6 < kk && kk <= 0) { - // 1234e-6 -> 0.001234 - const int offset = 2 - kk; - std::memmove(&buffer[offset], &buffer[0], static_cast(length)); - buffer[0] = '0'; - buffer[1] = '.'; - for (int i = 2; i < offset; i++) - buffer[i] = '0'; - if (length - kk > maxDecimalPlaces) { - // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 - // Remove extra trailing zeros (at least one) after truncation. - for (int i = maxDecimalPlaces + 1; i > 2; i--) - if (buffer[i] != '0') - return &buffer[i + 1]; - return &buffer[3]; // Reserve one zero - } - else - return &buffer[length + offset]; - } - else if (kk < -maxDecimalPlaces) { - // Truncate to zero - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else if (length == 1) { - // 1e30 - buffer[1] = 'e'; - return WriteExponent(kk - 1, &buffer[2]); - } - else { - // 1234e30 -> 1.234e33 - std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); - buffer[1] = '.'; - buffer[length + 1] = 'e'; - return WriteExponent(kk - 1, &buffer[0 + length + 2]); - } -} - -inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { - RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); - Double d(value); - if (d.IsZero()) { - if (d.Sign()) - *buffer++ = '-'; // -0.0, Issue #289 - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } - int length, K; - Grisu2(value, buffer, &length, &K); - return Prettify(buffer, length, K, maxDecimalPlaces); - } -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_DTOA_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/ieee754.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/ieee754.h deleted file mode 100644 index 68c9e966..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/ieee754.h +++ /dev/null @@ -1,78 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_IEEE754_ -#define RAPIDJSON_IEEE754_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -class Double { -public: - Double() {} - Double(double d) : d_(d) {} - Double(uint64_t u) : u_(u) {} - - double Value() const { return d_; } - uint64_t Uint64Value() const { return u_; } - - double NextPositiveDouble() const { - RAPIDJSON_ASSERT(!Sign()); - return Double(u_ + 1).Value(); - } - - bool Sign() const { return (u_ & kSignMask) != 0; } - uint64_t Significand() const { return u_ & kSignificandMask; } - int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } - - bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } - bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } - bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } - bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } - bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } - - uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } - int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } - uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - - static int EffectiveSignificandSize(int order) { - if (order >= -1021) - return 53; - else if (order <= -1074) - return 0; - else - return order + 1074; - } - -private: - static const int kSignificandSize = 52; - static const int kExponentBias = 0x3FF; - static const int kDenormalExponent = 1 - kExponentBias; - static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); - static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - - union { - double d_; - uint64_t u_; - }; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_IEEE754_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/itoa.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/itoa.h deleted file mode 100644 index 9fe8c932..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/itoa.h +++ /dev/null @@ -1,308 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ITOA_ -#define RAPIDJSON_ITOA_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline const char* GetDigitsLut() { - static const char cDigitsLut[200] = { - '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', - '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', - '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', - '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', - '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', - '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', - '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', - '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', - '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', - '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' - }; - return cDigitsLut; -} - -inline char* u32toa(uint32_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - - const char* cDigitsLut = GetDigitsLut(); - - if (value < 10000) { - const uint32_t d1 = (value / 100) << 1; - const uint32_t d2 = (value % 100) << 1; - - if (value >= 1000) - *buffer++ = cDigitsLut[d1]; - if (value >= 100) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 10) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - } - else if (value < 100000000) { - // value = bbbbcccc - const uint32_t b = value / 10000; - const uint32_t c = value % 10000; - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - if (value >= 10000000) - *buffer++ = cDigitsLut[d1]; - if (value >= 1000000) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 100000) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - else { - // value = aabbbbcccc in decimal - - const uint32_t a = value / 100000000; // 1 to 42 - value %= 100000000; - - if (a >= 10) { - const unsigned i = a << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else - *buffer++ = static_cast('0' + static_cast(a)); - - const uint32_t b = value / 10000; // 0 to 9999 - const uint32_t c = value % 10000; // 0 to 9999 - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - *buffer++ = cDigitsLut[d1]; - *buffer++ = cDigitsLut[d1 + 1]; - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - return buffer; -} - -inline char* i32toa(int32_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - uint32_t u = static_cast(value); - if (value < 0) { - *buffer++ = '-'; - u = ~u + 1; - } - - return u32toa(u, buffer); -} - -inline char* u64toa(uint64_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - const char* cDigitsLut = GetDigitsLut(); - const uint64_t kTen8 = 100000000; - const uint64_t kTen9 = kTen8 * 10; - const uint64_t kTen10 = kTen8 * 100; - const uint64_t kTen11 = kTen8 * 1000; - const uint64_t kTen12 = kTen8 * 10000; - const uint64_t kTen13 = kTen8 * 100000; - const uint64_t kTen14 = kTen8 * 1000000; - const uint64_t kTen15 = kTen8 * 10000000; - const uint64_t kTen16 = kTen8 * kTen8; - - if (value < kTen8) { - uint32_t v = static_cast(value); - if (v < 10000) { - const uint32_t d1 = (v / 100) << 1; - const uint32_t d2 = (v % 100) << 1; - - if (v >= 1000) - *buffer++ = cDigitsLut[d1]; - if (v >= 100) - *buffer++ = cDigitsLut[d1 + 1]; - if (v >= 10) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - } - else { - // value = bbbbcccc - const uint32_t b = v / 10000; - const uint32_t c = v % 10000; - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - if (value >= 10000000) - *buffer++ = cDigitsLut[d1]; - if (value >= 1000000) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 100000) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - } - else if (value < kTen16) { - const uint32_t v0 = static_cast(value / kTen8); - const uint32_t v1 = static_cast(value % kTen8); - - const uint32_t b0 = v0 / 10000; - const uint32_t c0 = v0 % 10000; - - const uint32_t d1 = (b0 / 100) << 1; - const uint32_t d2 = (b0 % 100) << 1; - - const uint32_t d3 = (c0 / 100) << 1; - const uint32_t d4 = (c0 % 100) << 1; - - const uint32_t b1 = v1 / 10000; - const uint32_t c1 = v1 % 10000; - - const uint32_t d5 = (b1 / 100) << 1; - const uint32_t d6 = (b1 % 100) << 1; - - const uint32_t d7 = (c1 / 100) << 1; - const uint32_t d8 = (c1 % 100) << 1; - - if (value >= kTen15) - *buffer++ = cDigitsLut[d1]; - if (value >= kTen14) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= kTen13) - *buffer++ = cDigitsLut[d2]; - if (value >= kTen12) - *buffer++ = cDigitsLut[d2 + 1]; - if (value >= kTen11) - *buffer++ = cDigitsLut[d3]; - if (value >= kTen10) - *buffer++ = cDigitsLut[d3 + 1]; - if (value >= kTen9) - *buffer++ = cDigitsLut[d4]; - - *buffer++ = cDigitsLut[d4 + 1]; - *buffer++ = cDigitsLut[d5]; - *buffer++ = cDigitsLut[d5 + 1]; - *buffer++ = cDigitsLut[d6]; - *buffer++ = cDigitsLut[d6 + 1]; - *buffer++ = cDigitsLut[d7]; - *buffer++ = cDigitsLut[d7 + 1]; - *buffer++ = cDigitsLut[d8]; - *buffer++ = cDigitsLut[d8 + 1]; - } - else { - const uint32_t a = static_cast(value / kTen16); // 1 to 1844 - value %= kTen16; - - if (a < 10) - *buffer++ = static_cast('0' + static_cast(a)); - else if (a < 100) { - const uint32_t i = a << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else if (a < 1000) { - *buffer++ = static_cast('0' + static_cast(a / 100)); - - const uint32_t i = (a % 100) << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else { - const uint32_t i = (a / 100) << 1; - const uint32_t j = (a % 100) << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - *buffer++ = cDigitsLut[j]; - *buffer++ = cDigitsLut[j + 1]; - } - - const uint32_t v0 = static_cast(value / kTen8); - const uint32_t v1 = static_cast(value % kTen8); - - const uint32_t b0 = v0 / 10000; - const uint32_t c0 = v0 % 10000; - - const uint32_t d1 = (b0 / 100) << 1; - const uint32_t d2 = (b0 % 100) << 1; - - const uint32_t d3 = (c0 / 100) << 1; - const uint32_t d4 = (c0 % 100) << 1; - - const uint32_t b1 = v1 / 10000; - const uint32_t c1 = v1 % 10000; - - const uint32_t d5 = (b1 / 100) << 1; - const uint32_t d6 = (b1 % 100) << 1; - - const uint32_t d7 = (c1 / 100) << 1; - const uint32_t d8 = (c1 % 100) << 1; - - *buffer++ = cDigitsLut[d1]; - *buffer++ = cDigitsLut[d1 + 1]; - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - *buffer++ = cDigitsLut[d5]; - *buffer++ = cDigitsLut[d5 + 1]; - *buffer++ = cDigitsLut[d6]; - *buffer++ = cDigitsLut[d6 + 1]; - *buffer++ = cDigitsLut[d7]; - *buffer++ = cDigitsLut[d7 + 1]; - *buffer++ = cDigitsLut[d8]; - *buffer++ = cDigitsLut[d8 + 1]; - } - - return buffer; -} - -inline char* i64toa(int64_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - uint64_t u = static_cast(value); - if (value < 0) { - *buffer++ = '-'; - u = ~u + 1; - } - - return u64toa(u, buffer); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ITOA_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/meta.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/meta.h deleted file mode 100644 index 27092dc0..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/meta.h +++ /dev/null @@ -1,186 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_META_H_ -#define RAPIDJSON_INTERNAL_META_H_ - -#include "../rapidjson.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#if defined(_MSC_VER) && !defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(6334) -#endif - -#if RAPIDJSON_HAS_CXX11_TYPETRAITS -#include -#endif - -//@cond RAPIDJSON_INTERNAL -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching -template struct Void { typedef void Type; }; - -/////////////////////////////////////////////////////////////////////////////// -// BoolType, TrueType, FalseType -// -template struct BoolType { - static const bool Value = Cond; - typedef BoolType Type; -}; -typedef BoolType TrueType; -typedef BoolType FalseType; - - -/////////////////////////////////////////////////////////////////////////////// -// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr -// - -template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; -template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; -template struct SelectIfCond : SelectIfImpl::template Apply {}; -template struct SelectIf : SelectIfCond {}; - -template struct AndExprCond : FalseType {}; -template <> struct AndExprCond : TrueType {}; -template struct OrExprCond : TrueType {}; -template <> struct OrExprCond : FalseType {}; - -template struct BoolExpr : SelectIf::Type {}; -template struct NotExpr : SelectIf::Type {}; -template struct AndExpr : AndExprCond::Type {}; -template struct OrExpr : OrExprCond::Type {}; - - -/////////////////////////////////////////////////////////////////////////////// -// AddConst, MaybeAddConst, RemoveConst -template struct AddConst { typedef const T Type; }; -template struct MaybeAddConst : SelectIfCond {}; -template struct RemoveConst { typedef T Type; }; -template struct RemoveConst { typedef T Type; }; - - -/////////////////////////////////////////////////////////////////////////////// -// IsSame, IsConst, IsMoreConst, IsPointer -// -template struct IsSame : FalseType {}; -template struct IsSame : TrueType {}; - -template struct IsConst : FalseType {}; -template struct IsConst : TrueType {}; - -template -struct IsMoreConst - : AndExpr::Type, typename RemoveConst::Type>, - BoolType::Value >= IsConst::Value> >::Type {}; - -template struct IsPointer : FalseType {}; -template struct IsPointer : TrueType {}; - -/////////////////////////////////////////////////////////////////////////////// -// IsBaseOf -// -#if RAPIDJSON_HAS_CXX11_TYPETRAITS - -template struct IsBaseOf - : BoolType< ::std::is_base_of::value> {}; - -#else // simplified version adopted from Boost - -template struct IsBaseOfImpl { - RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); - RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); - - typedef char (&Yes)[1]; - typedef char (&No) [2]; - - template - static Yes Check(const D*, T); - static No Check(const B*, int); - - struct Host { - operator const B*() const; - operator const D*(); - }; - - enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; -}; - -template struct IsBaseOf - : OrExpr, BoolExpr > >::Type {}; - -#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS - - -////////////////////////////////////////////////////////////////////////// -// EnableIf / DisableIf -// -template struct EnableIfCond { typedef T Type; }; -template struct EnableIfCond { /* empty */ }; - -template struct DisableIfCond { typedef T Type; }; -template struct DisableIfCond { /* empty */ }; - -template -struct EnableIf : EnableIfCond {}; - -template -struct DisableIf : DisableIfCond {}; - -// SFINAE helpers -struct SfinaeTag {}; -template struct RemoveSfinaeTag; -template struct RemoveSfinaeTag { typedef T Type; }; - -#define RAPIDJSON_REMOVEFPTR_(type) \ - typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ - < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type - -#define RAPIDJSON_ENABLEIF(cond) \ - typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type * = NULL - -#define RAPIDJSON_DISABLEIF(cond) \ - typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type * = NULL - -#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ - typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type - -#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ - typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type - -} // namespace internal -RAPIDJSON_NAMESPACE_END -//@endcond - -#if defined(_MSC_VER) && !defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/pow10.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/pow10.h deleted file mode 100644 index eae1a43e..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/pow10.h +++ /dev/null @@ -1,55 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_POW10_ -#define RAPIDJSON_POW10_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Computes integer powers of 10 in double (10.0^n). -/*! This function uses lookup table for fast and accurate results. - \param n non-negative exponent. Must <= 308. - \return 10.0^n -*/ -inline double Pow10(int n) { - static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes - 1e+0, - 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, - 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, - 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, - 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, - 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, - 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, - 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, - 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, - 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, - 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, - 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, - 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, - 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, - 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, - 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, - 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 - }; - RAPIDJSON_ASSERT(n >= 0 && n <= 308); - return e[n]; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_POW10_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/regex.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/regex.h deleted file mode 100644 index 6446c403..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/regex.h +++ /dev/null @@ -1,739 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_REGEX_H_ -#define RAPIDJSON_INTERNAL_REGEX_H_ - -#include "../allocators.h" -#include "../stream.h" -#include "stack.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifndef RAPIDJSON_REGEX_VERBOSE -#define RAPIDJSON_REGEX_VERBOSE 0 -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -/////////////////////////////////////////////////////////////////////////////// -// DecodedStream - -template -class DecodedStream { -public: - DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } - unsigned Peek() { return codepoint_; } - unsigned Take() { - unsigned c = codepoint_; - if (c) // No further decoding when '\0' - Decode(); - return c; - } - -private: - void Decode() { - if (!Encoding::Decode(ss_, &codepoint_)) - codepoint_ = 0; - } - - SourceStream& ss_; - unsigned codepoint_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericRegex - -static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 -static const SizeType kRegexInvalidRange = ~SizeType(0); - -template -class GenericRegexSearch; - -//! Regular expression engine with subset of ECMAscript grammar. -/*! - Supported regular expression syntax: - - \c ab Concatenation - - \c a|b Alternation - - \c a? Zero or one - - \c a* Zero or more - - \c a+ One or more - - \c a{3} Exactly 3 times - - \c a{3,} At least 3 times - - \c a{3,5} 3 to 5 times - - \c (ab) Grouping - - \c ^a At the beginning - - \c a$ At the end - - \c . Any character - - \c [abc] Character classes - - \c [a-c] Character class range - - \c [a-z0-9_] Character class combination - - \c [^abc] Negated character classes - - \c [^a-c] Negated character class range - - \c [\b] Backspace (U+0008) - - \c \\| \\\\ ... Escape characters - - \c \\f Form feed (U+000C) - - \c \\n Line feed (U+000A) - - \c \\r Carriage return (U+000D) - - \c \\t Tab (U+0009) - - \c \\v Vertical tab (U+000B) - - \note This is a Thompson NFA engine, implemented with reference to - Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", - https://swtch.com/~rsc/regexp/regexp1.html -*/ -template -class GenericRegex { -public: - typedef Encoding EncodingType; - typedef typename Encoding::Ch Ch; - template friend class GenericRegexSearch; - - GenericRegex(const Ch* source, Allocator* allocator = 0) : - ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), - states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), - anchorBegin_(), anchorEnd_() - { - GenericStringStream ss(source); - DecodedStream, Encoding> ds(ss); - Parse(ds); - } - - ~GenericRegex() - { - RAPIDJSON_DELETE(ownAllocator_); - } - - bool IsValid() const { - return root_ != kRegexInvalidState; - } - -private: - enum Operator { - kZeroOrOne, - kZeroOrMore, - kOneOrMore, - kConcatenation, - kAlternation, - kLeftParenthesis - }; - - static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' - static const unsigned kRangeCharacterClass = 0xFFFFFFFE; - static const unsigned kRangeNegationFlag = 0x80000000; - - struct Range { - unsigned start; // - unsigned end; - SizeType next; - }; - - struct State { - SizeType out; //!< Equals to kInvalid for matching state - SizeType out1; //!< Equals to non-kInvalid for split - SizeType rangeStart; - unsigned codepoint; - }; - - struct Frag { - Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} - SizeType start; - SizeType out; //!< link-list of all output states - SizeType minIndex; - }; - - State& GetState(SizeType index) { - RAPIDJSON_ASSERT(index < stateCount_); - return states_.template Bottom()[index]; - } - - const State& GetState(SizeType index) const { - RAPIDJSON_ASSERT(index < stateCount_); - return states_.template Bottom()[index]; - } - - Range& GetRange(SizeType index) { - RAPIDJSON_ASSERT(index < rangeCount_); - return ranges_.template Bottom()[index]; - } - - const Range& GetRange(SizeType index) const { - RAPIDJSON_ASSERT(index < rangeCount_); - return ranges_.template Bottom()[index]; - } - - template - void Parse(DecodedStream& ds) { - Stack operandStack(allocator_, 256); // Frag - Stack operatorStack(allocator_, 256); // Operator - Stack atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis) - - *atomCountStack.template Push() = 0; - - unsigned codepoint; - while (ds.Peek() != 0) { - switch (codepoint = ds.Take()) { - case '^': - anchorBegin_ = true; - break; - - case '$': - anchorEnd_ = true; - break; - - case '|': - while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - *operatorStack.template Push() = kAlternation; - *atomCountStack.template Top() = 0; - break; - - case '(': - *operatorStack.template Push() = kLeftParenthesis; - *atomCountStack.template Push() = 0; - break; - - case ')': - while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - if (operatorStack.Empty()) - return; - operatorStack.template Pop(1); - atomCountStack.template Pop(1); - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '?': - if (!Eval(operandStack, kZeroOrOne)) - return; - break; - - case '*': - if (!Eval(operandStack, kZeroOrMore)) - return; - break; - - case '+': - if (!Eval(operandStack, kOneOrMore)) - return; - break; - - case '{': - { - unsigned n, m; - if (!ParseUnsigned(ds, &n)) - return; - - if (ds.Peek() == ',') { - ds.Take(); - if (ds.Peek() == '}') - m = kInfinityQuantifier; - else if (!ParseUnsigned(ds, &m) || m < n) - return; - } - else - m = n; - - if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') - return; - ds.Take(); - } - break; - - case '.': - PushOperand(operandStack, kAnyCharacterClass); - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '[': - { - SizeType range; - if (!ParseRange(ds, &range)) - return; - SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); - GetState(s).rangeStart = range; - *operandStack.template Push() = Frag(s, s, s); - } - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '\\': // Escape character - if (!CharacterEscape(ds, &codepoint)) - return; // Unsupported escape character - // fall through to default - RAPIDJSON_DELIBERATE_FALLTHROUGH; - - default: // Pattern character - PushOperand(operandStack, codepoint); - ImplicitConcatenation(atomCountStack, operatorStack); - } - } - - while (!operatorStack.Empty()) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - - // Link the operand to matching state. - if (operandStack.GetSize() == sizeof(Frag)) { - Frag* e = operandStack.template Pop(1); - Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); - root_ = e->start; - -#if RAPIDJSON_REGEX_VERBOSE - printf("root: %d\n", root_); - for (SizeType i = 0; i < stateCount_ ; i++) { - State& s = GetState(i); - printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); - } - printf("\n"); -#endif - } - } - - SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { - State* s = states_.template Push(); - s->out = out; - s->out1 = out1; - s->codepoint = codepoint; - s->rangeStart = kRegexInvalidRange; - return stateCount_++; - } - - void PushOperand(Stack& operandStack, unsigned codepoint) { - SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); - *operandStack.template Push() = Frag(s, s, s); - } - - void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { - if (*atomCountStack.template Top()) - *operatorStack.template Push() = kConcatenation; - (*atomCountStack.template Top())++; - } - - SizeType Append(SizeType l1, SizeType l2) { - SizeType old = l1; - while (GetState(l1).out != kRegexInvalidState) - l1 = GetState(l1).out; - GetState(l1).out = l2; - return old; - } - - void Patch(SizeType l, SizeType s) { - for (SizeType next; l != kRegexInvalidState; l = next) { - next = GetState(l).out; - GetState(l).out = s; - } - } - - bool Eval(Stack& operandStack, Operator op) { - switch (op) { - case kConcatenation: - RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); - { - Frag e2 = *operandStack.template Pop(1); - Frag e1 = *operandStack.template Pop(1); - Patch(e1.out, e2.start); - *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); - } - return true; - - case kAlternation: - if (operandStack.GetSize() >= sizeof(Frag) * 2) { - Frag e2 = *operandStack.template Pop(1); - Frag e1 = *operandStack.template Pop(1); - SizeType s = NewState(e1.start, e2.start, 0); - *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); - return true; - } - return false; - - case kZeroOrOne: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); - return true; - } - return false; - - case kZeroOrMore: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - Patch(e.out, s); - *operandStack.template Push() = Frag(s, s, e.minIndex); - return true; - } - return false; - - case kOneOrMore: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - Patch(e.out, s); - *operandStack.template Push() = Frag(e.start, s, e.minIndex); - return true; - } - return false; - - default: - // syntax error (e.g. unclosed kLeftParenthesis) - return false; - } - } - - bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { - RAPIDJSON_ASSERT(n <= m); - RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); - - if (n == 0) { - if (m == 0) // a{0} not support - return false; - else if (m == kInfinityQuantifier) - Eval(operandStack, kZeroOrMore); // a{0,} -> a* - else { - Eval(operandStack, kZeroOrOne); // a{0,5} -> a? - for (unsigned i = 0; i < m - 1; i++) - CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? - for (unsigned i = 0; i < m - 1; i++) - Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? - } - return true; - } - - for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a - CloneTopOperand(operandStack); - - if (m == kInfinityQuantifier) - Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ - else if (m > n) { - CloneTopOperand(operandStack); // a{3,5} -> a a a a - Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? - for (unsigned i = n; i < m - 1; i++) - CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? - for (unsigned i = n; i < m; i++) - Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? - } - - for (unsigned i = 0; i < n - 1; i++) - Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? - - return true; - } - - static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } - - void CloneTopOperand(Stack& operandStack) { - const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation - SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) - State* s = states_.template Push(count); - memcpy(s, &GetState(src.minIndex), count * sizeof(State)); - for (SizeType j = 0; j < count; j++) { - if (s[j].out != kRegexInvalidState) - s[j].out += count; - if (s[j].out1 != kRegexInvalidState) - s[j].out1 += count; - } - *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); - stateCount_ += count; - } - - template - bool ParseUnsigned(DecodedStream& ds, unsigned* u) { - unsigned r = 0; - if (ds.Peek() < '0' || ds.Peek() > '9') - return false; - while (ds.Peek() >= '0' && ds.Peek() <= '9') { - if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 - return false; // overflow - r = r * 10 + (ds.Take() - '0'); - } - *u = r; - return true; - } - - template - bool ParseRange(DecodedStream& ds, SizeType* range) { - bool isBegin = true; - bool negate = false; - int step = 0; - SizeType start = kRegexInvalidRange; - SizeType current = kRegexInvalidRange; - unsigned codepoint; - while ((codepoint = ds.Take()) != 0) { - if (isBegin) { - isBegin = false; - if (codepoint == '^') { - negate = true; - continue; - } - } - - switch (codepoint) { - case ']': - if (start == kRegexInvalidRange) - return false; // Error: nothing inside [] - if (step == 2) { // Add trailing '-' - SizeType r = NewRange('-'); - RAPIDJSON_ASSERT(current != kRegexInvalidRange); - GetRange(current).next = r; - } - if (negate) - GetRange(start).start |= kRangeNegationFlag; - *range = start; - return true; - - case '\\': - if (ds.Peek() == 'b') { - ds.Take(); - codepoint = 0x0008; // Escape backspace character - } - else if (!CharacterEscape(ds, &codepoint)) - return false; - // fall through to default - RAPIDJSON_DELIBERATE_FALLTHROUGH; - - default: - switch (step) { - case 1: - if (codepoint == '-') { - step++; - break; - } - // fall through to step 0 for other characters - RAPIDJSON_DELIBERATE_FALLTHROUGH; - - case 0: - { - SizeType r = NewRange(codepoint); - if (current != kRegexInvalidRange) - GetRange(current).next = r; - if (start == kRegexInvalidRange) - start = r; - current = r; - } - step = 1; - break; - - default: - RAPIDJSON_ASSERT(step == 2); - GetRange(current).end = codepoint; - step = 0; - } - } - } - return false; - } - - SizeType NewRange(unsigned codepoint) { - Range* r = ranges_.template Push(); - r->start = r->end = codepoint; - r->next = kRegexInvalidRange; - return rangeCount_++; - } - - template - bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { - unsigned codepoint; - switch (codepoint = ds.Take()) { - case '^': - case '$': - case '|': - case '(': - case ')': - case '?': - case '*': - case '+': - case '.': - case '[': - case ']': - case '{': - case '}': - case '\\': - *escapedCodepoint = codepoint; return true; - case 'f': *escapedCodepoint = 0x000C; return true; - case 'n': *escapedCodepoint = 0x000A; return true; - case 'r': *escapedCodepoint = 0x000D; return true; - case 't': *escapedCodepoint = 0x0009; return true; - case 'v': *escapedCodepoint = 0x000B; return true; - default: - return false; // Unsupported escape character - } - } - - Allocator* ownAllocator_; - Allocator* allocator_; - Stack states_; - Stack ranges_; - SizeType root_; - SizeType stateCount_; - SizeType rangeCount_; - - static const unsigned kInfinityQuantifier = ~0u; - - // For SearchWithAnchoring() - bool anchorBegin_; - bool anchorEnd_; -}; - -template -class GenericRegexSearch { -public: - typedef typename RegexType::EncodingType Encoding; - typedef typename Encoding::Ch Ch; - - GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : - regex_(regex), allocator_(allocator), ownAllocator_(0), - state0_(allocator, 0), state1_(allocator, 0), stateSet_() - { - RAPIDJSON_ASSERT(regex_.IsValid()); - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); - state0_.template Reserve(regex_.stateCount_); - state1_.template Reserve(regex_.stateCount_); - } - - ~GenericRegexSearch() { - Allocator::Free(stateSet_); - RAPIDJSON_DELETE(ownAllocator_); - } - - template - bool Match(InputStream& is) { - return SearchWithAnchoring(is, true, true); - } - - bool Match(const Ch* s) { - GenericStringStream is(s); - return Match(is); - } - - template - bool Search(InputStream& is) { - return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); - } - - bool Search(const Ch* s) { - GenericStringStream is(s); - return Search(is); - } - -private: - typedef typename RegexType::State State; - typedef typename RegexType::Range Range; - - template - bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { - DecodedStream ds(is); - - state0_.Clear(); - Stack *current = &state0_, *next = &state1_; - const size_t stateSetSize = GetStateSetSize(); - std::memset(stateSet_, 0, stateSetSize); - - bool matched = AddState(*current, regex_.root_); - unsigned codepoint; - while (!current->Empty() && (codepoint = ds.Take()) != 0) { - std::memset(stateSet_, 0, stateSetSize); - next->Clear(); - matched = false; - for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { - const State& sr = regex_.GetState(*s); - if (sr.codepoint == codepoint || - sr.codepoint == RegexType::kAnyCharacterClass || - (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) - { - matched = AddState(*next, sr.out) || matched; - if (!anchorEnd && matched) - return true; - } - if (!anchorBegin) - AddState(*next, regex_.root_); - } - internal::Swap(current, next); - } - - return matched; - } - - size_t GetStateSetSize() const { - return (regex_.stateCount_ + 31) / 32 * 4; - } - - // Return whether the added states is a match state - bool AddState(Stack& l, SizeType index) { - RAPIDJSON_ASSERT(index != kRegexInvalidState); - - const State& s = regex_.GetState(index); - if (s.out1 != kRegexInvalidState) { // Split - bool matched = AddState(l, s.out); - return AddState(l, s.out1) || matched; - } - else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { - stateSet_[index >> 5] |= (1u << (index & 31)); - *l.template PushUnsafe() = index; - } - return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. - } - - bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { - bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; - while (rangeIndex != kRegexInvalidRange) { - const Range& r = regex_.GetRange(rangeIndex); - if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) - return yes; - rangeIndex = r.next; - } - return !yes; - } - - const RegexType& regex_; - Allocator* allocator_; - Allocator* ownAllocator_; - Stack state0_; - Stack state1_; - uint32_t* stateSet_; -}; - -typedef GenericRegex > Regex; -typedef GenericRegexSearch RegexSearch; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/stack.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/stack.h deleted file mode 100644 index 73abd706..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/stack.h +++ /dev/null @@ -1,232 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STACK_H_ -#define RAPIDJSON_INTERNAL_STACK_H_ - -#include "../allocators.h" -#include "swap.h" -#include - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -/////////////////////////////////////////////////////////////////////////////// -// Stack - -//! A type-unsafe stack for storing different types of data. -/*! \tparam Allocator Allocator for allocating stack memory. -*/ -template -class Stack { -public: - // Optimization note: Do not allocate memory for stack_ in constructor. - // Do it lazily when first Push() -> Expand() -> Resize(). - Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Stack(Stack&& rhs) - : allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(rhs.stack_), - stackTop_(rhs.stackTop_), - stackEnd_(rhs.stackEnd_), - initialCapacity_(rhs.initialCapacity_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.stack_ = 0; - rhs.stackTop_ = 0; - rhs.stackEnd_ = 0; - rhs.initialCapacity_ = 0; - } -#endif - - ~Stack() { - Destroy(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Stack& operator=(Stack&& rhs) { - if (&rhs != this) - { - Destroy(); - - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = rhs.stack_; - stackTop_ = rhs.stackTop_; - stackEnd_ = rhs.stackEnd_; - initialCapacity_ = rhs.initialCapacity_; - - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.stack_ = 0; - rhs.stackTop_ = 0; - rhs.stackEnd_ = 0; - rhs.initialCapacity_ = 0; - } - return *this; - } -#endif - - void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(stack_, rhs.stack_); - internal::Swap(stackTop_, rhs.stackTop_); - internal::Swap(stackEnd_, rhs.stackEnd_); - internal::Swap(initialCapacity_, rhs.initialCapacity_); - } - - void Clear() { stackTop_ = stack_; } - - void ShrinkToFit() { - if (Empty()) { - // If the stack is empty, completely deallocate the memory. - Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) - stack_ = 0; - stackTop_ = 0; - stackEnd_ = 0; - } - else - Resize(GetSize()); - } - - // Optimization note: try to minimize the size of this function for force inline. - // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. - template - RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { - // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) - Expand(count); - } - - template - RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { - Reserve(count); - return PushUnsafe(count); - } - - template - RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { - RAPIDJSON_ASSERT(stackTop_); - RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); - T* ret = reinterpret_cast(stackTop_); - stackTop_ += sizeof(T) * count; - return ret; - } - - template - T* Pop(size_t count) { - RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); - stackTop_ -= count * sizeof(T); - return reinterpret_cast(stackTop_); - } - - template - T* Top() { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stackTop_ - sizeof(T)); - } - - template - const T* Top() const { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stackTop_ - sizeof(T)); - } - - template - T* End() { return reinterpret_cast(stackTop_); } - - template - const T* End() const { return reinterpret_cast(stackTop_); } - - template - T* Bottom() { return reinterpret_cast(stack_); } - - template - const T* Bottom() const { return reinterpret_cast(stack_); } - - bool HasAllocator() const { - return allocator_ != 0; - } - - Allocator& GetAllocator() { - RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } - - bool Empty() const { return stackTop_ == stack_; } - size_t GetSize() const { return static_cast(stackTop_ - stack_); } - size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } - -private: - template - void Expand(size_t count) { - // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. - size_t newCapacity; - if (stack_ == 0) { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - newCapacity = initialCapacity_; - } else { - newCapacity = GetCapacity(); - newCapacity += (newCapacity + 1) / 2; - } - size_t newSize = GetSize() + sizeof(T) * count; - if (newCapacity < newSize) - newCapacity = newSize; - - Resize(newCapacity); - } - - void Resize(size_t newCapacity) { - const size_t size = GetSize(); // Backup the current size - stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); - stackTop_ = stack_ + size; - stackEnd_ = stack_ + newCapacity; - } - - void Destroy() { - Allocator::Free(stack_); - RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack - } - - // Prohibit copy constructor & assignment operator. - Stack(const Stack&); - Stack& operator=(const Stack&); - - Allocator* allocator_; - Allocator* ownAllocator_; - char *stack_; - char *stackTop_; - char *stackEnd_; - size_t initialCapacity_; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_STACK_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strfunc.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strfunc.h deleted file mode 100644 index b698a8f4..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strfunc.h +++ /dev/null @@ -1,83 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ -#define RAPIDJSON_INTERNAL_STRFUNC_H_ - -#include "../stream.h" -#include - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom strlen() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s Null-terminated input string. - \return Number of characters in the string. - \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. -*/ -template -inline SizeType StrLen(const Ch* s) { - RAPIDJSON_ASSERT(s != 0); - const Ch* p = s; - while (*p) ++p; - return SizeType(p - s); -} - -template <> -inline SizeType StrLen(const char* s) { - return SizeType(std::strlen(s)); -} - -template <> -inline SizeType StrLen(const wchar_t* s) { - return SizeType(std::wcslen(s)); -} - -//! Custom strcmpn() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s1 Null-terminated input string. - \param s2 Null-terminated input string. - \return 0 if equal -*/ -template -inline int StrCmp(const Ch* s1, const Ch* s2) { - RAPIDJSON_ASSERT(s1 != 0); - RAPIDJSON_ASSERT(s2 != 0); - while(*s1 && (*s1 == *s2)) { s1++; s2++; } - return static_cast(*s1) < static_cast(*s2) ? -1 : static_cast(*s1) > static_cast(*s2); -} - -//! Returns number of code points in a encoded string. -template -bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { - RAPIDJSON_ASSERT(s != 0); - RAPIDJSON_ASSERT(outCount != 0); - GenericStringStream is(s); - const typename Encoding::Ch* end = s + length; - SizeType count = 0; - while (is.src_ < end) { - unsigned codepoint; - if (!Encoding::Decode(is, &codepoint)) - return false; - count++; - } - *outCount = count; - return true; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strtod.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strtod.h deleted file mode 100644 index 55f0e380..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/strtod.h +++ /dev/null @@ -1,293 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRTOD_ -#define RAPIDJSON_STRTOD_ - -#include "ieee754.h" -#include "biginteger.h" -#include "diyfp.h" -#include "pow10.h" -#include -#include - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline double FastPath(double significand, int exp) { - if (exp < -308) - return 0.0; - else if (exp >= 0) - return significand * internal::Pow10(exp); - else - return significand / internal::Pow10(-exp); -} - -inline double StrtodNormalPrecision(double d, int p) { - if (p < -308) { - // Prevent expSum < -308, making Pow10(p) = 0 - d = FastPath(d, -308); - d = FastPath(d, p + 308); - } - else - d = FastPath(d, p); - return d; -} - -template -inline T Min3(T a, T b, T c) { - T m = a; - if (m > b) m = b; - if (m > c) m = c; - return m; -} - -inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { - const Double db(b); - const uint64_t bInt = db.IntegerSignificand(); - const int bExp = db.IntegerExponent(); - const int hExp = bExp - 1; - - int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; - - // Adjust for decimal exponent - if (dExp >= 0) { - dS_Exp2 += dExp; - dS_Exp5 += dExp; - } - else { - bS_Exp2 -= dExp; - bS_Exp5 -= dExp; - hS_Exp2 -= dExp; - hS_Exp5 -= dExp; - } - - // Adjust for binary exponent - if (bExp >= 0) - bS_Exp2 += bExp; - else { - dS_Exp2 -= bExp; - hS_Exp2 -= bExp; - } - - // Adjust for half ulp exponent - if (hExp >= 0) - hS_Exp2 += hExp; - else { - dS_Exp2 -= hExp; - bS_Exp2 -= hExp; - } - - // Remove common power of two factor from all three scaled values - int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); - dS_Exp2 -= common_Exp2; - bS_Exp2 -= common_Exp2; - hS_Exp2 -= common_Exp2; - - BigInteger dS = d; - dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); - - BigInteger bS(bInt); - bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); - - BigInteger hS(1); - hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); - - BigInteger delta(0); - dS.Difference(bS, &delta); - - return delta.Compare(hS); -} - -inline bool StrtodFast(double d, int p, double* result) { - // Use fast path for string-to-double conversion if possible - // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - if (p > 22 && p < 22 + 16) { - // Fast Path Cases In Disguise - d *= internal::Pow10(p - 22); - p = 22; - } - - if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 - *result = FastPath(d, p); - return true; - } - else - return false; -} - -// Compute an approximation and see if it is within 1/2 ULP -template -inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) { - uint64_t significand = 0; - int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 - for (; i < dLen; i++) { - if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || - (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5'))) - break; - significand = significand * 10u + static_cast(decimals[i] - Ch('0')); - } - - if (i < dLen && decimals[i] >= Ch('5')) // Rounding - significand++; - - int remaining = dLen - i; - const int kUlpShift = 3; - const int kUlp = 1 << kUlpShift; - int64_t error = (remaining == 0) ? 0 : kUlp / 2; - - DiyFp v(significand, 0); - v = v.Normalize(); - error <<= -v.e; - - dExp += remaining; - - int actualExp; - DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); - if (actualExp != dExp) { - static const DiyFp kPow10[] = { - DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 - DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 - DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 - DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 - DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 - DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 - DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 - }; - int adjustment = dExp - actualExp; - RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); - v = v * kPow10[adjustment - 1]; - if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit - error += kUlp / 2; - } - - v = v * cachedPower; - - error += kUlp + (error == 0 ? 0 : 1); - - const int oldExp = v.e; - v = v.Normalize(); - error <<= oldExp - v.e; - - const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - int precisionSize = 64 - effectiveSignificandSize; - if (precisionSize + kUlpShift >= 64) { - int scaleExp = (precisionSize + kUlpShift) - 63; - v.f >>= scaleExp; - v.e += scaleExp; - error = (error >> scaleExp) + 1 + kUlp; - precisionSize -= scaleExp; - } - - DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); - const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; - const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + static_cast(error)) { - rounded.f++; - if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) - rounded.f >>= 1; - rounded.e++; - } - } - - *result = rounded.ToDouble(); - - return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); -} - -template -inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) { - RAPIDJSON_ASSERT(dLen >= 0); - const BigInteger dInt(decimals, static_cast(dLen)); - Double a(approx); - int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); - if (cmp < 0) - return a.Value(); // within half ULP - else if (cmp == 0) { - // Round towards even - if (a.Significand() & 1) - return a.NextPositiveDouble(); - else - return a.Value(); - } - else // adjustment - return a.NextPositiveDouble(); -} - -template -inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) { - RAPIDJSON_ASSERT(d >= 0.0); - RAPIDJSON_ASSERT(length >= 1); - - double result = 0.0; - if (StrtodFast(d, p, &result)) - return result; - - RAPIDJSON_ASSERT(length <= INT_MAX); - int dLen = static_cast(length); - - RAPIDJSON_ASSERT(length >= decimalPosition); - RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); - int dExpAdjust = static_cast(length - decimalPosition); - - RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); - int dExp = exp - dExpAdjust; - - // Make sure length+dExp does not overflow - RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); - - // Trim leading zeros - while (dLen > 0 && *decimals == '0') { - dLen--; - decimals++; - } - - // Trim trailing zeros - while (dLen > 0 && decimals[dLen - 1] == '0') { - dLen--; - dExp++; - } - - if (dLen == 0) { // Buffer only contains zeros. - return 0.0; - } - - // Trim right-most digits - const int kMaxDecimalDigit = 767 + 1; - if (dLen > kMaxDecimalDigit) { - dExp += dLen - kMaxDecimalDigit; - dLen = kMaxDecimalDigit; - } - - // If too small, underflow to zero. - // Any x <= 10^-324 is interpreted as zero. - if (dLen + dExp <= -324) - return 0.0; - - // If too large, overflow to infinity. - // Any x >= 10^309 is interpreted as +infinity. - if (dLen + dExp > 309) - return std::numeric_limits::infinity(); - - if (StrtodDiyFp(decimals, dLen, dExp, &result)) - return result; - - // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison - return StrtodBigInteger(result, decimals, dLen, dExp); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STRTOD_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/swap.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/swap.h deleted file mode 100644 index 2cf92f93..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/internal/swap.h +++ /dev/null @@ -1,46 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_SWAP_H_ -#define RAPIDJSON_INTERNAL_SWAP_H_ - -#include "../rapidjson.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom swap() to avoid dependency on C++ header -/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. - \note This has the same semantics as std::swap(). -*/ -template -inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { - T tmp = a; - a = b; - b = tmp; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/istreamwrapper.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/istreamwrapper.h deleted file mode 100644 index 01437ec0..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/istreamwrapper.h +++ /dev/null @@ -1,128 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ -#define RAPIDJSON_ISTREAMWRAPPER_H_ - -#include "stream.h" -#include -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::istringstream - - \c std::stringstream - - \c std::wistringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wifstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_istream. -*/ - -template -class BasicIStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - - //! Constructor. - /*! - \param stream stream opened for read. - */ - BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - Read(); - } - - //! Constructor. - /*! - \param stream stream opened for read. - \param buffer user-supplied buffer. - \param bufferSize size of buffer in bytes. Must >=4 bytes. - */ - BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); - } - - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; - } - -private: - BasicIStreamWrapper(); - BasicIStreamWrapper(const BasicIStreamWrapper&); - BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = bufferSize_; - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; - - if (!stream_.read(buffer_, static_cast(bufferSize_))) { - readCount_ = static_cast(stream_.gcount()); - *(bufferLast_ = buffer_ + readCount_) = '\0'; - eof_ = true; - } - } - } - - StreamType &stream_; - Ch peekBuffer_[4], *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; -}; - -typedef BasicIStreamWrapper IStreamWrapper; -typedef BasicIStreamWrapper WIStreamWrapper; - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorybuffer.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorybuffer.h deleted file mode 100644 index ffbc41ed..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorybuffer.h +++ /dev/null @@ -1,70 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_MEMORYBUFFER_H_ -#define RAPIDJSON_MEMORYBUFFER_H_ - -#include "stream.h" -#include "internal/stack.h" - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory output byte stream. -/*! - This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. - - It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. - - Differences between MemoryBuffer and StringBuffer: - 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. - 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. - - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept -*/ -template -struct GenericMemoryBuffer { - typedef char Ch; // byte - - GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - - void Put(Ch c) { *stack_.template Push() = c; } - void Flush() {} - - void Clear() { stack_.Clear(); } - void ShrinkToFit() { stack_.ShrinkToFit(); } - Ch* Push(size_t count) { return stack_.template Push(count); } - void Pop(size_t count) { stack_.template Pop(count); } - - const Ch* GetBuffer() const { - return stack_.template Bottom(); - } - - size_t GetSize() const { return stack_.GetSize(); } - - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; -}; - -typedef GenericMemoryBuffer<> MemoryBuffer; - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { - std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); -} - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorystream.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorystream.h deleted file mode 100644 index 77af6c99..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/memorystream.h +++ /dev/null @@ -1,71 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_MEMORYSTREAM_H_ -#define RAPIDJSON_MEMORYSTREAM_H_ - -#include "stream.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(missing-noreturn) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory input byte stream. -/*! - This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. - - It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. - - Differences between MemoryStream and StringStream: - 1. StringStream has encoding but MemoryStream is a byte stream. - 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. - 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). - \note implements Stream concept -*/ -struct MemoryStream { - typedef char Ch; // byte - - MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} - - Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } - Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } - size_t Tell() const { return static_cast(src_ - begin_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return Tell() + 4 <= size_ ? src_ : 0; - } - - const Ch* src_; //!< Current read position. - const Ch* begin_; //!< Original head of the string. - const Ch* end_; //!< End of stream. - size_t size_; //!< Size of the stream. -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/inttypes.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/inttypes.h deleted file mode 100644 index 18111286..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/inttypes.h +++ /dev/null @@ -1,316 +0,0 @@ -// ISO C9x compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2013 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the product nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -// The above software in this distribution may have been modified by -// THL A29 Limited ("Tencent Modifications"). -// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include "stdint.h" - -// miloyip: VC supports inttypes.h since VC2013 -#if _MSC_VER >= 1800 -#include -#else - -// 7.8 Format conversion of integer types - -typedef struct { - intmax_t quot; - intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 - -// The fprintf macros for signed integers are: -#define PRId8 "d" -#define PRIi8 "i" -#define PRIdLEAST8 "d" -#define PRIiLEAST8 "i" -#define PRIdFAST8 "d" -#define PRIiFAST8 "i" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIdLEAST16 "hd" -#define PRIiLEAST16 "hi" -#define PRIdFAST16 "hd" -#define PRIiFAST16 "hi" - -#define PRId32 "I32d" -#define PRIi32 "I32i" -#define PRIdLEAST32 "I32d" -#define PRIiLEAST32 "I32i" -#define PRIdFAST32 "I32d" -#define PRIiFAST32 "I32i" - -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIdLEAST64 "I64d" -#define PRIiLEAST64 "I64i" -#define PRIdFAST64 "I64d" -#define PRIiFAST64 "I64i" - -#define PRIdMAX "I64d" -#define PRIiMAX "I64i" - -#define PRIdPTR "Id" -#define PRIiPTR "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8 "o" -#define PRIu8 "u" -#define PRIx8 "x" -#define PRIX8 "X" -#define PRIoLEAST8 "o" -#define PRIuLEAST8 "u" -#define PRIxLEAST8 "x" -#define PRIXLEAST8 "X" -#define PRIoFAST8 "o" -#define PRIuFAST8 "u" -#define PRIxFAST8 "x" -#define PRIXFAST8 "X" - -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" -#define PRIoLEAST16 "ho" -#define PRIuLEAST16 "hu" -#define PRIxLEAST16 "hx" -#define PRIXLEAST16 "hX" -#define PRIoFAST16 "ho" -#define PRIuFAST16 "hu" -#define PRIxFAST16 "hx" -#define PRIXFAST16 "hX" - -#define PRIo32 "I32o" -#define PRIu32 "I32u" -#define PRIx32 "I32x" -#define PRIX32 "I32X" -#define PRIoLEAST32 "I32o" -#define PRIuLEAST32 "I32u" -#define PRIxLEAST32 "I32x" -#define PRIXLEAST32 "I32X" -#define PRIoFAST32 "I32o" -#define PRIuFAST32 "I32u" -#define PRIxFAST32 "I32x" -#define PRIXFAST32 "I32X" - -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#define PRIoLEAST64 "I64o" -#define PRIuLEAST64 "I64u" -#define PRIxLEAST64 "I64x" -#define PRIXLEAST64 "I64X" -#define PRIoFAST64 "I64o" -#define PRIuFAST64 "I64u" -#define PRIxFAST64 "I64x" -#define PRIXFAST64 "I64X" - -#define PRIoMAX "I64o" -#define PRIuMAX "I64u" -#define PRIxMAX "I64x" -#define PRIXMAX "I64X" - -#define PRIoPTR "Io" -#define PRIuPTR "Iu" -#define PRIxPTR "Ix" -#define PRIXPTR "IX" - -// The fscanf macros for signed integers are: -#define SCNd8 "d" -#define SCNi8 "i" -#define SCNdLEAST8 "d" -#define SCNiLEAST8 "i" -#define SCNdFAST8 "d" -#define SCNiFAST8 "i" - -#define SCNd16 "hd" -#define SCNi16 "hi" -#define SCNdLEAST16 "hd" -#define SCNiLEAST16 "hi" -#define SCNdFAST16 "hd" -#define SCNiFAST16 "hi" - -#define SCNd32 "ld" -#define SCNi32 "li" -#define SCNdLEAST32 "ld" -#define SCNiLEAST32 "li" -#define SCNdFAST32 "ld" -#define SCNiFAST32 "li" - -#define SCNd64 "I64d" -#define SCNi64 "I64i" -#define SCNdLEAST64 "I64d" -#define SCNiLEAST64 "I64i" -#define SCNdFAST64 "I64d" -#define SCNiFAST64 "I64i" - -#define SCNdMAX "I64d" -#define SCNiMAX "I64i" - -#ifdef _WIN64 // [ -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -#else // _WIN64 ][ -# define SCNdPTR "ld" -# define SCNiPTR "li" -#endif // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8 "o" -#define SCNu8 "u" -#define SCNx8 "x" -#define SCNX8 "X" -#define SCNoLEAST8 "o" -#define SCNuLEAST8 "u" -#define SCNxLEAST8 "x" -#define SCNXLEAST8 "X" -#define SCNoFAST8 "o" -#define SCNuFAST8 "u" -#define SCNxFAST8 "x" -#define SCNXFAST8 "X" - -#define SCNo16 "ho" -#define SCNu16 "hu" -#define SCNx16 "hx" -#define SCNX16 "hX" -#define SCNoLEAST16 "ho" -#define SCNuLEAST16 "hu" -#define SCNxLEAST16 "hx" -#define SCNXLEAST16 "hX" -#define SCNoFAST16 "ho" -#define SCNuFAST16 "hu" -#define SCNxFAST16 "hx" -#define SCNXFAST16 "hX" - -#define SCNo32 "lo" -#define SCNu32 "lu" -#define SCNx32 "lx" -#define SCNX32 "lX" -#define SCNoLEAST32 "lo" -#define SCNuLEAST32 "lu" -#define SCNxLEAST32 "lx" -#define SCNXLEAST32 "lX" -#define SCNoFAST32 "lo" -#define SCNuFAST32 "lu" -#define SCNxFAST32 "lx" -#define SCNXFAST32 "lX" - -#define SCNo64 "I64o" -#define SCNu64 "I64u" -#define SCNx64 "I64x" -#define SCNX64 "I64X" -#define SCNoLEAST64 "I64o" -#define SCNuLEAST64 "I64u" -#define SCNxLEAST64 "I64x" -#define SCNXLEAST64 "I64X" -#define SCNoFAST64 "I64o" -#define SCNuFAST64 "I64u" -#define SCNxFAST64 "I64x" -#define SCNXFAST64 "I64X" - -#define SCNoMAX "I64o" -#define SCNuMAX "I64u" -#define SCNxMAX "I64x" -#define SCNXMAX "I64X" - -#ifdef _WIN64 // [ -# define SCNoPTR "I64o" -# define SCNuPTR "I64u" -# define SCNxPTR "I64x" -# define SCNXPTR "I64X" -#else // _WIN64 ][ -# define SCNoPTR "lo" -# define SCNuPTR "lu" -# define SCNxPTR "lx" -# define SCNXPTR "lX" -#endif // _WIN64 ] - -#endif // __STDC_FORMAT_MACROS ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ - imaxdiv_t result; - - result.quot = numer / denom; - result.rem = numer % denom; - - if (numer < 0 && result.rem > 0) { - // did division wrong; must fix up - ++result.quot; - result.rem -= denom; - } - - return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - -#endif // _MSC_VER >= 1800 - -#endif // _MSC_INTTYPES_H_ ] diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/stdint.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/stdint.h deleted file mode 100644 index 3d4477b9..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/msinttypes/stdint.h +++ /dev/null @@ -1,300 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2013 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the product nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -// The above software in this distribution may have been modified by -// THL A29 Limited ("Tencent Modifications"). -// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. -#if _MSC_VER >= 1600 // [ -#include - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -#undef INT8_C -#undef INT16_C -#undef INT32_C -#undef INT64_C -#undef UINT8_C -#undef UINT16_C -#undef UINT32_C -#undef UINT64_C - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -// These #ifndef's are needed to prevent collisions with . -// Check out Issue 9 for the details. -#ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] -#ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C -#endif // UINTMAX_C ] - -#endif // __STDC_CONSTANT_MACROS ] - -#else // ] _MSC_VER >= 1700 [ - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we have to wrap include with 'extern "C++" {}' -// or compiler would give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#if defined(__cplusplus) && !defined(_M_ARM) -extern "C" { -#endif -# include -#if defined(__cplusplus) && !defined(_M_ARM) -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -// These #ifndef's are needed to prevent collisions with . -// Check out Issue 9 for the details. -#ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] -#ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C -#endif // UINTMAX_C ] - -#endif // __STDC_CONSTANT_MACROS ] - -#endif // _MSC_VER >= 1600 ] - -#endif // _MSC_STDINT_H_ ] diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/ostreamwrapper.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/ostreamwrapper.h deleted file mode 100644 index 11ed4d33..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/ostreamwrapper.h +++ /dev/null @@ -1,81 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ -#define RAPIDJSON_OSTREAMWRAPPER_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::ostringstream - - \c std::stringstream - - \c std::wpstringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wofstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_ostream. -*/ - -template -class BasicOStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} - - void Put(Ch c) { - stream_.put(c); - } - - void Flush() { - stream_.flush(); - } - - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - BasicOStreamWrapper(const BasicOStreamWrapper&); - BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); - - StreamType& stream_; -}; - -typedef BasicOStreamWrapper OStreamWrapper; -typedef BasicOStreamWrapper WOStreamWrapper; - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/pointer.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/pointer.h deleted file mode 100644 index 15723c67..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/pointer.h +++ /dev/null @@ -1,1470 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_POINTER_H_ -#define RAPIDJSON_POINTER_H_ - -#include "document.h" -#include "uri.h" -#include "internal/itoa.h" -#include "error/error.h" // PointerParseErrorCode - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token - -/////////////////////////////////////////////////////////////////////////////// -// GenericPointer - -//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. -/*! - This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" - (https://tools.ietf.org/html/rfc6901). - - A JSON pointer is for identifying a specific value in a JSON document - (GenericDocument). It can simplify coding of DOM tree manipulation, because it - can access multiple-level depth of DOM tree with single API call. - - After it parses a string representation (e.g. "/foo/0" or URI fragment - representation (e.g. "#/foo/0") into its internal representation (tokens), - it can be used to resolve a specific value in multiple documents, or sub-tree - of documents. - - Contrary to GenericValue, Pointer can be copy constructed and copy assigned. - Apart from assignment, a Pointer cannot be modified after construction. - - Although Pointer is very convenient, please aware that constructing Pointer - involves parsing and dynamic memory allocation. A special constructor with user- - supplied tokens eliminates these. - - GenericPointer depends on GenericDocument and GenericValue. - - \tparam ValueType The value type of the DOM tree. E.g. GenericValue > - \tparam Allocator The allocator type for allocating memory for internal representation. - - \note GenericPointer uses same encoding of ValueType. - However, Allocator of GenericPointer is independent of Allocator of Value. -*/ -template -class GenericPointer { -public: - typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value - typedef typename ValueType::Ch Ch; //!< Character type from Value - typedef GenericUri UriType; - - - //! A token is the basic units of internal representation. - /*! - A JSON pointer string representation "/foo/123" is parsed to two tokens: - "foo" and 123. 123 will be represented in both numeric form and string form. - They are resolved according to the actual value type (object or array). - - For token that are not numbers, or the numeric value is out of bound - (greater than limits of SizeType), they are only treated as string form - (i.e. the token's index will be equal to kPointerInvalidIndex). - - This struct is public so that user can create a Pointer without parsing and - allocation, using a special constructor. - */ - struct Token { - const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. - SizeType length; //!< Length of the name. - SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. - }; - - //!@name Constructors and destructor. - //@{ - - //! Default constructor. - GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} - - //! Constructor that parses a string or URI fragment representation. - /*! - \param source A null-terminated, string or URI fragment representation of JSON pointer. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - */ - explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source, internal::StrLen(source)); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Constructor that parses a string or URI fragment representation. - /*! - \param source A string or URI fragment representation of JSON pointer. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source.c_str(), source.size()); - } -#endif - - //! Constructor that parses a string or URI fragment representation, with length of the source string. - /*! - \param source A string or URI fragment representation of JSON pointer. - \param length Length of source. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - \note Slightly faster than the overload without length. - */ - GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source, length); - } - - //! Constructor with user-supplied tokens. - /*! - This constructor let user supplies const array of tokens. - This prevents the parsing process and eliminates allocation. - This is preferred for memory constrained environments. - - \param tokens An constant array of tokens representing the JSON pointer. - \param tokenCount Number of tokens. - - \b Example - \code - #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } - #define INDEX(i) { #i, sizeof(#i) - 1, i } - - static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; - static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); - // Equivalent to static const Pointer p("/foo/123"); - - #undef NAME - #undef INDEX - \endcode - */ - GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} - - //! Copy constructor. - GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - *this = rhs; - } - - //! Copy constructor. - GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - *this = rhs; - } - - //! Destructor. - ~GenericPointer() { - if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. - Allocator::Free(tokens_); - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Assignment operator. - GenericPointer& operator=(const GenericPointer& rhs) { - if (this != &rhs) { - // Do not delete ownAllocator - if (nameBuffer_) - Allocator::Free(tokens_); - - tokenCount_ = rhs.tokenCount_; - parseErrorOffset_ = rhs.parseErrorOffset_; - parseErrorCode_ = rhs.parseErrorCode_; - - if (rhs.nameBuffer_) - CopyFromRaw(rhs); // Normally parsed tokens. - else { - tokens_ = rhs.tokens_; // User supplied const tokens. - nameBuffer_ = 0; - } - } - return *this; - } - - //! Swap the content of this pointer with another. - /*! - \param other The pointer to swap with. - \note Constant complexity. - */ - GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { - internal::Swap(allocator_, other.allocator_); - internal::Swap(ownAllocator_, other.ownAllocator_); - internal::Swap(nameBuffer_, other.nameBuffer_); - internal::Swap(tokens_, other.tokens_); - internal::Swap(tokenCount_, other.tokenCount_); - internal::Swap(parseErrorOffset_, other.parseErrorOffset_); - internal::Swap(parseErrorCode_, other.parseErrorCode_); - return *this; - } - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.pointer, b.pointer); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //@} - - //!@name Append token - //@{ - - //! Append a token and return a new Pointer - /*! - \param token Token to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const Token& token, Allocator* allocator = 0) const { - GenericPointer r; - r.allocator_ = allocator; - Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); - std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); - r.tokens_[tokenCount_].name = p; - r.tokens_[tokenCount_].length = token.length; - r.tokens_[tokenCount_].index = token.index; - return r; - } - - //! Append a name token with length, and return a new Pointer - /*! - \param name Name to be appended. - \param length Length of name. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { - Token token = { name, length, kPointerInvalidIndex }; - return Append(token, allocator); - } - - //! Append a name token without length, and return a new Pointer - /*! - \param name Name (const Ch*) to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) - Append(T* name, Allocator* allocator = 0) const { - return Append(name, internal::StrLen(name), allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Append a name token, and return a new Pointer - /*! - \param name Name to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { - return Append(name.c_str(), static_cast(name.size()), allocator); - } -#endif - - //! Append a index token, and return a new Pointer - /*! - \param index Index to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(SizeType index, Allocator* allocator = 0) const { - char buffer[21]; - char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); - SizeType length = static_cast(end - buffer); - buffer[length] = '\0'; - - if (sizeof(Ch) == 1) { - Token token = { reinterpret_cast(buffer), length, index }; - return Append(token, allocator); - } - else { - Ch name[21]; - for (size_t i = 0; i <= length; i++) - name[i] = static_cast(buffer[i]); - Token token = { name, length, index }; - return Append(token, allocator); - } - } - - //! Append a token by value, and return a new Pointer - /*! - \param token token to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { - if (token.IsString()) - return Append(token.GetString(), token.GetStringLength(), allocator); - else { - RAPIDJSON_ASSERT(token.IsUint64()); - RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); - return Append(static_cast(token.GetUint64()), allocator); - } - } - - //!@name Handling Parse Error - //@{ - - //! Check whether this is a valid pointer. - bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } - - //! Get the parsing error offset in code unit. - size_t GetParseErrorOffset() const { return parseErrorOffset_; } - - //! Get the parsing error code. - PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } - - //@} - - //! Get the allocator of this pointer. - Allocator& GetAllocator() { return *allocator_; } - - //!@name Tokens - //@{ - - //! Get the token array (const version only). - const Token* GetTokens() const { return tokens_; } - - //! Get the number of tokens. - size_t GetTokenCount() const { return tokenCount_; } - - //@} - - //!@name Equality/inequality operators - //@{ - - //! Equality operator. - /*! - \note When any pointers are invalid, always returns false. - */ - bool operator==(const GenericPointer& rhs) const { - if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) - return false; - - for (size_t i = 0; i < tokenCount_; i++) { - if (tokens_[i].index != rhs.tokens_[i].index || - tokens_[i].length != rhs.tokens_[i].length || - (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) - { - return false; - } - } - - return true; - } - - //! Inequality operator. - /*! - \note When any pointers are invalid, always returns true. - */ - bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } - - //! Less than operator. - /*! - \note Invalid pointers are always greater than valid ones. - */ - bool operator<(const GenericPointer& rhs) const { - if (!IsValid()) - return false; - if (!rhs.IsValid()) - return true; - - if (tokenCount_ != rhs.tokenCount_) - return tokenCount_ < rhs.tokenCount_; - - for (size_t i = 0; i < tokenCount_; i++) { - if (tokens_[i].index != rhs.tokens_[i].index) - return tokens_[i].index < rhs.tokens_[i].index; - - if (tokens_[i].length != rhs.tokens_[i].length) - return tokens_[i].length < rhs.tokens_[i].length; - - if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) - return cmp < 0; - } - - return false; - } - - //@} - - //!@name Stringify - //@{ - - //! Stringify the pointer into string representation. - /*! - \tparam OutputStream Type of output stream. - \param os The output stream. - */ - template - bool Stringify(OutputStream& os) const { - return Stringify(os); - } - - //! Stringify the pointer into URI fragment representation. - /*! - \tparam OutputStream Type of output stream. - \param os The output stream. - */ - template - bool StringifyUriFragment(OutputStream& os) const { - return Stringify(os); - } - - //@} - - //!@name Create value - //@{ - - //! Create a value in a subtree. - /*! - If the value is not exist, it creates all parent values and a JSON Null value. - So it always succeed and return the newly created or existing value. - - Remind that it may change types of parents according to tokens, so it - potentially removes previously stored values. For example, if a document - was an array, and "/foo" is used to create a value, then the document - will be changed to an object, and all existing array elements are lost. - - \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \param alreadyExist If non-null, it stores whether the resolved value is already exist. - \return The resolved newly created (a JSON Null value), or already exists value. - */ - ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - bool exist = true; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - if (v->IsArray() && t->name[0] == '-' && t->length == 1) { - v->PushBack(ValueType().Move(), allocator); - v = &((*v)[v->Size() - 1]); - exist = false; - } - else { - if (t->index == kPointerInvalidIndex) { // must be object name - if (!v->IsObject()) - v->SetObject(); // Change to Object - } - else { // object name or array index - if (!v->IsArray() && !v->IsObject()) - v->SetArray(); // Change to Array - } - - if (v->IsArray()) { - if (t->index >= v->Size()) { - v->Reserve(t->index + 1, allocator); - while (t->index >= v->Size()) - v->PushBack(ValueType().Move(), allocator); - exist = false; - } - v = &((*v)[t->index]); - } - else { - typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) { - v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); - m = v->MemberEnd(); - v = &(--m)->value; // Assumes AddMember() appends at the end - exist = false; - } - else - v = &m->value; - } - } - } - - if (alreadyExist) - *alreadyExist = exist; - - return *v; - } - - //! Creates a value in a document. - /*! - \param document A document to be resolved. - \param alreadyExist If non-null, it stores whether the resolved value is already exist. - \return The resolved newly created, or already exists value. - */ - template - ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { - return Create(document, document.GetAllocator(), alreadyExist); - } - - //@} - - //!@name Compute URI - //@{ - - //! Compute the in-scope URI for a subtree. - // For use with JSON pointers into JSON schema documents. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param rootUri Root URI - \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. - \param allocator Allocator for Uris - \return Uri if it can be resolved. Otherwise null. - - \note - There are only 3 situations when a URI cannot be resolved: - 1. A value in the path is neither an array nor object. - 2. An object value does not contain the token. - 3. A token is out of range of an array value. - - Use unresolvedTokenIndex to retrieve the token index. - */ - UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { - static const Ch kIdString[] = { 'i', 'd', '\0' }; - static const ValueType kIdValue(kIdString, 2); - UriType base = UriType(rootUri, allocator); - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - switch (v->GetType()) { - case kObjectType: - { - // See if we have an id, and if so resolve with the current base - typename ValueType::MemberIterator m = v->FindMember(kIdValue); - if (m != v->MemberEnd() && (m->value).IsString()) { - UriType here = UriType(m->value, allocator).Resolve(base, allocator); - base = here; - } - m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) - break; - v = &m->value; - } - continue; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - break; - v = &((*v)[t->index]); - continue; - default: - break; - } - - // Error: unresolved token - if (unresolvedTokenIndex) - *unresolvedTokenIndex = static_cast(t - tokens_); - return UriType(allocator); - } - return base; - } - - UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { - return GetUri(const_cast(root), rootUri, unresolvedTokenIndex, allocator); - } - - - //!@name Query value - //@{ - - //! Query a value in a subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. - \return Pointer to the value if it can be resolved. Otherwise null. - - \note - There are only 3 situations when a value cannot be resolved: - 1. A value in the path is neither an array nor object. - 2. An object value does not contain the token. - 3. A token is out of range of an array value. - - Use unresolvedTokenIndex to retrieve the token index. - */ - ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - switch (v->GetType()) { - case kObjectType: - { - typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) - break; - v = &m->value; - } - continue; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - break; - v = &((*v)[t->index]); - continue; - default: - break; - } - - // Error: unresolved token - if (unresolvedTokenIndex) - *unresolvedTokenIndex = static_cast(t - tokens_); - return 0; - } - return v; - } - - //! Query a const value in a const subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \return Pointer to the value if it can be resolved. Otherwise null. - */ - const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { - return Get(const_cast(root), unresolvedTokenIndex); - } - - //@} - - //!@name Query a value with default - //@{ - - //! Query a value in a subtree with default value. - /*! - Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. - So that this function always succeed. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param defaultValue Default value to be cloned if the value was not exists. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - ValueType& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); - } - - //! Query a value in a subtree with default null-terminated string. - ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - ValueType& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.SetString(defaultValue, allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Query a value in a subtree with default std::basic_string. - ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - ValueType& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.SetString(defaultValue, allocator); - } -#endif - - //! Query a value in a subtree with default primitive value. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { - return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); - } - - //! Query a value in a document with default value. - template - ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - - //! Query a value in a document with default null-terminated string. - template - ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Query a value in a document with default std::basic_string. - template - ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } -#endif - - //! Query a value in a document with default primitive value. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - GetWithDefault(GenericDocument& document, T defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - - //@} - - //!@name Set a value - //@{ - - //! Set a value in a subtree, with move semantics. - /*! - It creates all parents if they are not exist or types are different to the tokens. - So this function always succeeds but potentially remove existing values. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param value Value to be set. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = value; - } - - //! Set a value in a subtree, with copy semantics. - ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator).CopyFrom(value, allocator); - } - - //! Set a null-terminated string in a subtree. - ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value, allocator).Move(); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Set a std::basic_string in a subtree. - ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value, allocator).Move(); - } -#endif - - //! Set a primitive value in a subtree. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value).Move(); - } - - //! Set a value in a document, with move semantics. - template - ValueType& Set(GenericDocument& document, ValueType& value) const { - return Create(document) = value; - } - - //! Set a value in a document, with copy semantics. - template - ValueType& Set(GenericDocument& document, const ValueType& value) const { - return Create(document).CopyFrom(value, document.GetAllocator()); - } - - //! Set a null-terminated string in a document. - template - ValueType& Set(GenericDocument& document, const Ch* value) const { - return Create(document) = ValueType(value, document.GetAllocator()).Move(); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Sets a std::basic_string in a document. - template - ValueType& Set(GenericDocument& document, const std::basic_string& value) const { - return Create(document) = ValueType(value, document.GetAllocator()).Move(); - } -#endif - - //! Set a primitive value in a document. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - Set(GenericDocument& document, T value) const { - return Create(document) = value; - } - - //@} - - //!@name Swap a value - //@{ - - //! Swap a value with a value in a subtree. - /*! - It creates all parents if they are not exist or types are different to the tokens. - So this function always succeeds but potentially remove existing values. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param value Value to be swapped. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator).Swap(value); - } - - //! Swap a value with a value in a document. - template - ValueType& Swap(GenericDocument& document, ValueType& value) const { - return Create(document).Swap(value); - } - - //@} - - //! Erase a value in a subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \return Whether the resolved value is found and erased. - - \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. - */ - bool Erase(ValueType& root) const { - RAPIDJSON_ASSERT(IsValid()); - if (tokenCount_ == 0) // Cannot erase the root - return false; - - ValueType* v = &root; - const Token* last = tokens_ + (tokenCount_ - 1); - for (const Token *t = tokens_; t != last; ++t) { - switch (v->GetType()) { - case kObjectType: - { - typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) - return false; - v = &m->value; - } - break; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - return false; - v = &((*v)[t->index]); - break; - default: - return false; - } - } - - switch (v->GetType()) { - case kObjectType: - return v->EraseMember(GenericStringRef(last->name, last->length)); - case kArrayType: - if (last->index == kPointerInvalidIndex || last->index >= v->Size()) - return false; - v->Erase(v->Begin() + last->index); - return true; - default: - return false; - } - } - -private: - //! Clone the content from rhs to this. - /*! - \param rhs Source pointer. - \param extraToken Extra tokens to be allocated. - \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. - \return Start of non-occupied name buffer, for storing extra names. - */ - Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { - if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens - for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) - nameBufferSize += t->length; - - tokenCount_ = rhs.tokenCount_ + extraToken; - tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); - nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - if (rhs.tokenCount_ > 0) { - std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); - } - if (nameBufferSize > 0) { - std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); - } - - // Adjust pointers to name buffer - std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; - for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) - t->name += diff; - - return nameBuffer_ + nameBufferSize; - } - - //! Check whether a character should be percent-encoded. - /*! - According to RFC 3986 2.3 Unreserved Characters. - \param c The character (code unit) to be tested. - */ - bool NeedPercentEncode(Ch c) const { - return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); - } - - //! Parse a JSON String or its URI fragment representation into tokens. -#ifndef __clang__ // -Wdocumentation - /*! - \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. - \param length Length of the source string. - \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. - */ -#endif - void Parse(const Ch* source, size_t length) { - RAPIDJSON_ASSERT(source != NULL); - RAPIDJSON_ASSERT(nameBuffer_ == 0); - RAPIDJSON_ASSERT(tokens_ == 0); - - // Create own allocator if user did not supply. - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - // Count number of '/' as tokenCount - tokenCount_ = 0; - for (const Ch* s = source; s != source + length; s++) - if (*s == '/') - tokenCount_++; - - Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); - Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - size_t i = 0; - - // Detect if it is a URI fragment - bool uriFragment = false; - if (source[i] == '#') { - uriFragment = true; - i++; - } - - if (i != length && source[i] != '/') { - parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; - goto error; - } - - while (i < length) { - RAPIDJSON_ASSERT(source[i] == '/'); - i++; // consumes '/' - - token->name = name; - bool isNumber = true; - - while (i < length && source[i] != '/') { - Ch c = source[i]; - if (uriFragment) { - // Decoding percent-encoding for URI fragment - if (c == '%') { - PercentDecodeStream is(&source[i], source + length); - GenericInsituStringStream os(name); - Ch* begin = os.PutBegin(); - if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { - parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; - goto error; - } - size_t len = os.PutEnd(begin); - i += is.Tell() - 1; - if (len == 1) - c = *name; - else { - name += len; - isNumber = false; - i++; - continue; - } - } - else if (NeedPercentEncode(c)) { - parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; - goto error; - } - } - - i++; - - // Escaping "~0" -> '~', "~1" -> '/' - if (c == '~') { - if (i < length) { - c = source[i]; - if (c == '0') c = '~'; - else if (c == '1') c = '/'; - else { - parseErrorCode_ = kPointerParseErrorInvalidEscape; - goto error; - } - i++; - } - else { - parseErrorCode_ = kPointerParseErrorInvalidEscape; - goto error; - } - } - - // First check for index: all of characters are digit - if (c < '0' || c > '9') - isNumber = false; - - *name++ = c; - } - token->length = static_cast(name - token->name); - if (token->length == 0) - isNumber = false; - *name++ = '\0'; // Null terminator - - // Second check for index: more than one digit cannot have leading zero - if (isNumber && token->length > 1 && token->name[0] == '0') - isNumber = false; - - // String to SizeType conversion - SizeType n = 0; - if (isNumber) { - for (size_t j = 0; j < token->length; j++) { - SizeType m = n * 10 + static_cast(token->name[j] - '0'); - if (m < n) { // overflow detection - isNumber = false; - break; - } - n = m; - } - } - - token->index = isNumber ? n : kPointerInvalidIndex; - token++; - } - - RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer - parseErrorCode_ = kPointerParseErrorNone; - return; - - error: - Allocator::Free(tokens_); - nameBuffer_ = 0; - tokens_ = 0; - tokenCount_ = 0; - parseErrorOffset_ = i; - return; - } - - //! Stringify to string or URI fragment representation. - /*! - \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. - \tparam OutputStream type of output stream. - \param os The output stream. - */ - template - bool Stringify(OutputStream& os) const { - RAPIDJSON_ASSERT(IsValid()); - - if (uriFragment) - os.Put('#'); - - for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - os.Put('/'); - for (size_t j = 0; j < t->length; j++) { - Ch c = t->name[j]; - if (c == '~') { - os.Put('~'); - os.Put('0'); - } - else if (c == '/') { - os.Put('~'); - os.Put('1'); - } - else if (uriFragment && NeedPercentEncode(c)) { - // Transcode to UTF8 sequence - GenericStringStream source(&t->name[j]); - PercentEncodeStream target(os); - if (!Transcoder >().Validate(source, target)) - return false; - j += source.Tell() - 1; - } - else - os.Put(c); - } - } - return true; - } - - //! A helper stream for decoding a percent-encoded sequence into code unit. - /*! - This stream decodes %XY triplet into code unit (0-255). - If it encounters invalid characters, it sets output code unit as 0 and - mark invalid, and to be checked by IsValid(). - */ - class PercentDecodeStream { - public: - typedef typename ValueType::Ch Ch; - - //! Constructor - /*! - \param source Start of the stream - \param end Past-the-end of the stream. - */ - PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} - - Ch Take() { - if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet - valid_ = false; - return 0; - } - src_++; - Ch c = 0; - for (int j = 0; j < 2; j++) { - c = static_cast(c << 4); - Ch h = *src_; - if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); - else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); - else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); - else { - valid_ = false; - return 0; - } - src_++; - } - return c; - } - - size_t Tell() const { return static_cast(src_ - head_); } - bool IsValid() const { return valid_; } - - private: - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. - const Ch* end_; //!< Past-the-end position. - bool valid_; //!< Whether the parsing is valid. - }; - - //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. - template - class PercentEncodeStream { - public: - PercentEncodeStream(OutputStream& os) : os_(os) {} - void Put(char c) { // UTF-8 must be byte - unsigned char u = static_cast(c); - static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - os_.Put('%'); - os_.Put(static_cast(hexDigits[u >> 4])); - os_.Put(static_cast(hexDigits[u & 15])); - } - private: - OutputStream& os_; - }; - - Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. - Allocator* ownAllocator_; //!< Allocator owned by this Pointer. - Ch* nameBuffer_; //!< A buffer containing all names in tokens. - Token* tokens_; //!< A list of tokens. - size_t tokenCount_; //!< Number of tokens in tokens_. - size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. - PointerParseErrorCode parseErrorCode_; //!< Parsing error code. -}; - -//! GenericPointer for Value (UTF-8, default allocator). -typedef GenericPointer Pointer; - -//!@name Helper functions for GenericPointer -//@{ - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { - return pointer.Create(root, a); -} - -template -typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Create(root, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { - return pointer.Create(document); -} - -template -typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Create(document); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { - return pointer.Get(root, unresolvedTokenIndex); -} - -template -const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { - return pointer.Get(root, unresolvedTokenIndex); -} - -template -typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { - return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); -} - -template -const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { - return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { - return pointer.Set(document, value); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { - return pointer.Set(document, value); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { - return GenericPointer(source, N - 1).Set(document, value); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Swap(root, value, a); -} - -template -typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Swap(root, value, a); -} - -template -typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { - return pointer.Swap(document, value); -} - -template -typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Swap(document, value); -} - -////////////////////////////////////////////////////////////////////////////// - -template -bool EraseValueByPointer(T& root, const GenericPointer& pointer) { - return pointer.Erase(root); -} - -template -bool EraseValueByPointer(T& root, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Erase(root); -} - -//@} - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_POINTER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/prettywriter.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/prettywriter.h deleted file mode 100644 index fe45df1d..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/prettywriter.h +++ /dev/null @@ -1,277 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_PRETTYWRITER_H_ -#define RAPIDJSON_PRETTYWRITER_H_ - -#include "writer.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Combination of PrettyWriter format flags. -/*! \see PrettyWriter::SetFormatOptions - */ -enum PrettyFormatOptions { - kFormatDefault = 0, //!< Default pretty formatting. - kFormatSingleLineArray = 1 //!< Format arrays on a single line. -}; - -//! Writer with indentation and spacing. -/*! - \tparam OutputStream Type of output os. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam StackAllocator Type of allocator for allocating memory of stack. -*/ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> -class PrettyWriter : public Writer { -public: - typedef Writer Base; - typedef typename Base::Ch Ch; - - //! Constructor - /*! \param os Output stream. - \param allocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} - - - explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - PrettyWriter(PrettyWriter&& rhs) : - Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} -#endif - - //! Set custom indentation. - /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). - \param indentCharCount Number of indent characters for each indentation level. - \note The default indentation is 4 spaces. - */ - PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { - RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); - indentChar_ = indentChar; - indentCharCount_ = indentCharCount; - return *this; - } - - //! Set pretty writer formatting options. - /*! \param options Formatting options. - */ - PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { - formatOptions_ = options; - return *this; - } - - /*! @name Implementation of Handler - \see Handler - */ - //@{ - - bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); } - bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } - bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } - bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } - bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } - bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); } - bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } - - bool RawNumber(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - PrettyPrefix(kNumberType); - return Base::EndValue(Base::WriteString(str, length)); - } - - bool String(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - PrettyPrefix(kStringType); - return Base::EndValue(Base::WriteString(str, length)); - } - -#if RAPIDJSON_HAS_STDSTRING - bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); - } -#endif - - bool StartObject() { - PrettyPrefix(kObjectType); - new (Base::level_stack_.template Push()) typename Base::Level(false); - return Base::WriteStartObject(); - } - - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - -#if RAPIDJSON_HAS_STDSTRING - bool Key(const std::basic_string& str) { - return Key(str.data(), SizeType(str.size())); - } -#endif - - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object - RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value - - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - - if (!empty) { - Base::os_->Put('\n'); - WriteIndent(); - } - bool ret = Base::EndValue(Base::WriteEndObject()); - (void)ret; - RAPIDJSON_ASSERT(ret == true); - if (Base::level_stack_.Empty()) // end of json text - Base::Flush(); - return true; - } - - bool StartArray() { - PrettyPrefix(kArrayType); - new (Base::level_stack_.template Push()) typename Base::Level(true); - return Base::WriteStartArray(); - } - - bool EndArray(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - - if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { - Base::os_->Put('\n'); - WriteIndent(); - } - bool ret = Base::EndValue(Base::WriteEndArray()); - (void)ret; - RAPIDJSON_ASSERT(ret == true); - if (Base::level_stack_.Empty()) // end of json text - Base::Flush(); - return true; - } - - //@} - - /*! @name Convenience extensions */ - //@{ - - //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - - //@} - - //! Write a raw JSON value. - /*! - For user to write a stringified JSON as a value. - - \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. - \param length Length of the json. - \param type Type of the root of json. - \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. - */ - bool RawValue(const Ch* json, size_t length, Type type) { - RAPIDJSON_ASSERT(json != 0); - PrettyPrefix(type); - return Base::EndValue(Base::WriteRawValue(json, length)); - } - -protected: - void PrettyPrefix(Type type) { - (void)type; - if (Base::level_stack_.GetSize() != 0) { // this value is not at root - typename Base::Level* level = Base::level_stack_.template Top(); - - if (level->inArray) { - if (level->valueCount > 0) { - Base::os_->Put(','); // add comma if it is not the first element in array - if (formatOptions_ & kFormatSingleLineArray) - Base::os_->Put(' '); - } - - if (!(formatOptions_ & kFormatSingleLineArray)) { - Base::os_->Put('\n'); - WriteIndent(); - } - } - else { // in object - if (level->valueCount > 0) { - if (level->valueCount % 2 == 0) { - Base::os_->Put(','); - Base::os_->Put('\n'); - } - else { - Base::os_->Put(':'); - Base::os_->Put(' '); - } - } - else - Base::os_->Put('\n'); - - if (level->valueCount % 2 == 0) - WriteIndent(); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. - Base::hasRoot_ = true; - } - } - - void WriteIndent() { - size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, static_cast(indentChar_), count); - } - - Ch indentChar_; - unsigned indentCharCount_; - PrettyFormatOptions formatOptions_; - -private: - // Prohibit copy constructor & assignment operator. - PrettyWriter(const PrettyWriter&); - PrettyWriter& operator=(const PrettyWriter&); -}; - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/rapidjson.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/rapidjson.h deleted file mode 100644 index 00bdc3f6..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/rapidjson.h +++ /dev/null @@ -1,742 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_RAPIDJSON_H_ -#define RAPIDJSON_RAPIDJSON_H_ - -/*!\file rapidjson.h - \brief common definitions and configuration - - \see RAPIDJSON_CONFIG - */ - -/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration - \brief Configuration macros for library features - - Some RapidJSON features are configurable to adapt the library to a wide - variety of platforms, environments and usage scenarios. Most of the - features can be configured in terms of overridden or predefined - preprocessor macros at compile-time. - - Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. - - \note These macros should be given on the compiler command-line - (where applicable) to avoid inconsistent values when compiling - different translation units of a single application. - */ - -#include // malloc(), realloc(), free(), size_t -#include // memset(), memcpy(), memmove(), memcmp() - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_VERSION_STRING -// -// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. -// - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -// token stringification -#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) -#define RAPIDJSON_DO_STRINGIFY(x) #x - -// token concatenation -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y -//!@endcond - -/*! \def RAPIDJSON_MAJOR_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Major version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_MINOR_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Minor version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_PATCH_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Patch version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_VERSION_STRING - \ingroup RAPIDJSON_CONFIG - \brief Version of RapidJSON in ".." string format. -*/ -#define RAPIDJSON_MAJOR_VERSION 1 -#define RAPIDJSON_MINOR_VERSION 1 -#define RAPIDJSON_PATCH_VERSION 0 -#define RAPIDJSON_VERSION_STRING \ - RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NAMESPACE_(BEGIN|END) -/*! \def RAPIDJSON_NAMESPACE - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace - - In order to avoid symbol clashes and/or "One Definition Rule" errors - between multiple inclusions of (different versions of) RapidJSON in - a single binary, users can customize the name of the main RapidJSON - namespace. - - In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE - to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple - levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref - RAPIDJSON_NAMESPACE_END need to be defined as well: - - \code - // in some .cpp file - #define RAPIDJSON_NAMESPACE my::rapidjson - #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { - #define RAPIDJSON_NAMESPACE_END } } - #include "rapidjson/..." - \endcode - - \see rapidjson - */ -/*! \def RAPIDJSON_NAMESPACE_BEGIN - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace (opening expression) - \see RAPIDJSON_NAMESPACE -*/ -/*! \def RAPIDJSON_NAMESPACE_END - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace (closing expression) - \see RAPIDJSON_NAMESPACE -*/ -#ifndef RAPIDJSON_NAMESPACE -#define RAPIDJSON_NAMESPACE rapidjson -#endif -#ifndef RAPIDJSON_NAMESPACE_BEGIN -#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { -#endif -#ifndef RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_NAMESPACE_END } -#endif - -/////////////////////////////////////////////////////////////////////////////// -// __cplusplus macro - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN - -#if defined(_MSC_VER) -#define RAPIDJSON_CPLUSPLUS _MSVC_LANG -#else -#define RAPIDJSON_CPLUSPLUS __cplusplus -#endif - -//!@endcond - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_HAS_STDSTRING - -#ifndef RAPIDJSON_HAS_STDSTRING -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation -#else -#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default -#endif -/*! \def RAPIDJSON_HAS_STDSTRING - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for \c std::string - - By defining this preprocessor symbol to \c 1, several convenience functions for using - \ref rapidjson::GenericValue with \c std::string are enabled, especially - for construction and comparison. - - \hideinitializer -*/ -#endif // !defined(RAPIDJSON_HAS_STDSTRING) - -#if RAPIDJSON_HAS_STDSTRING -#include -#endif // RAPIDJSON_HAS_STDSTRING - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_USE_MEMBERSMAP - -/*! \def RAPIDJSON_USE_MEMBERSMAP - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for object members handling in a \c std::multimap - - By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object - members are stored in a \c std::multimap for faster lookup and deletion times, a - trade off with a slightly slower insertion time and a small object allocat(or)ed - memory overhead. - - \hideinitializer -*/ -#ifndef RAPIDJSON_USE_MEMBERSMAP -#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NO_INT64DEFINE - -/*! \def RAPIDJSON_NO_INT64DEFINE - \ingroup RAPIDJSON_CONFIG - \brief Use external 64-bit integer types. - - RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types - to be available at global scope. - - If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to - prevent RapidJSON from defining its own types. -*/ -#ifndef RAPIDJSON_NO_INT64DEFINE -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 -#include "msinttypes/stdint.h" -#include "msinttypes/inttypes.h" -#else -// Other compilers should have this. -#include -#include -#endif -//!@endcond -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_NO_INT64DEFINE -#endif -#endif // RAPIDJSON_NO_INT64TYPEDEF - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_FORCEINLINE - -#ifndef RAPIDJSON_FORCEINLINE -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && defined(NDEBUG) -#define RAPIDJSON_FORCEINLINE __forceinline -#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) -#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) -#else -#define RAPIDJSON_FORCEINLINE -#endif -//!@endcond -#endif // RAPIDJSON_FORCEINLINE - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ENDIAN -#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine -#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine - -//! Endianness of the machine. -/*! - \def RAPIDJSON_ENDIAN - \ingroup RAPIDJSON_CONFIG - - GCC 4.6 provided macro for detecting endianness of the target machine. But other - compilers may not have this. User can define RAPIDJSON_ENDIAN to either - \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. - - Default detection implemented with reference to - \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html - \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp -*/ -#ifndef RAPIDJSON_ENDIAN -// Detect with GCC 4.6's macro -# ifdef __BYTE_ORDER__ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __BYTE_ORDER__ -// Detect with GLIBC's endian.h -# elif defined(__GLIBC__) -# include -# if (__BYTE_ORDER == __LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif (__BYTE_ORDER == __BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __GLIBC__ -// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro -# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -// Detect with architecture macros -# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(RAPIDJSON_DOXYGEN_RUNNING) -# define RAPIDJSON_ENDIAN -# else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. -# endif -#endif // RAPIDJSON_ENDIAN - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_64BIT - -//! Whether using 64-bit architecture -#ifndef RAPIDJSON_64BIT -#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) -#define RAPIDJSON_64BIT 1 -#else -#define RAPIDJSON_64BIT 0 -#endif -#endif // RAPIDJSON_64BIT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ALIGN - -//! Data alignment of the machine. -/*! \ingroup RAPIDJSON_CONFIG - \param x pointer to align - - Some machines require strict data alignment. The default is 8 bytes. - User can customize by defining the RAPIDJSON_ALIGN function macro. -*/ -#ifndef RAPIDJSON_ALIGN -#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_UINT64_C2 - -//! Construct a 64-bit literal by a pair of 32-bit integer. -/*! - 64-bit literal with or without ULL suffix is prone to compiler warnings. - UINT64_C() is C macro which cause compilation problems. - Use this macro to define 64-bit constants by a pair of 32-bit integer. -*/ -#ifndef RAPIDJSON_UINT64_C2 -#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_48BITPOINTER_OPTIMIZATION - -//! Use only lower 48-bit address for some pointers. -/*! - \ingroup RAPIDJSON_CONFIG - - This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. - The higher 16-bit can be used for storing other data. - \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. -*/ -#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 -#else -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 -#endif -#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION - -#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 -#if RAPIDJSON_64BIT != 1 -#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 -#endif -#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) -#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) -#else -#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) -#define RAPIDJSON_GETPOINTER(type, p) (p) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD - -/*! \def RAPIDJSON_SIMD - \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2/Neon optimization. - - RapidJSON supports optimized implementations for some parsing operations - based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel - or ARM compatible processors. - - To enable these optimizations, three different symbols can be defined; - \code - // Enable SSE2 optimization. - #define RAPIDJSON_SSE2 - - // Enable SSE4.2 optimization. - #define RAPIDJSON_SSE42 - \endcode - - // Enable ARM Neon optimization. - #define RAPIDJSON_NEON - \endcode - - \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. - - If any of these symbols is defined, RapidJSON defines the macro - \c RAPIDJSON_SIMD to indicate the availability of the optimized code. -*/ -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) -#define RAPIDJSON_SIMD -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NO_SIZETYPEDEFINE - -#ifndef RAPIDJSON_NO_SIZETYPEDEFINE -/*! \def RAPIDJSON_NO_SIZETYPEDEFINE - \ingroup RAPIDJSON_CONFIG - \brief User-provided \c SizeType definition. - - In order to avoid using 32-bit size types for indexing strings and arrays, - define this preprocessor symbol and provide the type rapidjson::SizeType - before including RapidJSON: - \code - #define RAPIDJSON_NO_SIZETYPEDEFINE - namespace rapidjson { typedef ::std::size_t SizeType; } - #include "rapidjson/..." - \endcode - - \see rapidjson::SizeType -*/ -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_NO_SIZETYPEDEFINE -#endif -RAPIDJSON_NAMESPACE_BEGIN -//! Size type (for string lengths, array sizes, etc.) -/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, - instead of using \c size_t. Users may override the SizeType by defining - \ref RAPIDJSON_NO_SIZETYPEDEFINE. -*/ -typedef unsigned SizeType; -RAPIDJSON_NAMESPACE_END -#endif - -// always import std::size_t to rapidjson namespace -RAPIDJSON_NAMESPACE_BEGIN -using std::size_t; -RAPIDJSON_NAMESPACE_END - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ASSERT - -//! Assertion. -/*! \ingroup RAPIDJSON_CONFIG - By default, rapidjson uses C \c assert() for internal assertions. - User can override it by defining RAPIDJSON_ASSERT(x) macro. - - \note Parsing errors are handled and can be customized by the - \ref RAPIDJSON_ERRORS APIs. -*/ -#ifndef RAPIDJSON_ASSERT - //#include - //#define RAPIDJSON_ASSERT(x) assert(x) - #define RAPIDJSON_ASSERT(x) -#endif // RAPIDJSON_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_STATIC_ASSERT - -// Prefer C++11 static_assert, if available -#ifndef RAPIDJSON_STATIC_ASSERT -#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) -#define RAPIDJSON_STATIC_ASSERT(x) \ - static_assert(x, RAPIDJSON_STRINGIFY(x)) -#endif // C++11 -#endif // RAPIDJSON_STATIC_ASSERT - -// Adopt C++03 implementation from boost -#ifndef RAPIDJSON_STATIC_ASSERT -#ifndef __clang__ -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#endif -RAPIDJSON_NAMESPACE_BEGIN -template struct STATIC_ASSERTION_FAILURE; -template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; -RAPIDJSON_NAMESPACE_END - -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) -#else -#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif -#ifndef __clang__ -//!@endcond -#endif - -/*! \def RAPIDJSON_STATIC_ASSERT - \brief (Internal) macro to check for conditions at compile-time - \param x compile-time condition - \hideinitializer - */ -#define RAPIDJSON_STATIC_ASSERT(x) \ - typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ - sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ - RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif // RAPIDJSON_STATIC_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY - -//! Compiler branching hint for expression with high probability to be true. -/*! - \ingroup RAPIDJSON_CONFIG - \param x Boolean expression likely to be true. -*/ -#ifndef RAPIDJSON_LIKELY -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) -#else -#define RAPIDJSON_LIKELY(x) (x) -#endif -#endif - -//! Compiler branching hint for expression with low probability to be true. -/*! - \ingroup RAPIDJSON_CONFIG - \param x Boolean expression unlikely to be true. -*/ -#ifndef RAPIDJSON_UNLIKELY -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define RAPIDJSON_UNLIKELY(x) (x) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Helpers - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN - -#define RAPIDJSON_MULTILINEMACRO_BEGIN do { -#define RAPIDJSON_MULTILINEMACRO_END \ -} while((void)0, 0) - -// adopted from Boost -#define RAPIDJSON_VERSION_CODE(x,y,z) \ - (((x)*100000) + ((y)*100) + (z)) - -#if defined(__has_builtin) -#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) -#else -#define RAPIDJSON_HAS_BUILTIN(x) 0 -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF - -#if defined(__GNUC__) -#define RAPIDJSON_GNUC \ - RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) -#endif - -#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) - -#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) -#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) -#define RAPIDJSON_DIAG_OFF(x) \ - RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) - -// push/pop support in Clang and GCC>=4.6 -#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) -#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) -#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) -#else // GCC >= 4.2, < 4.6 -#define RAPIDJSON_DIAG_PUSH /* ignored */ -#define RAPIDJSON_DIAG_POP /* ignored */ -#endif - -#elif defined(_MSC_VER) - -// pragma (MSVC specific) -#define RAPIDJSON_PRAGMA(x) __pragma(x) -#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) - -#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) -#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) -#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) - -#else - -#define RAPIDJSON_DIAG_OFF(x) /* ignored */ -#define RAPIDJSON_DIAG_PUSH /* ignored */ -#define RAPIDJSON_DIAG_POP /* ignored */ - -#endif // RAPIDJSON_DIAG_* - -/////////////////////////////////////////////////////////////////////////////// -// C++11 features - -#ifndef RAPIDJSON_HAS_CXX11 -#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L) -#endif - -#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS -#if RAPIDJSON_HAS_CXX11 -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#elif defined(__clang__) -#if __has_feature(cxx_rvalue_references) && \ - (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#else -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 -#endif -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1600) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) - -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#else -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 -#endif -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move -#endif - -#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT -#if RAPIDJSON_HAS_CXX11 -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 -#elif defined(__clang__) -#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1900) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 -#else -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 -#endif -#endif -#ifndef RAPIDJSON_NOEXCEPT -#if RAPIDJSON_HAS_CXX11_NOEXCEPT -#define RAPIDJSON_NOEXCEPT noexcept -#else -#define RAPIDJSON_NOEXCEPT throw() -#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT -#endif - -// no automatic detection, yet -#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS -#if (defined(_MSC_VER) && _MSC_VER >= 1700) -#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 -#else -#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 -#endif -#endif - -#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR -#if defined(__clang__) -#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1700) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 -#else -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 -#endif -#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR - -/////////////////////////////////////////////////////////////////////////////// -// C++17 features - -#ifndef RAPIDJSON_HAS_CXX17 -#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L) -#endif - -#if RAPIDJSON_HAS_CXX17 -# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] -#elif defined(__has_cpp_attribute) -# if __has_cpp_attribute(clang::fallthrough) -# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]] -# elif __has_cpp_attribute(fallthrough) -# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough)) -# else -# define RAPIDJSON_DELIBERATE_FALLTHROUGH -# endif -#else -# define RAPIDJSON_DELIBERATE_FALLTHROUGH -#endif - -//!@endcond - -//! Assertion (in non-throwing contexts). - /*! \ingroup RAPIDJSON_CONFIG - Some functions provide a \c noexcept guarantee, if the compiler supports it. - In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to - throw an exception. This macro adds a separate customization point for - such cases. - - Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is - supported, and to \ref RAPIDJSON_ASSERT otherwise. - */ - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NOEXCEPT_ASSERT - -#ifndef RAPIDJSON_NOEXCEPT_ASSERT -#ifdef RAPIDJSON_ASSERT_THROWS -#include -#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) -#else -#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) -#endif // RAPIDJSON_ASSERT_THROWS -#endif // RAPIDJSON_NOEXCEPT_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// malloc/realloc/free - -#ifndef RAPIDJSON_MALLOC -///! customization point for global \c malloc -#define RAPIDJSON_MALLOC(size) std::malloc(size) -#endif -#ifndef RAPIDJSON_REALLOC -///! customization point for global \c realloc -#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) -#endif -#ifndef RAPIDJSON_FREE -///! customization point for global \c free -#define RAPIDJSON_FREE(ptr) std::free(ptr) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// new/delete - -#ifndef RAPIDJSON_NEW -///! customization point for global \c new -#define RAPIDJSON_NEW(TypeName) new TypeName -#endif -#ifndef RAPIDJSON_DELETE -///! customization point for global \c delete -#define RAPIDJSON_DELETE(x) delete x -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Type - -/*! \namespace rapidjson - \brief main RapidJSON namespace - \see RAPIDJSON_NAMESPACE -*/ -RAPIDJSON_NAMESPACE_BEGIN - -//! Type of JSON value -enum Type { - kNullType = 0, //!< null - kFalseType = 1, //!< false - kTrueType = 2, //!< true - kObjectType = 3, //!< object - kArrayType = 4, //!< array - kStringType = 5, //!< string - kNumberType = 6 //!< number -}; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/reader.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/reader.h deleted file mode 100644 index 86c1f28e..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/reader.h +++ /dev/null @@ -1,2246 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_READER_H_ -#define RAPIDJSON_READER_H_ - -/*! \file reader.h */ - -#include "allocators.h" -#include "stream.h" -#include "encodedstream.h" -#include "internal/clzll.h" -#include "internal/meta.h" -#include "internal/stack.h" -#include "internal/strtod.h" -#include - -#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -#endif -#ifdef RAPIDJSON_SSE42 -#include -#elif defined(RAPIDJSON_SSE2) -#include -#elif defined(RAPIDJSON_NEON) -#include -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(old-style-cast) -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define RAPIDJSON_NOTHING /* deliberately empty */ -#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN -#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ - RAPIDJSON_MULTILINEMACRO_END -#endif -#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) -//!@endcond - -/*! \def RAPIDJSON_PARSE_ERROR_NORETURN - \ingroup RAPIDJSON_ERRORS - \brief Macro to indicate a parse error. - \param parseErrorCode \ref rapidjson::ParseErrorCode of the error - \param offset position of the error in JSON input (\c size_t) - - This macros can be used as a customization point for the internal - error handling mechanism of RapidJSON. - - A common usage model is to throw an exception instead of requiring the - caller to explicitly check the \ref rapidjson::GenericReader::Parse's - return value: - - \code - #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ - throw ParseException(parseErrorCode, #parseErrorCode, offset) - - #include // std::runtime_error - #include "rapidjson/error/error.h" // rapidjson::ParseResult - - struct ParseException : std::runtime_error, rapidjson::ParseResult { - ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) - : std::runtime_error(msg), ParseResult(code, offset) {} - }; - - #include "rapidjson/reader.h" - \endcode - - \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse - */ -#ifndef RAPIDJSON_PARSE_ERROR_NORETURN -#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ - SetParseError(parseErrorCode, offset); \ - RAPIDJSON_MULTILINEMACRO_END -#endif - -/*! \def RAPIDJSON_PARSE_ERROR - \ingroup RAPIDJSON_ERRORS - \brief (Internal) macro to indicate and handle a parse error. - \param parseErrorCode \ref rapidjson::ParseErrorCode of the error - \param offset position of the error in JSON input (\c size_t) - - Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. - - \see RAPIDJSON_PARSE_ERROR_NORETURN - \hideinitializer - */ -#ifndef RAPIDJSON_PARSE_ERROR -#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ - RAPIDJSON_MULTILINEMACRO_END -#endif - -#include "error/error.h" // ParseErrorCode, ParseResult - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseFlag - -/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kParseDefaultFlags definition. - - User can define this as any \c ParseFlag combinations. -*/ -#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS -#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags -#endif - -//! Combination of parseFlags -/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream - */ -enum ParseFlag { - kParseNoFlags = 0, //!< No flags are set. - kParseInsituFlag = 1, //!< In-situ(destructive) parsing. - kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. - kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. - kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. - kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). - kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. - kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. - kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. - kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. - kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. - kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS -}; - -/////////////////////////////////////////////////////////////////////////////// -// Handler - -/*! \class rapidjson::Handler - \brief Concept for receiving events from GenericReader upon parsing. - The functions return true if no error occurs. If they return false, - the event publisher should terminate the process. -\code -concept Handler { - typename Ch; - - bool Null(); - bool Bool(bool b); - bool Int(int i); - bool Uint(unsigned i); - bool Int64(int64_t i); - bool Uint64(uint64_t i); - bool Double(double d); - /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) - bool RawNumber(const Ch* str, SizeType length, bool copy); - bool String(const Ch* str, SizeType length, bool copy); - bool StartObject(); - bool Key(const Ch* str, SizeType length, bool copy); - bool EndObject(SizeType memberCount); - bool StartArray(); - bool EndArray(SizeType elementCount); -}; -\endcode -*/ -/////////////////////////////////////////////////////////////////////////////// -// BaseReaderHandler - -//! Default implementation of Handler. -/*! This can be used as base class of any reader handler. - \note implements Handler concept -*/ -template, typename Derived = void> -struct BaseReaderHandler { - typedef typename Encoding::Ch Ch; - - typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; - - bool Default() { return true; } - bool Null() { return static_cast(*this).Default(); } - bool Bool(bool) { return static_cast(*this).Default(); } - bool Int(int) { return static_cast(*this).Default(); } - bool Uint(unsigned) { return static_cast(*this).Default(); } - bool Int64(int64_t) { return static_cast(*this).Default(); } - bool Uint64(uint64_t) { return static_cast(*this).Default(); } - bool Double(double) { return static_cast(*this).Default(); } - /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) - bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } - bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } - bool StartObject() { return static_cast(*this).Default(); } - bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } - bool EndObject(SizeType) { return static_cast(*this).Default(); } - bool StartArray() { return static_cast(*this).Default(); } - bool EndArray(SizeType) { return static_cast(*this).Default(); } -}; - -/////////////////////////////////////////////////////////////////////////////// -// StreamLocalCopy - -namespace internal { - -template::copyOptimization> -class StreamLocalCopy; - -//! Do copy optimization. -template -class StreamLocalCopy { -public: - StreamLocalCopy(Stream& original) : s(original), original_(original) {} - ~StreamLocalCopy() { original_ = s; } - - Stream s; - -private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; - - Stream& original_; -}; - -//! Keep reference. -template -class StreamLocalCopy { -public: - StreamLocalCopy(Stream& original) : s(original) {} - - Stream& s; - -private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// SkipWhitespace - -//! Skip the JSON white spaces in a stream. -/*! \param is A input stream for skipping white spaces. - \note This function has SSE2/SSE4.2 specialization. -*/ -template -void SkipWhitespace(InputStream& is) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); - - typename InputStream::Ch c; - while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') - s.Take(); -} - -inline const char* SkipWhitespace(const char* p, const char* end) { - while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - return p; -} - -#ifdef RAPIDJSON_SSE42 -//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // The rest of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); - if (r != 16) // some of characters is non-whitespace - return p + r; - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - // The middle of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); - - for (; p <= end - 16; p += 16) { - const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); - if (r != 16) // some of characters is non-whitespace - return p + r; - } - - return SkipWhitespace(p, end); -} - -#elif defined(RAPIDJSON_SSE2) - -//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // The rest of string - #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } - static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; - #undef C16 - - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = static_cast(~_mm_movemask_epi8(x)); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - // The rest of string - #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } - static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; - #undef C16 - - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); - - for (; p <= end - 16; p += 16) { - const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = static_cast(~_mm_movemask_epi8(x)); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } - - return SkipWhitespace(p, end); -} - -#elif defined(RAPIDJSON_NEON) - -//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - const uint8x16_t w0 = vmovq_n_u8(' '); - const uint8x16_t w1 = vmovq_n_u8('\n'); - const uint8x16_t w2 = vmovq_n_u8('\r'); - const uint8x16_t w3 = vmovq_n_u8('\t'); - - for (;; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, w0); - x = vorrq_u8(x, vceqq_u8(s, w1)); - x = vorrq_u8(x, vceqq_u8(s, w2)); - x = vorrq_u8(x, vceqq_u8(s, w3)); - - x = vmvnq_u8(x); // Negate - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - return p + 8 + (lz >> 3); - } - } else { - uint32_t lz = internal::clzll(low); - return p + (lz >> 3); - } - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - const uint8x16_t w0 = vmovq_n_u8(' '); - const uint8x16_t w1 = vmovq_n_u8('\n'); - const uint8x16_t w2 = vmovq_n_u8('\r'); - const uint8x16_t w3 = vmovq_n_u8('\t'); - - for (; p <= end - 16; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, w0); - x = vorrq_u8(x, vceqq_u8(s, w1)); - x = vorrq_u8(x, vceqq_u8(s, w2)); - x = vorrq_u8(x, vceqq_u8(s, w3)); - - x = vmvnq_u8(x); // Negate - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - return p + 8 + (lz >> 3); - } - } else { - uint32_t lz = internal::clzll(low); - return p + (lz >> 3); - } - } - - return SkipWhitespace(p, end); -} - -#endif // RAPIDJSON_NEON - -#ifdef RAPIDJSON_SIMD -//! Template function specialization for InsituStringStream -template<> inline void SkipWhitespace(InsituStringStream& is) { - is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); -} - -//! Template function specialization for StringStream -template<> inline void SkipWhitespace(StringStream& is) { - is.src_ = SkipWhitespace_SIMD(is.src_); -} - -template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { - is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); -} -#endif // RAPIDJSON_SIMD - -/////////////////////////////////////////////////////////////////////////////// -// GenericReader - -//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. -/*! GenericReader parses JSON text from a stream, and send events synchronously to an - object implementing Handler concept. - - It needs to allocate a stack for storing a single decoded string during - non-destructive parsing. - - For in-situ parsing, the decoded string is directly written to the source - text string, no temporary buffer is required. - - A GenericReader object can be reused for parsing multiple JSON text. - - \tparam SourceEncoding Encoding of the input stream. - \tparam TargetEncoding Encoding of the parse output. - \tparam StackAllocator Allocator type for stack. -*/ -template -class GenericReader { -public: - typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type - - //! Constructor. - /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) - \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) - */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : - stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} - - //! Parse JSON text. - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - if (parseFlags & kParseIterativeFlag) - return IterativeParse(is, handler); - - parseResult_.Clear(); - - ClearStackOnExit scope(*this); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - else { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (!(parseFlags & kParseStopWhenDoneFlag)) { - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - } - } - - return parseResult_; - } - - //! Parse JSON text (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - return Parse(is, handler); - } - - //! Initialize JSON text token-by-token parsing - /*! - */ - void IterativeParseInit() { - parseResult_.Clear(); - state_ = IterativeParsingStartState; - } - - //! Parse one token from JSON text - /*! \tparam InputStream Type of input stream, implementing Stream concept - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - bool IterativeParseNext(InputStream& is, Handler& handler) { - while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { - SkipWhitespaceAndComments(is); - - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state_, t); - IterativeParsingState d = Transit(state_, t, n, is, handler); - - // If we've finished or hit an error... - if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { - // Report errors. - if (d == IterativeParsingErrorState) { - HandleError(state_, is); - return false; - } - - // Transition to the finish state. - RAPIDJSON_ASSERT(d == IterativeParsingFinishState); - state_ = d; - - // If StopWhenDone is not set... - if (!(parseFlags & kParseStopWhenDoneFlag)) { - // ... and extra non-whitespace data is found... - SkipWhitespaceAndComments(is); - if (is.Peek() != '\0') { - // ... this is considered an error. - HandleError(state_, is); - return false; - } - } - - // Success! We are done! - return true; - } - - // Transition to the new state. - state_ = d; - - // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. - if (!IsIterativeParsingDelimiterState(n)) - return true; - } - - // We reached the end of file. - stack_.Clear(); - - if (state_ != IterativeParsingFinishState) { - HandleError(state_, is); - return false; - } - - return true; - } - - //! Check if token-by-token parsing JSON text is complete - /*! \return Whether the JSON has been fully decoded. - */ - RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const { - return IsIterativeParsingCompleteState(state_); - } - - //! Whether a parse error has occurred in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } - -protected: - void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } - -private: - // Prohibit copy constructor & assignment operator. - GenericReader(const GenericReader&); - GenericReader& operator=(const GenericReader&); - - void ClearStack() { stack_.Clear(); } - - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericReader& r) : r_(r) {} - ~ClearStackOnExit() { r_.ClearStack(); } - private: - GenericReader& r_; - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - }; - - template - void SkipWhitespaceAndComments(InputStream& is) { - SkipWhitespace(is); - - if (parseFlags & kParseCommentsFlag) { - while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { - if (Consume(is, '*')) { - while (true) { - if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - else if (Consume(is, '*')) { - if (Consume(is, '/')) - break; - } - else - is.Take(); - } - } - else if (RAPIDJSON_LIKELY(Consume(is, '/'))) - while (is.Peek() != '\0' && is.Take() != '\n') {} - else - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - - SkipWhitespace(is); - } - } - } - - // Parse object: { string : value, ... } - template - void ParseObject(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '{'); - is.Take(); // Skip '{' - - if (RAPIDJSON_UNLIKELY(!handler.StartObject())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, '}')) { - if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - - for (SizeType memberCount = 0;;) { - if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - - ParseString(is, handler, true); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ++memberCount; - - switch (is.Peek()) { - case ',': - is.Take(); - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - break; - case '}': - is.Take(); - if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - default: - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy - } - - if (parseFlags & kParseTrailingCommasFlag) { - if (is.Peek() == '}') { - if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - is.Take(); - return; - } - } - } - } - - // Parse array: [ value, ... ] - template - void ParseArray(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '['); - is.Take(); // Skip '[' - - if (RAPIDJSON_UNLIKELY(!handler.StartArray())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, ']')) { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - - for (SizeType elementCount = 0;;) { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ++elementCount; - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, ',')) { - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - } - else if (Consume(is, ']')) { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); - - if (parseFlags & kParseTrailingCommasFlag) { - if (is.Peek() == ']') { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - is.Take(); - return; - } - } - } - } - - template - void ParseNull(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'n'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { - if (RAPIDJSON_UNLIKELY(!handler.Null())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - void ParseTrue(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 't'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { - if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - void ParseFalse(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'f'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { - if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { - if (RAPIDJSON_LIKELY(is.Peek() == expect)) { - is.Take(); - return true; - } - else - return false; - } - - // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). - template - unsigned ParseHex4(InputStream& is, size_t escapeOffset) { - unsigned codepoint = 0; - for (int i = 0; i < 4; i++) { - Ch c = is.Peek(); - codepoint <<= 4; - codepoint += static_cast(c); - if (c >= '0' && c <= '9') - codepoint -= '0'; - else if (c >= 'A' && c <= 'F') - codepoint -= 'A' - 10; - else if (c >= 'a' && c <= 'f') - codepoint -= 'a' - 10; - else { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); - } - is.Take(); - } - return codepoint; - } - - template - class StackStream { - public: - typedef CharType Ch; - - StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} - RAPIDJSON_FORCEINLINE void Put(Ch c) { - *stack_.template Push() = c; - ++length_; - } - - RAPIDJSON_FORCEINLINE void* Push(SizeType count) { - length_ += count; - return stack_.template Push(count); - } - - size_t Length() const { return length_; } - - Ch* Pop() { - return stack_.template Pop(length_); - } - - private: - StackStream(const StackStream&); - StackStream& operator=(const StackStream&); - - internal::Stack& stack_; - SizeType length_; - }; - - // Parse string and generate String event. Different code paths for kParseInsituFlag. - template - void ParseString(InputStream& is, Handler& handler, bool isKey = false) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); - - RAPIDJSON_ASSERT(s.Peek() == '\"'); - s.Take(); // Skip '\"' - - bool success = false; - if (parseFlags & kParseInsituFlag) { - typename InputStream::Ch *head = s.PutBegin(); - ParseStringToStream(s, s); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - size_t length = s.PutEnd(head) - 1; - RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - const typename TargetEncoding::Ch* const str = reinterpret_cast(head); - success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); - } - else { - StackStream stackStream(stack_); - ParseStringToStream(s, stackStream); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SizeType length = static_cast(stackStream.Length()) - 1; - const typename TargetEncoding::Ch* const str = stackStream.Pop(); - success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); - } - if (RAPIDJSON_UNLIKELY(!success)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); - } - - // Parse string to an output is - // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. - template - RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', - Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, - 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, - 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 - }; -#undef Z16 -//!@endcond - - for (;;) { - // Scan and copy string before "\\\"" or < 0x20. This is an optional optimization. - if (!(parseFlags & kParseValidateEncodingFlag)) - ScanCopyUnescapedString(is, os); - - Ch c = is.Peek(); - if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape - size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset - is.Take(); - Ch e = is.Peek(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { - is.Take(); - os.Put(static_cast(escape[static_cast(e)])); - } - else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe - is.Take(); - os.Put('\''); - } - else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode - is.Take(); - unsigned codepoint = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) { - // high surrogate, check if followed by valid low surrogate - if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) { - // Handle UTF-16 surrogate pair - if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - unsigned codepoint2 = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; - } - // single low surrogate - else - { - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - } - } - TEncoding::Encode(os, codepoint); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); - } - else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote - is.Take(); - os.Put('\0'); // null-terminate the string - return; - } - else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF - if (c == '\0') - RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); - } - else { - size_t offset = is.Tell(); - if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? - !Transcoder::Validate(is, os) : - !Transcoder::Transcode(is, os)))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); - } - } - } - - template - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { - // Do nothing for generic version - } - -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) - // StringStream -> StackStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { - const char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - return; - } - else - os.Put(*p++); - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - SizeType length; - #ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; - #else - length = static_cast(__builtin_ffs(r) - 1); - #endif - if (length != 0) { - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; - - p += length; - } - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); - } - - is.src_ = p; - } - - // InsituStringStream -> InsituStringStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { - RAPIDJSON_ASSERT(&is == &os); - (void)os; - - if (is.src_ == is.dst_) { - SkipUnescapedString(is); - return; - } - - char* p = is.src_; - char *q = is.dst_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - is.dst_ = q; - return; - } - else - *q++ = *p++; - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16, q += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; -#else - length = static_cast(__builtin_ffs(r) - 1); -#endif - for (const char* pend = p + length; p != pend; ) - *q++ = *p++; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); - } - - is.src_ = p; - is.dst_ = q; - } - - // When read/write pointers are the same for insitu stream, just skip unescaped characters - static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { - RAPIDJSON_ASSERT(is.src_ == is.dst_); - char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - for (; p != nextAligned; p++) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = is.dst_ = p; - return; - } - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; -#else - length = static_cast(__builtin_ffs(r) - 1); -#endif - p += length; - break; - } - } - - is.src_ = is.dst_ = p; - } -#elif defined(RAPIDJSON_NEON) - // StringStream -> StackStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { - const char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - return; - } - else - os.Put(*p++); - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (;; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - SizeType length = 0; - bool escaped = false; - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - length = 8 + (lz >> 3); - escaped = true; - } - } else { - uint32_t lz = internal::clzll(low); - length = lz >> 3; - escaped = true; - } - if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped - if (length != 0) { - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; - - p += length; - } - break; - } - vst1q_u8(reinterpret_cast(os.Push(16)), s); - } - - is.src_ = p; - } - - // InsituStringStream -> InsituStringStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { - RAPIDJSON_ASSERT(&is == &os); - (void)os; - - if (is.src_ == is.dst_) { - SkipUnescapedString(is); - return; - } - - char* p = is.src_; - char *q = is.dst_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - is.dst_ = q; - return; - } - else - *q++ = *p++; - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (;; p += 16, q += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - SizeType length = 0; - bool escaped = false; - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - length = 8 + (lz >> 3); - escaped = true; - } - } else { - uint32_t lz = internal::clzll(low); - length = lz >> 3; - escaped = true; - } - if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped - for (const char* pend = p + length; p != pend; ) { - *q++ = *p++; - } - break; - } - vst1q_u8(reinterpret_cast(q), s); - } - - is.src_ = p; - is.dst_ = q; - } - - // When read/write pointers are the same for insitu stream, just skip unescaped characters - static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { - RAPIDJSON_ASSERT(is.src_ == is.dst_); - char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - for (; p != nextAligned; p++) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = is.dst_ = p; - return; - } - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (;; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - p += 8 + (lz >> 3); - break; - } - } else { - uint32_t lz = internal::clzll(low); - p += lz >> 3; - break; - } - } - - is.src_ = is.dst_ = p; - } -#endif // RAPIDJSON_NEON - - template - class NumberStream; - - template - class NumberStream { - public: - typedef typename InputStream::Ch Ch; - - NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - - RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } - RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } - RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char) {} - - size_t Tell() { return is.Tell(); } - size_t Length() { return 0; } - const StackCharacter* Pop() { return 0; } - - protected: - NumberStream& operator=(const NumberStream&); - - InputStream& is; - }; - - template - class NumberStream : public NumberStream { - typedef NumberStream Base; - public: - NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {} - - RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put(static_cast(Base::is.Peek())); - return Base::is.Take(); - } - - RAPIDJSON_FORCEINLINE void Push(StackCharacter c) { - stackStream.Put(c); - } - - size_t Length() { return stackStream.Length(); } - - const StackCharacter* Pop() { - stackStream.Put('\0'); - return stackStream.Pop(); - } - - private: - StackStream stackStream; - }; - - template - class NumberStream : public NumberStream { - typedef NumberStream Base; - public: - NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {} - - RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } - }; - - template - void ParseNumber(InputStream& is, Handler& handler) { - typedef typename internal::SelectIf, typename TargetEncoding::Ch, char>::Type NumberCharacter; - - internal::StreamLocalCopy copy(is); - NumberStream s(*this, copy.s); - - size_t startOffset = s.Tell(); - double d = 0.0; - bool useNanOrInf = false; - - // Parse minus - bool minus = Consume(s, '-'); - - // Parse int: zero / ( digit1-9 *DIGIT ) - unsigned i = 0; - uint64_t i64 = 0; - bool use64bit = false; - int significandDigit = 0; - if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { - i = 0; - s.TakePush(); - } - else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { - i = static_cast(s.TakePush() - '0'); - - if (minus) - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 - if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { - i64 = i; - use64bit = true; - break; - } - } - i = i * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - else - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 - if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { - i64 = i; - use64bit = true; - break; - } - } - i = i * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - } - // Parse NaN or Infinity here - else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - if (Consume(s, 'N')) { - if (Consume(s, 'a') && Consume(s, 'N')) { - d = std::numeric_limits::quiet_NaN(); - useNanOrInf = true; - } - } - else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { - if (Consume(s, 'n') && Consume(s, 'f')) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - useNanOrInf = true; - - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - } - } - } - - if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - - // Parse 64bit int - bool useDouble = false; - if (use64bit) { - if (minus) - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 - if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { - d = static_cast(i64); - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - else - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 - if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { - d = static_cast(i64); - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - } - - // Force double for big integer - if (useDouble) { - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - d = d * 10 + (s.TakePush() - '0'); - } - } - - // Parse frac = decimal-point 1*DIGIT - int expFrac = 0; - size_t decimalPosition; - if (Consume(s, '.')) { - decimalPosition = s.Length(); - - if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); - - if (!useDouble) { -#if RAPIDJSON_64BIT - // Use i64 to store significand in 64-bit architecture - if (!use64bit) - i64 = i; - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path - break; - else { - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - --expFrac; - if (i64 != 0) - significandDigit++; - } - } - - d = static_cast(i64); -#else - // Use double to store significand in 32-bit architecture - d = static_cast(use64bit ? i64 : i); -#endif - useDouble = true; - } - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (significandDigit < 17) { - d = d * 10.0 + (s.TakePush() - '0'); - --expFrac; - if (RAPIDJSON_LIKELY(d > 0.0)) - significandDigit++; - } - else - s.TakePush(); - } - } - else - decimalPosition = s.Length(); // decimal position at the end of integer. - - // Parse exp = e [ minus / plus ] 1*DIGIT - int exp = 0; - if (Consume(s, 'e') || Consume(s, 'E')) { - if (!useDouble) { - d = static_cast(use64bit ? i64 : i); - useDouble = true; - } - - bool expMinus = false; - if (Consume(s, '+')) - ; - else if (Consume(s, '-')) - expMinus = true; - - if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = static_cast(s.Take() - '0'); - if (expMinus) { - // (exp + expFrac) must not underflow int => we're detecting when -exp gets - // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into - // underflow territory): - // - // -(exp * 10 + 9) + expFrac >= INT_MIN - // <=> exp <= (expFrac - INT_MIN - 9) / 10 - RAPIDJSON_ASSERT(expFrac <= 0); - int maxExp = (expFrac + 2147483639) / 10; - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = exp * 10 + static_cast(s.Take() - '0'); - if (RAPIDJSON_UNLIKELY(exp > maxExp)) { - while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent - s.Take(); - } - } - } - else { // positive exp - int maxExp = 308 - expFrac; - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = exp * 10 + static_cast(s.Take() - '0'); - if (RAPIDJSON_UNLIKELY(exp > maxExp)) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); - } - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); - - if (expMinus) - exp = -exp; - } - - // Finish parsing, call event according to the type of number. - bool cont = true; - - if (parseFlags & kParseNumbersAsStringsFlag) { - if (parseFlags & kParseInsituFlag) { - s.Pop(); // Pop stack no matter if it will be used or not. - typename InputStream::Ch* head = is.PutBegin(); - const size_t length = s.Tell() - startOffset; - RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - // unable to insert the \0 character here, it will erase the comma after this number - const typename TargetEncoding::Ch* const str = reinterpret_cast(head); - cont = handler.RawNumber(str, SizeType(length), false); - } - else { - SizeType numCharsToCopy = static_cast(s.Length()); - GenericStringStream > srcStream(s.Pop()); - StackStream dstStream(stack_); - while (numCharsToCopy--) { - Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); - } - dstStream.Put('\0'); - const typename TargetEncoding::Ch* str = dstStream.Pop(); - const SizeType length = static_cast(dstStream.Length()) - 1; - cont = handler.RawNumber(str, SizeType(length), true); - } - } - else { - size_t length = s.Length(); - const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not. - - if (useDouble) { - int p = exp + expFrac; - if (parseFlags & kParseFullPrecisionFlag) - d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); - else - d = internal::StrtodNormalPrecision(d, p); - - // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal - if (d > (std::numeric_limits::max)()) { - // Overflow - // TODO: internal::StrtodX should report overflow (or underflow) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); - } - - cont = handler.Double(minus ? -d : d); - } - else if (useNanOrInf) { - cont = handler.Double(d); - } - else { - if (use64bit) { - if (minus) - cont = handler.Int64(static_cast(~i64 + 1)); - else - cont = handler.Uint64(i64); - } - else { - if (minus) - cont = handler.Int(static_cast(~i + 1)); - else - cont = handler.Uint(i); - } - } - } - if (RAPIDJSON_UNLIKELY(!cont)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); - } - - // Parse any JSON value - template - void ParseValue(InputStream& is, Handler& handler) { - switch (is.Peek()) { - case 'n': ParseNull (is, handler); break; - case 't': ParseTrue (is, handler); break; - case 'f': ParseFalse (is, handler); break; - case '"': ParseString(is, handler); break; - case '{': ParseObject(is, handler); break; - case '[': ParseArray (is, handler); break; - default : - ParseNumber(is, handler); - break; - - } - } - - // Iterative Parsing - - // States - enum IterativeParsingState { - IterativeParsingFinishState = 0, // sink states at top - IterativeParsingErrorState, // sink states at top - IterativeParsingStartState, - - // Object states - IterativeParsingObjectInitialState, - IterativeParsingMemberKeyState, - IterativeParsingMemberValueState, - IterativeParsingObjectFinishState, - - // Array states - IterativeParsingArrayInitialState, - IterativeParsingElementState, - IterativeParsingArrayFinishState, - - // Single value state - IterativeParsingValueState, - - // Delimiter states (at bottom) - IterativeParsingElementDelimiterState, - IterativeParsingMemberDelimiterState, - IterativeParsingKeyValueDelimiterState, - - cIterativeParsingStateCount - }; - - // Tokens - enum Token { - LeftBracketToken = 0, - RightBracketToken, - - LeftCurlyBracketToken, - RightCurlyBracketToken, - - CommaToken, - ColonToken, - - StringToken, - FalseToken, - TrueToken, - NullToken, - NumberToken, - - kTokenCount - }; - - RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define N NumberToken -#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N - // Maps from ASCII to Token - static const unsigned char tokenMap[256] = { - N16, // 00~0F - N16, // 10~1F - N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F - N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F - N16, // 40~4F - N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F - N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F - N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F - N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF - }; -#undef N -#undef N16 -//!@endcond - - if (sizeof(Ch) == 1 || static_cast(c) < 256) - return static_cast(tokenMap[static_cast(c)]); - else - return NumberToken; - } - - RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const { - // current state x one lookahead token -> new state - static const char G[cIterativeParsingStateCount][kTokenCount] = { - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Start - { - IterativeParsingArrayInitialState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingValueState, // String - IterativeParsingValueState, // False - IterativeParsingValueState, // True - IterativeParsingValueState, // Null - IterativeParsingValueState // Number - }, - // ObjectInitial - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberKey - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingKeyValueDelimiterState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberValue - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingMemberDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ObjectFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ArrayInitial - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // Element - { - IterativeParsingErrorState, // Left bracket - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingElementDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ArrayFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Single Value (sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ElementDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, - }; // End of G - - return static_cast(G[state][token]); - } - - // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). - // May return a new state on state pop. - template - RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { - (void)token; - - switch (dst) { - case IterativeParsingErrorState: - return dst; - - case IterativeParsingObjectInitialState: - case IterativeParsingArrayInitialState: - { - // Push the state(Element or MemberValue) if we are nested in another array or value of member. - // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. - IterativeParsingState n = src; - if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) - n = IterativeParsingElementState; - else if (src == IterativeParsingKeyValueDelimiterState) - n = IterativeParsingMemberValueState; - // Push current state. - *stack_.template Push(1) = n; - // Initialize and push the member/element count. - *stack_.template Push(1) = 0; - // Call handler - bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return dst; - } - } - - case IterativeParsingMemberKeyState: - ParseString(is, handler, true); - if (HasParseError()) - return IterativeParsingErrorState; - else - return dst; - - case IterativeParsingKeyValueDelimiterState: - RAPIDJSON_ASSERT(token == ColonToken); - is.Take(); - return dst; - - case IterativeParsingMemberValueState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; - - case IterativeParsingElementState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; - - case IterativeParsingMemberDelimiterState: - case IterativeParsingElementDelimiterState: - is.Take(); - // Update member/element count. - *stack_.template Top() = *stack_.template Top() + 1; - return dst; - - case IterativeParsingObjectFinishState: - { - // Transit from delimiter is only allowed when trailing commas are enabled - if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); - return IterativeParsingErrorState; - } - // Get member count. - SizeType c = *stack_.template Pop(1); - // If the object is not empty, count the last member. - if (src == IterativeParsingMemberValueState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndObject(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } - - case IterativeParsingArrayFinishState: - { - // Transit from delimiter is only allowed when trailing commas are enabled - if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); - return IterativeParsingErrorState; - } - // Get element count. - SizeType c = *stack_.template Pop(1); - // If the array is not empty, count the last element. - if (src == IterativeParsingElementState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndArray(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } - - default: - // This branch is for IterativeParsingValueState actually. - // Use `default:` rather than - // `case IterativeParsingValueState:` is for code coverage. - - // The IterativeParsingStartState is not enumerated in this switch-case. - // It is impossible for that case. And it can be caught by following assertion. - - // The IterativeParsingFinishState is not enumerated in this switch-case either. - // It is a "derivative" state which cannot triggered from Predict() directly. - // Therefore it cannot happen here. And it can be caught by following assertion. - RAPIDJSON_ASSERT(dst == IterativeParsingValueState); - - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return IterativeParsingFinishState; - } - } - - template - void HandleError(IterativeParsingState src, InputStream& is) { - if (HasParseError()) { - // Error flag has been set. - return; - } - - switch (src) { - case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; - case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; - case IterativeParsingObjectInitialState: - case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; - case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; - case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; - case IterativeParsingKeyValueDelimiterState: - case IterativeParsingArrayInitialState: - case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; - default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; - } - } - - RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const { - return s >= IterativeParsingElementDelimiterState; - } - - RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const { - return s <= IterativeParsingErrorState; - } - - template - ParseResult IterativeParse(InputStream& is, Handler& handler) { - parseResult_.Clear(); - ClearStackOnExit scope(*this); - IterativeParsingState state = IterativeParsingStartState; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - while (is.Peek() != '\0') { - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state, t); - IterativeParsingState d = Transit(state, t, n, is, handler); - - if (d == IterativeParsingErrorState) { - HandleError(state, is); - break; - } - - state = d; - - // Do not further consume streams if a root JSON has been parsed. - if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) - break; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - - // Handle the end of file. - if (state != IterativeParsingFinishState) - HandleError(state, is); - - return parseResult_; - } - - static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. - internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. - ParseResult parseResult_; - IterativeParsingState state_; -}; // class GenericReader - -//! Reader with UTF8 encoding and default allocator. -typedef GenericReader, UTF8<> > Reader; - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_READER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/schema.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/schema.h deleted file mode 100644 index fea254e8..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/schema.h +++ /dev/null @@ -1,3262 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available-> -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License-> You may obtain a copy of the License at -// -// http://opensource->org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied-> See the License for the -// specific language governing permissions and limitations under the License-> - -#ifndef RAPIDJSON_SCHEMA_H_ -#define RAPIDJSON_SCHEMA_H_ - -#include "document.h" -#include "pointer.h" -#include "stringbuffer.h" -#include "error/en.h" -#include "uri.h" -#include // abs, floor - -#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 -#endif - -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) -#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX -#include "internal/regex.h" -#elif RAPIDJSON_SCHEMA_USE_STDREGEX -#include -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX -#define RAPIDJSON_SCHEMA_HAS_REGEX 1 -#else -#define RAPIDJSON_SCHEMA_HAS_REGEX 0 -#endif - -#ifndef RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_VERBOSE 0 -#endif - -RAPIDJSON_DIAG_PUSH - -#if defined(__GNUC__) -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(weak-vtables) -RAPIDJSON_DIAG_OFF(exit-time-destructors) -RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) -RAPIDJSON_DIAG_OFF(variadic-macros) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Verbose Utilities - -#if RAPIDJSON_SCHEMA_VERBOSE - -namespace internal { - -inline void PrintInvalidKeywordData(const char* keyword) { - printf(" Fail keyword: '%s'\n", keyword); -} - -inline void PrintInvalidKeywordData(const wchar_t* keyword) { - wprintf(L" Fail keyword: '%ls'\n", keyword); -} - -inline void PrintInvalidDocumentData(const char* document) { - printf(" Fail document: '%s'\n", document); -} - -inline void PrintInvalidDocumentData(const wchar_t* document) { - wprintf(L" Fail document: '%ls'\n", document); -} - -inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) { - printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d); -} - -inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) { - wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d); -} - -inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) { - printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved); -} - -inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) { - wprintf(L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved); -} - -inline void PrintMethodData(const char* method) { - printf("%s\n", method); -} - -inline void PrintMethodData(const char* method, bool b) { - printf("%s, Data: '%s'\n", method, b ? "true" : "false"); -} - -inline void PrintMethodData(const char* method, int64_t i) { - printf("%s, Data: '%" PRId64 "'\n", method, i); -} - -inline void PrintMethodData(const char* method, uint64_t u) { - printf("%s, Data: '%" PRIu64 "'\n", method, u); -} - -inline void PrintMethodData(const char* method, double d) { - printf("%s, Data: '%lf'\n", method, d); -} - -inline void PrintMethodData(const char* method, const char* s) { - printf("%s, Data: '%s'\n", method, s); -} - -inline void PrintMethodData(const char* method, const wchar_t* s) { - wprintf(L"%hs, Data: '%ls'\n", method, s); -} - -inline void PrintMethodData(const char* method, const char* s1, const char* s2) { - printf("%s, Data: '%s', '%s'\n", method, s1, s2); -} - -inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) { - wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2); -} - -} // namespace internal - -#endif // RAPIDJSON_SCHEMA_VERBOSE - -#ifndef RAPIDJSON_SCHEMA_PRINT -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__) -#else -#define RAPIDJSON_SCHEMA_PRINT(name, ...) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_INVALID_KEYWORD_RETURN - -#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - context.invalidCode = code;\ - context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ - RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\ - return false;\ -RAPIDJSON_MULTILINEMACRO_END - -/////////////////////////////////////////////////////////////////////////////// -// ValidateFlag - -/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kValidateDefaultFlags definition. - - User can define this as any \c ValidateFlag combinations. -*/ -#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS -#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags -#endif - -//! Combination of validate flags -/*! \see - */ -enum ValidateFlag { - kValidateNoFlags = 0, //!< No flags are set. - kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error. - kValidateReadFlag = 2, //!< Validation is for a read semantic. - kValidateWriteFlag = 4, //!< Validation is for a write semantic. - kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS -}; - -/////////////////////////////////////////////////////////////////////////////// -// Specification -enum SchemaDraft { - kDraftUnknown = -1, - kDraftNone = 0, - kDraft03 = 3, - kDraftMin = 4, //!< Current minimum supported draft - kDraft04 = 4, - kDraft05 = 5, - kDraftMax = 5, //!< Current maximum supported draft - kDraft06 = 6, - kDraft07 = 7, - kDraft2019_09 = 8, - kDraft2020_12 = 9 -}; - -enum OpenApiVersion { - kVersionUnknown = -1, - kVersionNone = 0, - kVersionMin = 2, //!< Current minimum supported version - kVersion20 = 2, - kVersion30 = 3, - kVersionMax = 3, //!< Current maximum supported version - kVersion31 = 4, -}; - -struct Specification { - Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {} - Specification(OpenApiVersion o) : oapi(o) { - if (oapi == kVersion20) draft = kDraft04; - else if (oapi == kVersion30) draft = kDraft05; - else if (oapi == kVersion31) draft = kDraft2020_12; - else draft = kDraft04; - } - ~Specification() {} - bool IsSupported() const { - return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax))); - } - SchemaDraft draft; - OpenApiVersion oapi; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Forward declarations - -template -class GenericSchemaDocument; - -namespace internal { - -template -class Schema; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaValidator - -class ISchemaValidator { -public: - virtual ~ISchemaValidator() {} - virtual bool IsValid() const = 0; - virtual void SetValidateFlags(unsigned flags) = 0; - virtual unsigned GetValidateFlags() const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaStateFactory - -template -class ISchemaStateFactory { -public: - virtual ~ISchemaStateFactory() {} - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0; - virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; - virtual void* CreateHasher() = 0; - virtual uint64_t GetHashCode(void* hasher) = 0; - virtual void DestroyHasher(void* hasher) = 0; - virtual void* MallocState(size_t size) = 0; - virtual void FreeState(void* p) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// IValidationErrorHandler - -template -class IValidationErrorHandler { -public: - typedef typename SchemaType::Ch Ch; - typedef typename SchemaType::SValue SValue; - - virtual ~IValidationErrorHandler() {} - - virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; - virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; - virtual void NotMultipleOf(double actual, const SValue& expected) = 0; - virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; - virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; - - virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; - virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; - virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; - - virtual void DisallowedItem(SizeType index) = 0; - virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; - virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; - virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; - - virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; - virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; - virtual void StartMissingProperties() = 0; - virtual void AddMissingProperty(const SValue& name) = 0; - virtual bool EndMissingProperties() = 0; - virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; - - virtual void StartDependencyErrors() = 0; - virtual void StartMissingDependentProperties() = 0; - virtual void AddMissingDependentProperty(const SValue& targetName) = 0; - virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; - virtual void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) = 0; - virtual bool EndDependencyErrors() = 0; - - virtual void DisallowedValue(const ValidateErrorCode code) = 0; - virtual void StartDisallowedType() = 0; - virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; - virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; - virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0; - virtual void Disallowed() = 0; - virtual void DisallowedWhenWriting() = 0; - virtual void DisallowedWhenReading() = 0; -}; - - -/////////////////////////////////////////////////////////////////////////////// -// Hasher - -// For comparison of compound value -template -class Hasher { -public: - typedef typename Encoding::Ch Ch; - - Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} - - bool Null() { return WriteType(kNullType); } - bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } - bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Double(double d) { - Number n; - if (d < 0) n.u.i = static_cast(d); - else n.u.u = static_cast(d); - n.d = d; - return WriteNumber(n); - } - - bool RawNumber(const Ch* str, SizeType len, bool) { - WriteBuffer(kNumberType, str, len * sizeof(Ch)); - return true; - } - - bool String(const Ch* str, SizeType len, bool) { - WriteBuffer(kStringType, str, len * sizeof(Ch)); - return true; - } - - bool StartObject() { return true; } - bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } - bool EndObject(SizeType memberCount) { - uint64_t h = Hash(0, kObjectType); - uint64_t* kv = stack_.template Pop(memberCount * 2); - for (SizeType i = 0; i < memberCount; i++) - h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive - *stack_.template Push() = h; - return true; - } - - bool StartArray() { return true; } - bool EndArray(SizeType elementCount) { - uint64_t h = Hash(0, kArrayType); - uint64_t* e = stack_.template Pop(elementCount); - for (SizeType i = 0; i < elementCount; i++) - h = Hash(h, e[i]); // Use hash to achieve element order sensitive - *stack_.template Push() = h; - return true; - } - - bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } - - uint64_t GetHashCode() const { - RAPIDJSON_ASSERT(IsValid()); - return *stack_.template Top(); - } - -private: - static const size_t kDefaultSize = 256; - struct Number { - union U { - uint64_t u; - int64_t i; - }u; - double d; - }; - - bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } - - bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } - - bool WriteBuffer(Type type, const void* data, size_t len) { - // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ - uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); - const unsigned char* d = static_cast(data); - for (size_t i = 0; i < len; i++) - h = Hash(h, d[i]); - *stack_.template Push() = h; - return true; - } - - static uint64_t Hash(uint64_t h, uint64_t d) { - static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); - h ^= d; - h *= kPrime; - return h; - } - - Stack stack_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidationContext - -template -struct SchemaValidationContext { - typedef Schema SchemaType; - typedef ISchemaStateFactory SchemaValidatorFactoryType; - typedef IValidationErrorHandler ErrorHandlerType; - typedef typename SchemaType::ValueType ValueType; - typedef typename ValueType::Ch Ch; - - enum PatternValidatorType { - kPatternValidatorOnly, - kPatternValidatorWithProperty, - kPatternValidatorWithAdditionalProperty - }; - - SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s, unsigned fl = 0) : - factory(f), - error_handler(eh), - schema(s), - flags(fl), - valueSchema(), - invalidKeyword(), - invalidCode(), - hasher(), - arrayElementHashCodes(), - validators(), - validatorCount(), - patternPropertiesValidators(), - patternPropertiesValidatorCount(), - patternPropertiesSchemas(), - patternPropertiesSchemaCount(), - valuePatternValidatorType(kPatternValidatorOnly), - propertyExist(), - inArray(false), - valueUniqueness(false), - arrayUniqueness(false) - { - } - - ~SchemaValidationContext() { - if (hasher) - factory.DestroyHasher(hasher); - if (validators) { - for (SizeType i = 0; i < validatorCount; i++) { - if (validators[i]) { - factory.DestroySchemaValidator(validators[i]); - } - } - factory.FreeState(validators); - } - if (patternPropertiesValidators) { - for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) { - if (patternPropertiesValidators[i]) { - factory.DestroySchemaValidator(patternPropertiesValidators[i]); - } - } - factory.FreeState(patternPropertiesValidators); - } - if (patternPropertiesSchemas) - factory.FreeState(patternPropertiesSchemas); - if (propertyExist) - factory.FreeState(propertyExist); - } - - SchemaValidatorFactoryType& factory; - ErrorHandlerType& error_handler; - const SchemaType* schema; - unsigned flags; - const SchemaType* valueSchema; - const Ch* invalidKeyword; - ValidateErrorCode invalidCode; - void* hasher; // Only validator access - void* arrayElementHashCodes; // Only validator access this - ISchemaValidator** validators; - SizeType validatorCount; - ISchemaValidator** patternPropertiesValidators; - SizeType patternPropertiesValidatorCount; - const SchemaType** patternPropertiesSchemas; - SizeType patternPropertiesSchemaCount; - PatternValidatorType valuePatternValidatorType; - PatternValidatorType objectPatternValidatorType; - SizeType arrayElementIndex; - bool* propertyExist; - bool inArray; - bool valueUniqueness; - bool arrayUniqueness; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Schema - -template -class Schema { -public: - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename SchemaDocumentType::AllocatorType AllocatorType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef SchemaValidationContext Context; - typedef Schema SchemaType; - typedef GenericValue SValue; - typedef IValidationErrorHandler ErrorHandler; - typedef GenericUri UriType; - friend class GenericSchemaDocument; - - Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) : - allocator_(allocator), - uri_(schemaDocument->GetURI(), *allocator), - id_(id, allocator), - spec_(schemaDocument->GetSpecification()), - pointer_(p, allocator), - typeless_(schemaDocument->GetTypeless()), - enum_(), - enumCount_(), - not_(), - type_((1 << kTotalSchemaType) - 1), // typeless - validatorCount_(), - notValidatorIndex_(), - properties_(), - additionalPropertiesSchema_(), - patternProperties_(), - patternPropertyCount_(), - propertyCount_(), - minProperties_(), - maxProperties_(SizeType(~0)), - additionalProperties_(true), - hasDependencies_(), - hasRequired_(), - hasSchemaDependencies_(), - additionalItemsSchema_(), - itemsList_(), - itemsTuple_(), - itemsTupleCount_(), - minItems_(), - maxItems_(SizeType(~0)), - additionalItems_(true), - uniqueItems_(false), - pattern_(), - minLength_(0), - maxLength_(~SizeType(0)), - exclusiveMinimum_(false), - exclusiveMaximum_(false), - defaultValueLength_(0), - readOnly_(false), - writeOnly_(false), - nullable_(false) - { - GenericStringBuffer sb; - p.StringifyUriFragment(sb); - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString()); - - typedef typename ValueType::ConstValueIterator ConstValueIterator; - typedef typename ValueType::ConstMemberIterator ConstMemberIterator; - - // PR #1393 - // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite - // recursion (with recursive schemas), since schemaDocument->getSchema() is always - // checked before creating a new one. Don't cache typeless_, though. - if (this != typeless_) { - typedef typename SchemaDocumentType::SchemaEntry SchemaEntry; - SchemaEntry *entry = schemaDocument->schemaMap_.template Push(); - new (entry) SchemaEntry(pointer_, this, true, allocator_); - schemaDocument->AddSchemaRefs(this); - } - - if (!value.IsObject()) - return; - - // If we have an id property, resolve it with the in-scope id - // Not supported for open api 2.0 or 3.0 - if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) - if (const ValueType* v = GetMember(value, GetIdString())) { - if (v->IsString()) { - UriType local(*v, allocator); - id_ = local.Resolve(id_, allocator); - RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString()); - } - } - - if (const ValueType* v = GetMember(value, GetTypeString())) { - type_ = 0; - if (v->IsString()) - AddType(*v); - else if (v->IsArray()) - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) - AddType(*itr); - } - - if (const ValueType* v = GetMember(value, GetEnumString())) { - if (v->IsArray() && v->Size() > 0) { - enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { - typedef Hasher > EnumHasherType; - char buffer[256u + 24]; - MemoryPoolAllocator hasherAllocator(buffer, sizeof(buffer)); - EnumHasherType h(&hasherAllocator, 256); - itr->Accept(h); - enum_[enumCount_++] = h.GetHashCode(); - } - } - } - - if (schemaDocument) - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - - // AnyOf, OneOf, Not not supported for open api 2.0 - if (schemaDocument && spec_.oapi != kVersion20) { - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - - if (const ValueType* v = GetMember(value, GetNotString())) { - schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_); - notValidatorIndex_ = validatorCount_; - validatorCount_++; - } - } - - // Object - - const ValueType* properties = GetMember(value, GetPropertiesString()); - const ValueType* required = GetMember(value, GetRequiredString()); - const ValueType* dependencies = GetMember(value, GetDependenciesString()); - { - // Gather properties from properties/required/dependencies - SValue allProperties(kArrayType); - - if (properties && properties->IsObject()) - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) - AddUniqueElement(allProperties, itr->name); - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) - AddUniqueElement(allProperties, *itr); - - // Dependencies not supported for open api 2.0 and 3.0 - if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) - if (dependencies && dependencies->IsObject()) - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - AddUniqueElement(allProperties, itr->name); - if (itr->value.IsArray()) - for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) - if (i->IsString()) - AddUniqueElement(allProperties, *i); - } - - if (allProperties.Size() > 0) { - propertyCount_ = allProperties.Size(); - properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); - for (SizeType i = 0; i < propertyCount_; i++) { - new (&properties_[i]) Property(); - properties_[i].name = allProperties[i]; - properties_[i].schema = typeless_; - } - } - } - - if (properties && properties->IsObject()) { - PointerType q = p.Append(GetPropertiesString(), allocator_); - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { - SizeType index; - if (FindPropertyIndex(itr->name, &index)) - schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_); - } - } - - // PatternProperties not supported for open api 2.0 and 3.0 - if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) - if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { - PointerType q = p.Append(GetPatternPropertiesString(), allocator_); - patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); - patternPropertyCount_ = 0; - - for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { - new (&patternProperties_[patternPropertyCount_]) PatternProperty(); - PointerType r = q.Append(itr->name, allocator_); - patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r); - schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_); - patternPropertyCount_++; - } - } - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) { - SizeType index; - if (FindPropertyIndex(*itr, &index)) { - properties_[index].required = true; - hasRequired_ = true; - } - } - - // Dependencies not supported for open api 2.0 and 3.0 - if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) - if (dependencies && dependencies->IsObject()) { - PointerType q = p.Append(GetDependenciesString(), allocator_); - hasDependencies_ = true; - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - SizeType sourceIndex; - if (FindPropertyIndex(itr->name, &sourceIndex)) { - if (itr->value.IsArray()) { - properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); - std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); - for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { - SizeType targetIndex; - if (FindPropertyIndex(*targetItr, &targetIndex)) - properties_[sourceIndex].dependencies[targetIndex] = true; - } - } - else if (itr->value.IsObject()) { - hasSchemaDependencies_ = true; - schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_); - properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; - validatorCount_++; - } - } - } - } - - if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { - if (v->IsBool()) - additionalProperties_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_); - } - - AssignIfExist(minProperties_, value, GetMinPropertiesString()); - AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); - - // Array - if (const ValueType* v = GetMember(value, GetItemsString())) { - PointerType q = p.Append(GetItemsString(), allocator_); - if (v->IsObject()) // List validation - schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_); - else if (v->IsArray()) { // Tuple validation - itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); - SizeType index = 0; - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) - schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_); - } - } - - AssignIfExist(minItems_, value, GetMinItemsString()); - AssignIfExist(maxItems_, value, GetMaxItemsString()); - - // AdditionalItems not supported for openapi 2.0 and 3.0 - if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) - if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { - if (v->IsBool()) - additionalItems_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_); - } - - AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); - - // String - AssignIfExist(minLength_, value, GetMinLengthString()); - AssignIfExist(maxLength_, value, GetMaxLengthString()); - - if (const ValueType* v = GetMember(value, GetPatternString())) - pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_)); - - // Number - if (const ValueType* v = GetMember(value, GetMinimumString())) - if (v->IsNumber()) - minimum_.CopyFrom(*v, *allocator_); - - if (const ValueType* v = GetMember(value, GetMaximumString())) - if (v->IsNumber()) - maximum_.CopyFrom(*v, *allocator_); - - AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); - AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); - - if (const ValueType* v = GetMember(value, GetMultipleOfString())) - if (v->IsNumber() && v->GetDouble() > 0.0) - multipleOf_.CopyFrom(*v, *allocator_); - - // Default - if (const ValueType* v = GetMember(value, GetDefaultValueString())) - if (v->IsString()) - defaultValueLength_ = v->GetStringLength(); - - // ReadOnly - open api only (until draft 7 supported) - // WriteOnly - open api 3 only (until draft 7 supported) - // Both can't be true - if (spec_.oapi != kVersionNone) - AssignIfExist(readOnly_, value, GetReadOnlyString()); - if (spec_.oapi >= kVersion30) - AssignIfExist(writeOnly_, value, GetWriteOnlyString()); - if (readOnly_ && writeOnly_) - schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p); - - // Nullable - open api 3 only - // If true add 'null' as allowable type - if (spec_.oapi >= kVersion30) { - AssignIfExist(nullable_, value, GetNullableString()); - if (nullable_) - AddType(GetNullString()); - } - } - - ~Schema() { - AllocatorType::Free(enum_); - if (properties_) { - for (SizeType i = 0; i < propertyCount_; i++) - properties_[i].~Property(); - AllocatorType::Free(properties_); - } - if (patternProperties_) { - for (SizeType i = 0; i < patternPropertyCount_; i++) - patternProperties_[i].~PatternProperty(); - AllocatorType::Free(patternProperties_); - } - AllocatorType::Free(itemsTuple_); -#if RAPIDJSON_SCHEMA_HAS_REGEX - if (pattern_) { - pattern_->~RegexType(); - AllocatorType::Free(pattern_); - } -#endif - } - - const SValue& GetURI() const { - return uri_; - } - - const UriType& GetId() const { - return id_; - } - - const Specification& GetSpecification() const { - return spec_; - } - - const PointerType& GetPointer() const { - return pointer_; - } - - bool BeginValue(Context& context) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue"); - if (context.inArray) { - if (uniqueItems_) - context.valueUniqueness = true; - - if (itemsList_) - context.valueSchema = itemsList_; - else if (itemsTuple_) { - if (context.arrayElementIndex < itemsTupleCount_) - context.valueSchema = itemsTuple_[context.arrayElementIndex]; - else if (additionalItemsSchema_) - context.valueSchema = additionalItemsSchema_; - else if (additionalItems_) - context.valueSchema = typeless_; - else { - context.error_handler.DisallowedItem(context.arrayElementIndex); - // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error - context.valueSchema = typeless_; - // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set - context.arrayElementIndex++; - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems); - } - } - else - context.valueSchema = typeless_; - - context.arrayElementIndex++; - } - return true; - } - - RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue"); - // Only check pattern properties if we have validators - if (context.patternPropertiesValidatorCount > 0) { - bool otherValid = false; - SizeType count = context.patternPropertiesValidatorCount; - if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) - otherValid = context.patternPropertiesValidators[--count]->IsValid(); - - bool patternValid = true; - for (SizeType i = 0; i < count; i++) - if (!context.patternPropertiesValidators[i]->IsValid()) { - patternValid = false; - break; - } - - if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) { - context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); - } - } - else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) { - context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); - } - } - else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) - context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); - } - } - - // For enums only check if we have a hasher - if (enum_ && context.hasher) { - const uint64_t h = context.factory.GetHashCode(context.hasher); - for (SizeType i = 0; i < enumCount_; i++) - if (enum_[i] == h) - goto foundEnum; - context.error_handler.DisallowedValue(kValidateErrorEnum); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum); - foundEnum:; - } - - // Only check allOf etc if we have validators - if (context.validatorCount > 0) { - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) { - context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); - } - - if (anyOf_.schemas) { - for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) - if (context.validators[i]->IsValid()) - goto foundAny; - context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); - foundAny:; - } - - if (oneOf_.schemas) { - bool oneValid = false; - SizeType firstMatch = 0; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) { - context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); - } else { - oneValid = true; - firstMatch = i - oneOf_.begin; - } - } - if (!oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); - } - } - - if (not_ && context.validators[notValidatorIndex_]->IsValid()) { - context.error_handler.Disallowed(); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); - } - } - - return true; - } - - bool Null(Context& context) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null"); - if (!(type_ & (1 << kNullSchemaType))) { - DisallowedType(context, GetNullString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - return CreateParallelValidator(context); - } - - bool Bool(Context& context, bool b) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b); - if (!CheckBool(context, b)) - return false; - return CreateParallelValidator(context); - } - - bool Int(Context& context, int i) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i); - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint(Context& context, unsigned u) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u); - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Int64(Context& context, int64_t i) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i); - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint64(Context& context, uint64_t u) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u); - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Double(Context& context, double d) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d); - if (!(type_ & (1 << kNumberSchemaType))) { - DisallowedType(context, GetNumberString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) - return false; - - if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) - return false; - - if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) - return false; - - return CreateParallelValidator(context); - } - - bool String(Context& context, const Ch* str, SizeType length, bool) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str); - if (!(type_ & (1 << kStringSchemaType))) { - DisallowedType(context, GetStringString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (minLength_ != 0 || maxLength_ != SizeType(~0)) { - SizeType count; - if (internal::CountStringCodePoint(str, length, &count)) { - if (count < minLength_) { - context.error_handler.TooShort(str, length, minLength_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength); - } - if (count > maxLength_) { - context.error_handler.TooLong(str, length, maxLength_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength); - } - } - } - - if (pattern_ && !IsPatternMatch(pattern_, str, length)) { - context.error_handler.DoesNotMatch(str, length); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern); - } - - return CreateParallelValidator(context); - } - - bool StartObject(Context& context) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject"); - if (!(type_ & (1 << kObjectSchemaType))) { - DisallowedType(context, GetObjectString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (hasDependencies_ || hasRequired_) { - context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); - std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); - } - - if (patternProperties_) { // pre-allocate schema array - SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType - context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); - context.patternPropertiesSchemaCount = 0; - std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); - } - - return CreateParallelValidator(context); - } - - bool Key(Context& context, const Ch* str, SizeType len, bool) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str); - - if (patternProperties_) { - context.patternPropertiesSchemaCount = 0; - for (SizeType i = 0; i < patternPropertyCount_; i++) - if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; - context.valueSchema = typeless_; - } - } - - SizeType index = 0; - if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { - if (context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; - context.valueSchema = typeless_; - context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; - } - else - context.valueSchema = properties_[index].schema; - - if (context.propertyExist) - context.propertyExist[index] = true; - - return true; - } - - if (additionalPropertiesSchema_) { - if (context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; - context.valueSchema = typeless_; - context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; - } - else - context.valueSchema = additionalPropertiesSchema_; - return true; - } - else if (additionalProperties_) { - context.valueSchema = typeless_; - return true; - } - - if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties - // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error - context.valueSchema = typeless_; - context.error_handler.DisallowedProperty(str, len); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties); - } - - return true; - } - - bool EndObject(Context& context, SizeType memberCount) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject"); - if (hasRequired_) { - context.error_handler.StartMissingProperties(); - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required && !context.propertyExist[index]) - if (properties_[index].schema->defaultValueLength_ == 0 ) - context.error_handler.AddMissingProperty(properties_[index].name); - if (context.error_handler.EndMissingProperties()) - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired); - } - - if (memberCount < minProperties_) { - context.error_handler.TooFewProperties(memberCount, minProperties_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties); - } - - if (memberCount > maxProperties_) { - context.error_handler.TooManyProperties(memberCount, maxProperties_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties); - } - - if (hasDependencies_) { - context.error_handler.StartDependencyErrors(); - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { - const Property& source = properties_[sourceIndex]; - if (context.propertyExist[sourceIndex]) { - if (source.dependencies) { - context.error_handler.StartMissingDependentProperties(); - for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) - context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); - context.error_handler.EndMissingDependentProperties(source.name); - } - else if (source.dependenciesSchema) { - ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; - if (!dependenciesValidator->IsValid()) - context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); - } - } - } - if (context.error_handler.EndDependencyErrors()) - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); - } - - return true; - } - - bool StartArray(Context& context) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray"); - context.arrayElementIndex = 0; - context.inArray = true; // Ensure we note that we are in an array - - if (!(type_ & (1 << kArraySchemaType))) { - DisallowedType(context, GetArrayString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - return CreateParallelValidator(context); - } - - bool EndArray(Context& context, SizeType elementCount) const { - RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray"); - context.inArray = false; - - if (elementCount < minItems_) { - context.error_handler.TooFewItems(elementCount, minItems_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems); - } - - if (elementCount > maxItems_) { - context.error_handler.TooManyItems(elementCount, maxItems_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems); - } - - return true; - } - - static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) { - switch (validateErrorCode) { - case kValidateErrorMultipleOf: return GetMultipleOfString(); - case kValidateErrorMaximum: return GetMaximumString(); - case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same - case kValidateErrorMinimum: return GetMinimumString(); - case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same - - case kValidateErrorMaxLength: return GetMaxLengthString(); - case kValidateErrorMinLength: return GetMinLengthString(); - case kValidateErrorPattern: return GetPatternString(); - - case kValidateErrorMaxItems: return GetMaxItemsString(); - case kValidateErrorMinItems: return GetMinItemsString(); - case kValidateErrorUniqueItems: return GetUniqueItemsString(); - case kValidateErrorAdditionalItems: return GetAdditionalItemsString(); - - case kValidateErrorMaxProperties: return GetMaxPropertiesString(); - case kValidateErrorMinProperties: return GetMinPropertiesString(); - case kValidateErrorRequired: return GetRequiredString(); - case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString(); - case kValidateErrorPatternProperties: return GetPatternPropertiesString(); - case kValidateErrorDependencies: return GetDependenciesString(); - - case kValidateErrorEnum: return GetEnumString(); - case kValidateErrorType: return GetTypeString(); - - case kValidateErrorOneOf: return GetOneOfString(); - case kValidateErrorOneOfMatch: return GetOneOfString(); // Same - case kValidateErrorAllOf: return GetAllOfString(); - case kValidateErrorAnyOf: return GetAnyOfString(); - case kValidateErrorNot: return GetNotString(); - - case kValidateErrorReadOnly: return GetReadOnlyString(); - case kValidateErrorWriteOnly: return GetWriteOnlyString(); - - default: return GetNullString(); - } - } - - - // Generate functions for string literal according to Ch -#define RAPIDJSON_STRING_(name, ...) \ - static const ValueType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ - return v;\ - } - - RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') - RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') - RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') - RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') - RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') - RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') - RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') - RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') - RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') - RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') - RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') - RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') - RAPIDJSON_STRING_(Not, 'n', 'o', 't') - RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') - RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') - RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') - RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') - RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') - RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a') - RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f') - RAPIDJSON_STRING_(Id, 'i', 'd') - RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r') - RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i') - RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y') - RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y') - RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e') - -#undef RAPIDJSON_STRING_ - -private: - enum SchemaValueType { - kNullSchemaType, - kBooleanSchemaType, - kObjectSchemaType, - kArraySchemaType, - kStringSchemaType, - kNumberSchemaType, - kIntegerSchemaType, - kTotalSchemaType - }; - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - typedef std::basic_regex RegexType; -#else - typedef char RegexType; -#endif - - struct SchemaArray { - SchemaArray() : schemas(), count() {} - ~SchemaArray() { AllocatorType::Free(schemas); } - const SchemaType** schemas; - SizeType begin; // begin index of context.validators - SizeType count; - }; - - template - void AddUniqueElement(V1& a, const V2& v) { - for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) - if (*itr == v) - return; - V1 c(v, *allocator_); - a.PushBack(c, *allocator_); - } - - static const ValueType* GetMember(const ValueType& value, const ValueType& name) { - typename ValueType::ConstMemberIterator itr = value.FindMember(name); - return itr != value.MemberEnd() ? &(itr->value) : 0; - } - - static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsBool()) - out = v->GetBool(); - } - - static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) - out = static_cast(v->GetUint64()); - } - - void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { - if (const ValueType* v = GetMember(value, name)) { - if (v->IsArray() && v->Size() > 0) { - PointerType q = p.Append(name, allocator_); - out.count = v->Size(); - out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); - memset(out.schemas, 0, sizeof(Schema*)* out.count); - for (SizeType i = 0; i < out.count; i++) - schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_); - out.begin = validatorCount_; - validatorCount_ += out.count; - } - } - } - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - template - RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) { - if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); - if (!r->IsValid()) { - sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength()); - r->~RegexType(); - AllocatorType::Free(r); - r = 0; - } - return r; - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { - GenericRegexSearch rs(*pattern); - return rs.Search(str); - } -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - template - RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) { - if (value.IsString()) { - RegexType *r = static_cast(allocator_->Malloc(sizeof(RegexType))); - try { - return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); - } - catch (const std::regex_error& e) { - sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength()); - AllocatorType::Free(r); - } - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { - std::match_results r; - return std::regex_search(str, str + length, r, *pattern); - } -#else - template - RegexType* CreatePattern(const ValueType&) { - return 0; - } - - static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } -#endif // RAPIDJSON_SCHEMA_USE_STDREGEX - - void AddType(const ValueType& type) { - if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; - else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; - else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; - else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; - else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; - else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; - else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); - } - - // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required. - // Also creates a hasher for enums and array uniqueness, if required. - // Also a useful place to add type-independent error checks. - bool CreateParallelValidator(Context& context) const { - if (enum_ || context.arrayUniqueness) - context.hasher = context.factory.CreateHasher(); - - if (validatorCount_) { - RAPIDJSON_ASSERT(context.validators == 0); - context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); - std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_); - context.validatorCount = validatorCount_; - - // Always return after first failure for these sub-validators - if (allOf_.schemas) - CreateSchemaValidators(context, allOf_, false); - - if (anyOf_.schemas) - CreateSchemaValidators(context, anyOf_, false); - - if (oneOf_.schemas) - CreateSchemaValidators(context, oneOf_, false); - - if (not_) - context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false); - - if (hasSchemaDependencies_) { - for (SizeType i = 0; i < propertyCount_; i++) - if (properties_[i].dependenciesSchema) - context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false); - } - } - - // Add any other type-independent checks here - if (readOnly_ && (context.flags & kValidateWriteFlag)) { - context.error_handler.DisallowedWhenWriting(); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly); - } - if (writeOnly_ && (context.flags & kValidateReadFlag)) { - context.error_handler.DisallowedWhenReading(); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly); - } - - return true; - } - - void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const { - for (SizeType i = 0; i < schemas.count; i++) - context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors); - } - - // O(n) - bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { - SizeType len = name.GetStringLength(); - const Ch* str = name.GetString(); - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].name.GetStringLength() == len && - (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) - { - *outIndex = index; - return true; - } - return false; - } - - bool CheckBool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) { - DisallowedType(context, GetBooleanString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - return true; - } - - bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { - DisallowedType(context, GetIntegerString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (!minimum_.IsNull()) { - if (minimum_.IsInt64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { - context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); - } - } - else if (minimum_.IsUint64()) { - context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64() - } - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { - context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); - } - } - else if (maximum_.IsUint64()) { } - /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { - context.error_handler.NotMultipleOf(i, multipleOf_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); - } - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { - DisallowedType(context, GetIntegerString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (!minimum_.IsNull()) { - if (minimum_.IsUint64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { - context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); - } - } - else if (minimum_.IsInt64()) - /* do nothing */; // i >= 0 > minimum.Getint64() - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { - context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); - } - } - else if (maximum_.IsInt64()) { - context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_ - } - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (i % multipleOf_.GetUint64() != 0) { - context.error_handler.NotMultipleOf(i, multipleOf_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); - } - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { - context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); - } - return true; - } - - bool CheckDoubleMaximum(Context& context, double d) const { - if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { - context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); - } - return true; - } - - bool CheckDoubleMultipleOf(Context& context, double d) const { - double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); - double q = std::floor(a / b); - double r = a - q * b; - if (r > 0.0) { - context.error_handler.NotMultipleOf(d, multipleOf_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); - } - return true; - } - - void DisallowedType(Context& context, const ValueType& actualType) const { - ErrorHandler& eh = context.error_handler; - eh.StartDisallowedType(); - - if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); - if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); - if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); - if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); - if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); - - if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); - else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); - - eh.EndDisallowedType(actualType); - } - - struct Property { - Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} - ~Property() { AllocatorType::Free(dependencies); } - SValue name; - const SchemaType* schema; - const SchemaType* dependenciesSchema; - SizeType dependenciesValidatorIndex; - bool* dependencies; - bool required; - }; - - struct PatternProperty { - PatternProperty() : schema(), pattern() {} - ~PatternProperty() { - if (pattern) { - pattern->~RegexType(); - AllocatorType::Free(pattern); - } - } - const SchemaType* schema; - RegexType* pattern; - }; - - AllocatorType* allocator_; - SValue uri_; - UriType id_; - Specification spec_; - PointerType pointer_; - const SchemaType* typeless_; - uint64_t* enum_; - SizeType enumCount_; - SchemaArray allOf_; - SchemaArray anyOf_; - SchemaArray oneOf_; - const SchemaType* not_; - unsigned type_; // bitmask of kSchemaType - SizeType validatorCount_; - SizeType notValidatorIndex_; - - Property* properties_; - const SchemaType* additionalPropertiesSchema_; - PatternProperty* patternProperties_; - SizeType patternPropertyCount_; - SizeType propertyCount_; - SizeType minProperties_; - SizeType maxProperties_; - bool additionalProperties_; - bool hasDependencies_; - bool hasRequired_; - bool hasSchemaDependencies_; - - const SchemaType* additionalItemsSchema_; - const SchemaType* itemsList_; - const SchemaType** itemsTuple_; - SizeType itemsTupleCount_; - SizeType minItems_; - SizeType maxItems_; - bool additionalItems_; - bool uniqueItems_; - - RegexType* pattern_; - SizeType minLength_; - SizeType maxLength_; - - SValue minimum_; - SValue maximum_; - SValue multipleOf_; - bool exclusiveMinimum_; - bool exclusiveMaximum_; - - SizeType defaultValueLength_; - - bool readOnly_; - bool writeOnly_; - bool nullable_; -}; - -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - *documentStack.template Push() = '/'; - char buffer[21]; - size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); - for (size_t i = 0; i < length; i++) - *documentStack.template Push() = static_cast(buffer[i]); - } -}; - -// Partial specialized version for char to prevent buffer copying. -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - if (sizeof(SizeType) == 4) { - char *buffer = documentStack.template Push(1 + 10); // '/' + uint - *buffer++ = '/'; - const char* end = internal::u32toa(index, buffer); - documentStack.template Pop(static_cast(10 - (end - buffer))); - } - else { - char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 - *buffer++ = '/'; - const char* end = internal::u64toa(index, buffer); - documentStack.template Pop(static_cast(20 - (end - buffer))); - } - } -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// IGenericRemoteSchemaDocumentProvider - -template -class IGenericRemoteSchemaDocumentProvider { -public: - typedef typename SchemaDocumentType::Ch Ch; - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename SchemaDocumentType::AllocatorType AllocatorType; - - virtual ~IGenericRemoteSchemaDocumentProvider() {} - virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; - virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri uri, Specification& spec) { - // Default implementation just calls through for compatibility - // Following line suppresses unused parameter warning - (void)spec; - // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi); - return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaDocument - -//! JSON schema document. -/*! - A JSON schema document is a compiled version of a JSON schema. - It is basically a tree of internal::Schema. - - \note This is an immutable class (i.e. its instance cannot be modified after construction). - \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. - \tparam Allocator Allocator type for allocating memory of this document. -*/ -template -class GenericSchemaDocument { -public: - typedef ValueT ValueType; - typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; - typedef Allocator AllocatorType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef internal::Schema SchemaType; - typedef GenericPointer PointerType; - typedef GenericValue GValue; - typedef GenericUri UriType; - typedef GenericStringRef StringRefType; - friend class internal::Schema; - template - friend class GenericSchemaValidator; - - //! Constructor. - /*! - Compile a JSON document into schema document. - - \param document A JSON document as source. - \param uri The base URI of this schema document for purposes of violation reporting. - \param uriLength Length of \c name, in code points. - \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. - \param allocator An optional allocator instance for allocating memory. Can be null. - \param pointer An optional JSON pointer to the start of the schema document - \param spec Optional schema draft or OpenAPI version. Used if no specification in document. Defaults to draft-04. - */ - explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, - IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0, - const PointerType& pointer = PointerType(), // PR #1393 - const Specification& spec = Specification(kDraft04)) : - remoteProvider_(remoteProvider), - allocator_(allocator), - ownAllocator_(), - root_(), - typeless_(), - schemaMap_(allocator, kInitialSchemaMapSize), - schemaRef_(allocator, kInitialSchemaRefSize), - spec_(spec), - error_(kObjectType), - currentError_() - { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument"); - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - Ch noUri[1] = {0}; - uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); - docId_ = UriType(uri_, allocator_); - - typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); - new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_); - - // Establish the schema draft or open api version. - // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document. - SetSchemaSpecification(document); - - // Generate root schema, it will call CreateSchema() to create sub-schemas, - // And call HandleRefSchema() if there are $ref. - // PR #1393 use input pointer if supplied - root_ = typeless_; - if (pointer.GetTokenCount() == 0) { - CreateSchemaRecursive(&root_, pointer, document, document, docId_); - } - else if (const ValueType* v = pointer.Get(document)) { - CreateSchema(&root_, pointer, *v, document, docId_); - } - else { - GenericStringBuffer sb; - pointer.StringifyUriFragment(sb); - SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch))); - } - - RAPIDJSON_ASSERT(root_ != 0); - - schemaRef_.ShrinkToFit(); // Deallocate all memory for ref - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : - remoteProvider_(rhs.remoteProvider_), - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - root_(rhs.root_), - typeless_(rhs.typeless_), - schemaMap_(std::move(rhs.schemaMap_)), - schemaRef_(std::move(rhs.schemaRef_)), - uri_(std::move(rhs.uri_)), - docId_(std::move(rhs.docId_)), - spec_(rhs.spec_), - error_(std::move(rhs.error_)), - currentError_(std::move(rhs.currentError_)) - { - rhs.remoteProvider_ = 0; - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.typeless_ = 0; - } -#endif - - //! Destructor - ~GenericSchemaDocument() { - while (!schemaMap_.Empty()) - schemaMap_.template Pop(1)->~SchemaEntry(); - - if (typeless_) { - typeless_->~SchemaType(); - Allocator::Free(typeless_); - } - - // these may contain some allocator data so clear before deleting ownAllocator_ - uri_.SetNull(); - error_.SetNull(); - currentError_.SetNull(); - - RAPIDJSON_DELETE(ownAllocator_); - } - - const GValue& GetURI() const { return uri_; } - - const Specification& GetSpecification() const { return spec_; } - bool IsSupportedSpecification() const { return spec_.IsSupported(); } - - //! Static method to get the specification of any schema document - // Returns kDraftNone if document is silent - static const Specification GetSpecification(const ValueType& document) { - SchemaDraft draft = GetSchemaDraft(document); - if (draft != kDraftNone) - return Specification(draft); - else { - OpenApiVersion oapi = GetOpenApiVersion(document); - if (oapi != kVersionNone) - return Specification(oapi); - } - return Specification(kDraftNone); - } - - //! Get the root schema. - const SchemaType& GetRoot() const { return *root_; } - - //! Gets the error object. - GValue& GetError() { return error_; } - const GValue& GetError() const { return error_; } - - static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) { - switch (schemaErrorCode) { - case kSchemaErrorStartUnknown: return GetStartUnknownString(); - case kSchemaErrorRefPlainName: return GetRefPlainNameString(); - case kSchemaErrorRefInvalid: return GetRefInvalidString(); - case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString(); - case kSchemaErrorRefUnknown: return GetRefUnknownString(); - case kSchemaErrorRefCyclical: return GetRefCyclicalString(); - case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString(); - case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString(); - case kSchemaErrorRegexInvalid: return GetRegexInvalidString(); - case kSchemaErrorSpecUnknown: return GetSpecUnknownString(); - case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString(); - case kSchemaErrorSpecIllegal: return GetSpecIllegalString(); - case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString(); - default: return GetNullString(); - } - } - - //! Default error method - void SchemaError(const SchemaErrorCode code, const PointerType& location) { - currentError_ = GValue(kObjectType); - AddCurrentError(code, location); - } - - //! Method for error with single string value insert - void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) { - currentError_ = GValue(kObjectType); - currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_); - AddCurrentError(code, location); - } - - //! Method for error with invalid pointer - void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) { - currentError_ = GValue(kObjectType); - currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_); - currentError_.AddMember(GetOffsetString(), static_cast(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_); - AddCurrentError(code, location); - } - - private: - //! Prohibit copying - GenericSchemaDocument(const GenericSchemaDocument&); - //! Prohibit assignment - GenericSchemaDocument& operator=(const GenericSchemaDocument&); - - typedef const PointerType* SchemaRefPtr; // PR #1393 - - struct SchemaEntry { - SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} - ~SchemaEntry() { - if (owned) { - schema->~SchemaType(); - Allocator::Free(schema); - } - } - PointerType pointer; - SchemaType* schema; - bool owned; - }; - - void AddErrorInstanceLocation(GValue& result, const PointerType& location) { - GenericStringBuffer sb; - location.StringifyUriFragment(sb); - GValue instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), *allocator_); - result.AddMember(GetInstanceRefString(), instanceRef, *allocator_); - } - - void AddError(GValue& keyword, GValue& error) { - typename GValue::MemberIterator member = error_.FindMember(keyword); - if (member == error_.MemberEnd()) - error_.AddMember(keyword, error, *allocator_); - else { - if (member->value.IsObject()) { - GValue errors(kArrayType); - errors.PushBack(member->value, *allocator_); - member->value = errors; - } - member->value.PushBack(error, *allocator_); - } - } - - void AddCurrentError(const SchemaErrorCode code, const PointerType& location) { - RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code)); - currentError_.AddMember(GetErrorCodeString(), code, *allocator_); - AddErrorInstanceLocation(currentError_, location); - AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_); - } - -#define RAPIDJSON_STRING_(name, ...) \ - static const StringRefType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ - return v;\ - } - - RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') - RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') - RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e') - RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't') - - RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') - RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n') - RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd') - RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l') - RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n') - RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e') - RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd') - RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd') - RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n') - RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l') - RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r') - RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a') - RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y') - RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd') - -#undef RAPIDJSON_STRING_ - - // Static method to get schema draft of any schema document - static SchemaDraft GetSchemaDraft(const ValueType& document) { - static const Ch kDraft03String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; - static const Ch kDraft04String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; - static const Ch kDraft05String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; - static const Ch kDraft06String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; - static const Ch kDraft07String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; - static const Ch kDraft2019_09String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' }; - static const Ch kDraft2020_12String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' }; - - if (!document.IsObject()) { - return kDraftNone; - } - - // Get the schema draft from the $schema keyword at the supplied location - typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString()); - if (itr != document.MemberEnd()) { - if (!itr->value.IsString()) return kDraftUnknown; - const UriType draftUri(itr->value); - // Check base uri for match - if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04; - if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05; - if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06; - if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07; - if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03; - if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09; - if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12; - return kDraftUnknown; - } - // $schema not found - return kDraftNone; - } - - - // Get open api version of any schema document - static OpenApiVersion GetOpenApiVersion(const ValueType& document) { - static const Ch kVersion20String[] = { '2', '.', '0', '\0' }; - static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level - static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level - static SizeType len = internal::StrLen(kVersion30String); - - if (!document.IsObject()) { - return kVersionNone; - } - - // Get the open api version from the swagger / openapi keyword at the supplied location - typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString()); - if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString()); - if (itr != document.MemberEnd()) { - if (!itr->value.IsString()) return kVersionUnknown; - const ValueType kVersion20Value(kVersion20String); - if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly - const ValueType kVersion30Value(kVersion30String); - if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x - const ValueType kVersion31Value(kVersion31String); - if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x - return kVersionUnknown; - } - // swagger or openapi not found - return kVersionNone; - } - - // Get the draft of the schema or the open api version (which implies the draft). - // Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on. - void SetSchemaSpecification(const ValueType& document) { - // Look for '$schema', 'swagger' or 'openapi' keyword at document root - SchemaDraft docDraft = GetSchemaDraft(document); - OpenApiVersion docOapi = GetOpenApiVersion(document); - // Error if both in document - if (docDraft != kDraftNone && docOapi != kVersionNone) - SchemaError(kSchemaErrorSpecIllegal, PointerType()); - // Use document draft or open api version if present or use spec from constructor - if (docDraft != kDraftNone) - spec_ = Specification(docDraft); - else if (docOapi != kVersionNone) - spec_ = Specification(docOapi); - // Error if draft or version unknown - if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown) - SchemaError(kSchemaErrorSpecUnknown, PointerType()); - else if (!spec_.IsSupported()) - SchemaError(kSchemaErrorSpecUnsupported, PointerType()); - } - - // Changed by PR #1393 - void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { - if (v.GetType() == kObjectType) { - UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_); - - for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid); - } - else if (v.GetType() == kArrayType) - for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id); - } - - // Changed by PR #1393 - const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { - RAPIDJSON_ASSERT(pointer.IsValid()); - GenericStringBuffer sb; - pointer.StringifyUriFragment(sb); - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString()); - if (v.IsObject()) { - if (const SchemaType* sc = GetSchema(pointer)) { - if (schema) - *schema = sc; - AddSchemaRefs(const_cast(sc)); - } - else if (!HandleRefSchema(pointer, schema, v, document, id)) { - // The new schema constructor adds itself and its $ref(s) to schemaMap_ - SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id); - if (schema) - *schema = s; - return s->GetId(); - } - } - else { - if (schema) - *schema = typeless_; - AddSchemaRefs(typeless_); - } - return id; - } - - // Changed by PR #1393 - // TODO should this return a UriType& ? - bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) { - typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString()); - if (itr == v.MemberEnd()) - return false; - - GenericStringBuffer sb; - source.StringifyUriFragment(sb); - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString()); - // Resolve the source pointer to the $ref'ed schema (finally) - new (schemaRef_.template Push()) SchemaRefPtr(&source); - - if (itr->value.IsString()) { - SizeType len = itr->value.GetStringLength(); - if (len == 0) - SchemaError(kSchemaErrorRefInvalid, source); - else { - // First resolve $ref against the in-scope id - UriType scopeId = UriType(id, allocator_); - UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_); - RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString()); - // See if the resolved $ref minus the fragment matches a resolved id in this document - // Search from the root. Returns the subschema in the document and its absolute JSON pointer. - PointerType basePointer = PointerType(); - const ValueType *base = FindId(document, ref, basePointer, docId_, false); - if (!base) { - // Remote reference - call the remote document provider - if (!remoteProvider_) - SchemaError(kSchemaErrorRefNoRemoteProvider, source); - else { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) { - const Ch* s = ref.GetFragString(); - len = ref.GetFragStringLength(); - if (len <= 1 || s[1] == '/') { - // JSON pointer fragment, absolute in the remote schema - const PointerType pointer(s, len, allocator_); - if (!pointer.IsValid()) - SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer); - else { - // Get the subschema - if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) { - if (schema) - *schema = sc; - AddSchemaRefs(const_cast(sc)); - return true; - } else - SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); - } - } else - // Plain name fragment, not allowed in remote schema - SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len); - } else - SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength()); - } - } - else { // Local reference - const Ch* s = ref.GetFragString(); - len = ref.GetFragStringLength(); - if (len <= 1 || s[1] == '/') { - // JSON pointer fragment, relative to the resolved URI - const PointerType relPointer(s, len, allocator_); - if (!relPointer.IsValid()) - SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer); - else { - // Get the subschema - if (const ValueType *pv = relPointer.Get(*base)) { - // Now get the absolute JSON pointer by adding relative to base - PointerType pointer(basePointer, allocator_); - for (SizeType i = 0; i < relPointer.GetTokenCount(); i++) - pointer = pointer.Append(relPointer.GetTokens()[i], allocator_); - if (IsCyclicRef(pointer)) - SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength()); - else { - // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there - // TODO: cache pointer <-> id mapping - size_t unresolvedTokenIndex; - scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); - CreateSchema(schema, pointer, *pv, document, scopeId); - return true; - } - } else - SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); - } - } else { - // Plain name fragment, relative to the resolved URI - // Not supported in open api 2.0 and 3.0 - PointerType pointer(allocator_); - if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30) - SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len); - // See if the fragment matches an id in this document. - // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer. - else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) { - if (IsCyclicRef(pointer)) - SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength()); - else { - // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there - // TODO: cache pointer <-> id mapping - size_t unresolvedTokenIndex; - scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); - CreateSchema(schema, pointer, *pv, document, scopeId); - return true; - } - } else - SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); - } - } - } - } - - // Invalid/Unknown $ref - if (schema) - *schema = typeless_; - AddSchemaRefs(typeless_); - return true; - } - - //! Find the first subschema with a resolved 'id' that matches the specified URI. - // If full specified use all URI else ignore fragment. - // If found, return a pointer to the subschema and its JSON pointer. - // TODO cache pointer <-> id mapping - ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const { - SizeType i = 0; - ValueType* resval = 0; - UriType tempuri = UriType(finduri, allocator_); - UriType localuri = UriType(baseuri, allocator_); - if (doc.GetType() == kObjectType) { - // Establish the base URI of this object - typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString()); - if (m != doc.MemberEnd() && m->value.GetType() == kStringType) { - localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_); - } - // See if it matches - if (localuri.Match(finduri, full)) { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString()); - resval = const_cast(&doc); - resptr = here; - return resval; - } - // No match, continue looking - for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) { - if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) { - resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_)); - } - if (resval) break; - } - } else if (doc.GetType() == kArrayType) { - // Continue looking - for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) { - if (v->GetType() == kObjectType || v->GetType() == kArrayType) { - resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_)); - } - if (resval) break; - i++; - } - } - return resval; - } - - // Added by PR #1393 - void AddSchemaRefs(SchemaType* schema) { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs"); - while (!schemaRef_.Empty()) { - SchemaRefPtr *ref = schemaRef_.template Pop(1); - SchemaEntry *entry = schemaMap_.template Push(); - new (entry) SchemaEntry(**ref, schema, false, allocator_); - } - } - - // Added by PR #1393 - bool IsCyclicRef(const PointerType& pointer) const { - for (const SchemaRefPtr* ref = schemaRef_.template Bottom(); ref != schemaRef_.template End(); ++ref) - if (pointer == **ref) - return true; - return false; - } - - const SchemaType* GetSchema(const PointerType& pointer) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (pointer == target->pointer) - return target->schema; - return 0; - } - - PointerType GetPointer(const SchemaType* schema) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (schema == target->schema) - return target->pointer; - return PointerType(); - } - - const SchemaType* GetTypeless() const { return typeless_; } - - static const size_t kInitialSchemaMapSize = 64; - static const size_t kInitialSchemaRefSize = 64; - - IRemoteSchemaDocumentProviderType* remoteProvider_; - Allocator *allocator_; - Allocator *ownAllocator_; - const SchemaType* root_; //!< Root schema. - SchemaType* typeless_; - internal::Stack schemaMap_; // Stores created Pointer -> Schemas - internal::Stack schemaRef_; // Stores Pointer(s) from $ref(s) until resolved - GValue uri_; // Schema document URI - UriType docId_; - Specification spec_; - GValue error_; - GValue currentError_; -}; - -//! GenericSchemaDocument using Value type. -typedef GenericSchemaDocument SchemaDocument; -//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaValidator - -//! JSON Schema Validator. -/*! - A SAX style JSON schema validator. - It uses a \c GenericSchemaDocument to validate SAX events. - It delegates the incoming SAX events to an output handler. - The default output handler does nothing. - It can be reused multiple times by calling \c Reset(). - - \tparam SchemaDocumentType Type of schema document. - \tparam OutputHandler Type of output handler. Default handler does nothing. - \tparam StateAllocator Allocator for storing the internal validation states. -*/ -template < - typename SchemaDocumentType, - typename OutputHandler = BaseReaderHandler, - typename StateAllocator = CrtAllocator> -class GenericSchemaValidator : - public internal::ISchemaStateFactory, - public internal::ISchemaValidator, - public internal::IValidationErrorHandler { -public: - typedef typename SchemaDocumentType::SchemaType SchemaType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename SchemaType::EncodingType EncodingType; - typedef typename SchemaType::SValue SValue; - typedef typename EncodingType::Ch Ch; - typedef GenericStringRef StringRefType; - typedef GenericValue ValueType; - - //! Constructor without output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - outputHandler_(0), - error_(kObjectType), - currentError_(), - missingDependents_(), - valid_(true), - flags_(kValidateDefaultFlags), - depth_(0) - { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator"); - } - - //! Constructor with output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - OutputHandler& outputHandler, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - outputHandler_(&outputHandler), - error_(kObjectType), - currentError_(), - missingDependents_(), - valid_(true), - flags_(kValidateDefaultFlags), - depth_(0) - { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)"); - } - - //! Destructor. - ~GenericSchemaValidator() { - Reset(); - RAPIDJSON_DELETE(ownStateAllocator_); - } - - //! Reset the internal states. - void Reset() { - while (!schemaStack_.Empty()) - PopSchema(); - documentStack_.Clear(); - ResetError(); - } - - //! Reset the error state. - void ResetError() { - error_.SetObject(); - currentError_.SetNull(); - missingDependents_.SetNull(); - valid_ = true; - } - - //! Implementation of ISchemaValidator - void SetValidateFlags(unsigned flags) { - flags_ = flags; - } - virtual unsigned GetValidateFlags() const { - return flags_; - } - - virtual bool IsValid() const { - if (!valid_) return false; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false; - return true; - } - //! End of Implementation of ISchemaValidator - - //! Gets the error object. - ValueType& GetError() { return error_; } - const ValueType& GetError() const { return error_; } - - //! Gets the JSON pointer pointed to the invalid schema. - // If reporting all errors, the stack will be empty. - PointerType GetInvalidSchemaPointer() const { - return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); - } - - //! Gets the keyword of invalid schema. - // If reporting all errors, the stack will be empty, so return "errors". - const Ch* GetInvalidSchemaKeyword() const { - if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString(); - return 0; - } - - //! Gets the error code of invalid schema. - // If reporting all errors, the stack will be empty, so return kValidateErrors. - ValidateErrorCode GetInvalidSchemaCode() const { - if (!schemaStack_.Empty()) return CurrentContext().invalidCode; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors; - return kValidateErrorNone; - } - - //! Gets the JSON pointer pointed to the invalid value. - // If reporting all errors, the stack will be empty. - PointerType GetInvalidDocumentPointer() const { - if (documentStack_.Empty()) { - return PointerType(); - } - else { - return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); - } - } - - void NotMultipleOf(int64_t actual, const SValue& expected) { - AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); - } - void NotMultipleOf(uint64_t actual, const SValue& expected) { - AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); - } - void NotMultipleOf(double actual, const SValue& expected) { - AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); - } - void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMaximumString : 0); - } - void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMaximumString : 0); - } - void AboveMaximum(double actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMaximumString : 0); - } - void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMinimumString : 0); - } - void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMinimumString : 0); - } - void BelowMinimum(double actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMinimumString : 0); - } - - void TooLong(const Ch* str, SizeType length, SizeType expected) { - AddNumberError(kValidateErrorMaxLength, - ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); - } - void TooShort(const Ch* str, SizeType length, SizeType expected) { - AddNumberError(kValidateErrorMinLength, - ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); - } - void DoesNotMatch(const Ch* str, SizeType length) { - currentError_.SetObject(); - currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); - AddCurrentError(kValidateErrorPattern); - } - - void DisallowedItem(SizeType index) { - currentError_.SetObject(); - currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); - AddCurrentError(kValidateErrorAdditionalItems, true); - } - void TooFewItems(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMinItems, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void TooManyItems(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMaxItems, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void DuplicateItems(SizeType index1, SizeType index2) { - ValueType duplicates(kArrayType); - duplicates.PushBack(index1, GetStateAllocator()); - duplicates.PushBack(index2, GetStateAllocator()); - currentError_.SetObject(); - currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); - AddCurrentError(kValidateErrorUniqueItems, true); - } - - void TooManyProperties(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMaxProperties, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void TooFewProperties(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMinProperties, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void StartMissingProperties() { - currentError_.SetArray(); - } - void AddMissingProperty(const SValue& name) { - currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); - } - bool EndMissingProperties() { - if (currentError_.Empty()) - return false; - ValueType error(kObjectType); - error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); - currentError_ = error; - AddCurrentError(kValidateErrorRequired); - return true; - } - void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { - for (SizeType i = 0; i < count; ++i) - MergeError(static_cast(subvalidators[i])->GetError()); - } - void DisallowedProperty(const Ch* name, SizeType length) { - currentError_.SetObject(); - currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); - AddCurrentError(kValidateErrorAdditionalProperties, true); - } - - void StartDependencyErrors() { - currentError_.SetObject(); - } - void StartMissingDependentProperties() { - missingDependents_.SetArray(); - } - void AddMissingDependentProperty(const SValue& targetName) { - missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); - } - void EndMissingDependentProperties(const SValue& sourceName) { - if (!missingDependents_.Empty()) { - // Create equivalent 'required' error - ValueType error(kObjectType); - ValidateErrorCode code = kValidateErrorRequired; - error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator()); - AddErrorCode(error, code); - AddErrorInstanceLocation(error, false); - // When appending to a pointer ensure its allocator is used - PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator()); - AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator())); - ValueType wrapper(kObjectType); - wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator()); - currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator()); - } - } - void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { - currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), - static_cast(subvalidator)->GetError(), GetStateAllocator()); - } - bool EndDependencyErrors() { - if (currentError_.ObjectEmpty()) - return false; - ValueType error(kObjectType); - error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); - currentError_ = error; - AddCurrentError(kValidateErrorDependencies); - return true; - } - - void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) { - currentError_.SetObject(); - AddCurrentError(code); - } - void StartDisallowedType() { - currentError_.SetArray(); - } - void AddExpectedType(const typename SchemaType::ValueType& expectedType) { - currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); - } - void EndDisallowedType(const typename SchemaType::ValueType& actualType) { - ValueType error(kObjectType); - error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); - error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); - currentError_ = error; - AddCurrentError(kValidateErrorType); - } - void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { - // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf - AddErrorArray(kValidateErrorAllOf, subvalidators, count); - //for (SizeType i = 0; i < count; ++i) { - // MergeError(static_cast(subvalidators[i])->GetError()); - //} - } - void NoneOf(ISchemaValidator** subvalidators, SizeType count) { - AddErrorArray(kValidateErrorAnyOf, subvalidators, count); - } - void NotOneOf(ISchemaValidator** subvalidators, SizeType count) { - AddErrorArray(kValidateErrorOneOf, subvalidators, count); - } - void MultipleOneOf(SizeType index1, SizeType index2) { - ValueType matches(kArrayType); - matches.PushBack(index1, GetStateAllocator()); - matches.PushBack(index2, GetStateAllocator()); - currentError_.SetObject(); - currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator()); - AddCurrentError(kValidateErrorOneOfMatch); - } - void Disallowed() { - currentError_.SetObject(); - AddCurrentError(kValidateErrorNot); - } - void DisallowedWhenWriting() { - currentError_.SetObject(); - AddCurrentError(kValidateErrorReadOnly); - } - void DisallowedWhenReading() { - currentError_.SetObject(); - AddCurrentError(kValidateErrorWriteOnly); - } - -#define RAPIDJSON_STRING_(name, ...) \ - static const StringRefType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ - return v;\ - } - - RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') - RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') - RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') - RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') - RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') - RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') - RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') - RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') - RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e') - RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') - RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's') - -#undef RAPIDJSON_STRING_ - -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ - if (!valid_) return false; \ - if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ - *documentStack_.template Push() = '\0';\ - documentStack_.template Pop(1);\ - RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom());\ - valid_ = false;\ - return valid_;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ - for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ - if (context->hasher)\ - static_cast(context->hasher)->method arg2;\ - if (context->validators)\ - for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ - static_cast(context->validators[i_])->method arg2;\ - if (context->patternPropertiesValidators)\ - for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ - static_cast(context->patternPropertiesValidators[i_])->method arg2;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\ - return valid_; - -#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ - RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } - bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } - bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } - bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } - bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } - bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } - bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } - bool RawNumber(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - bool String(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - - bool StartObject() { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject"); - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - valid_ = !outputHandler_ || outputHandler_->StartObject(); - return valid_; - } - - bool Key(const Ch* str, SizeType len, bool copy) { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str); - if (!valid_) return false; - AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) { - valid_ = false; - return valid_; - } - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); - return valid_; - } - - bool EndObject(SizeType memberCount) { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject"); - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) { - valid_ = false; - return valid_; - } - RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); - } - - bool StartArray() { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray"); - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - valid_ = !outputHandler_ || outputHandler_->StartArray(); - return valid_; - } - - bool EndArray(SizeType elementCount) { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray"); - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) { - valid_ = false; - return valid_; - } - RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); - } - -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ -#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ -#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ - - // Implementation of ISchemaStateFactory - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) { - *documentStack_.template Push() = '\0'; - documentStack_.template Pop(1); - ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), - depth_ + 1, - &GetStateAllocator()); - sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag); - return sv; - } - - virtual void DestroySchemaValidator(ISchemaValidator* validator) { - GenericSchemaValidator* v = static_cast(validator); - v->~GenericSchemaValidator(); - StateAllocator::Free(v); - } - - virtual void* CreateHasher() { - return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); - } - - virtual uint64_t GetHashCode(void* hasher) { - return static_cast(hasher)->GetHashCode(); - } - - virtual void DestroyHasher(void* hasher) { - HasherType* h = static_cast(hasher); - h->~HasherType(); - StateAllocator::Free(h); - } - - virtual void* MallocState(size_t size) { - return GetStateAllocator().Malloc(size); - } - - virtual void FreeState(void* p) { - StateAllocator::Free(p); - } - // End of implementation of ISchemaStateFactory - -private: - typedef typename SchemaType::Context Context; - typedef GenericValue, StateAllocator> HashCodeArray; - typedef internal::Hasher HasherType; - - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - const SchemaType& root, - const char* basePath, size_t basePathSize, - unsigned depth, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(root), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - outputHandler_(0), - error_(kObjectType), - currentError_(), - missingDependents_(), - valid_(true), - flags_(kValidateDefaultFlags), - depth_(depth) - { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : ""); - if (basePath && basePathSize) - memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); - } - - StateAllocator& GetStateAllocator() { - if (!stateAllocator_) - stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); - return *stateAllocator_; - } - - bool GetContinueOnErrors() const { - return flags_ & kValidateContinueOnErrorFlag; - } - - bool BeginValue() { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue"); - if (schemaStack_.Empty()) - PushSchema(root_); - else { - if (CurrentContext().inArray) - internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - - if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors()) - return false; - - SizeType count = CurrentContext().patternPropertiesSchemaCount; - const SchemaType** sa = CurrentContext().patternPropertiesSchemas; - typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; - bool valueUniqueness = CurrentContext().valueUniqueness; - RAPIDJSON_ASSERT(CurrentContext().valueSchema); - PushSchema(*CurrentContext().valueSchema); - - if (count > 0) { - CurrentContext().objectPatternValidatorType = patternValidatorType; - ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; - SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; - va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); - std::memset(va, 0, sizeof(ISchemaValidator*) * count); - for (SizeType i = 0; i < count; i++) - va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError - } - - CurrentContext().arrayUniqueness = valueUniqueness; - } - return true; - } - - bool EndValue() { - RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue"); - if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors()) - return false; - - GenericStringBuffer sb; - schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb); - *documentStack_.template Push() = '\0'; - documentStack_.template Pop(1); - RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom(), depth_); - void* hasher = CurrentContext().hasher; - uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast(hasher)->GetHashCode() : 0; - - PopSchema(); - - if (!schemaStack_.Empty()) { - Context& context = CurrentContext(); - // Only check uniqueness if there is a hasher - if (hasher && context.valueUniqueness) { - HashCodeArray* a = static_cast(context.arrayElementHashCodes); - if (!a) - CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); - for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) - if (itr->GetUint64() == h) { - DuplicateItems(static_cast(itr - a->Begin()), a->Size()); - // Cleanup before returning if continuing - if (GetContinueOnErrors()) { - a->PushBack(h, GetStateAllocator()); - while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/'); - } - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems); - } - a->PushBack(h, GetStateAllocator()); - } - } - - // Remove the last token of document pointer - while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') - ; - - return true; - } - - void AppendToken(const Ch* str, SizeType len) { - documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters - *documentStack_.template PushUnsafe() = '/'; - for (SizeType i = 0; i < len; i++) { - if (str[i] == '~') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '0'; - } - else if (str[i] == '/') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '1'; - } - else - *documentStack_.template PushUnsafe() = str[i]; - } - } - - RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema, flags_); } - - RAPIDJSON_FORCEINLINE void PopSchema() { - Context* c = schemaStack_.template Pop(1); - if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { - a->~HashCodeArray(); - StateAllocator::Free(a); - } - c->~Context(); - } - - void AddErrorInstanceLocation(ValueType& result, bool parent) { - GenericStringBuffer sb; - PointerType instancePointer = GetInvalidDocumentPointer(); - ((parent && instancePointer.GetTokenCount() > 0) - ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) - : instancePointer).StringifyUriFragment(sb); - ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), - GetStateAllocator()); - result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); - } - - void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) { - GenericStringBuffer sb; - SizeType len = CurrentSchema().GetURI().GetStringLength(); - if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch)); - if (schema.GetTokenCount()) schema.StringifyUriFragment(sb); - else GetInvalidSchemaPointer().StringifyUriFragment(sb); - ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), - GetStateAllocator()); - result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); - } - - void AddErrorCode(ValueType& result, const ValidateErrorCode code) { - result.AddMember(GetErrorCodeString(), code, GetStateAllocator()); - } - - void AddError(ValueType& keyword, ValueType& error) { - typename ValueType::MemberIterator member = error_.FindMember(keyword); - if (member == error_.MemberEnd()) - error_.AddMember(keyword, error, GetStateAllocator()); - else { - if (member->value.IsObject()) { - ValueType errors(kArrayType); - errors.PushBack(member->value, GetStateAllocator()); - member->value = errors; - } - member->value.PushBack(error, GetStateAllocator()); - } - } - - void AddCurrentError(const ValidateErrorCode code, bool parent = false) { - AddErrorCode(currentError_, code); - AddErrorInstanceLocation(currentError_, parent); - AddErrorSchemaLocation(currentError_); - AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_); - } - - void MergeError(ValueType& other) { - for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { - AddError(it->name, it->value); - } - } - - void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected, - const typename SchemaType::ValueType& (*exclusive)() = 0) { - currentError_.SetObject(); - currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); - currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); - if (exclusive) - currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); - AddCurrentError(code); - } - - void AddErrorArray(const ValidateErrorCode code, - ISchemaValidator** subvalidators, SizeType count) { - ValueType errors(kArrayType); - for (SizeType i = 0; i < count; ++i) - errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); - currentError_.SetObject(); - currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); - AddCurrentError(code); - } - - const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } - Context& CurrentContext() { return *schemaStack_.template Top(); } - const Context& CurrentContext() const { return *schemaStack_.template Top(); } - - static const size_t kDefaultSchemaStackCapacity = 1024; - static const size_t kDefaultDocumentStackCapacity = 256; - const SchemaDocumentType* schemaDocument_; - const SchemaType& root_; - StateAllocator* stateAllocator_; - StateAllocator* ownStateAllocator_; - internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) - internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) - OutputHandler* outputHandler_; - ValueType error_; - ValueType currentError_; - ValueType missingDependents_; - bool valid_; - unsigned flags_; - unsigned depth_; -}; - -typedef GenericSchemaValidator SchemaValidator; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidatingReader - -//! A helper class for parsing with validation. -/*! - This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). - - \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam SourceEncoding Encoding of the input stream. - \tparam SchemaDocumentType Type of schema document. - \tparam StackAllocator Allocator type for stack. -*/ -template < - unsigned parseFlags, - typename InputStream, - typename SourceEncoding, - typename SchemaDocumentType = SchemaDocument, - typename StackAllocator = CrtAllocator> -class SchemaValidatingReader { -public: - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename InputStream::Ch Ch; - typedef GenericValue ValueType; - - //! Constructor - /*! - \param is Input stream. - \param sd Schema document. - */ - SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {} - - template - bool operator()(Handler& handler) { - GenericReader reader; - GenericSchemaValidator validator(sd_, handler); - parseResult_ = reader.template Parse(is_, validator); - - isValid_ = validator.IsValid(); - if (isValid_) { - invalidSchemaPointer_ = PointerType(); - invalidSchemaKeyword_ = 0; - invalidDocumentPointer_ = PointerType(); - error_.SetObject(); - } - else { - invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); - invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); - invalidSchemaCode_ = validator.GetInvalidSchemaCode(); - invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); - error_.CopyFrom(validator.GetError(), allocator_); - } - - return parseResult_; - } - - const ParseResult& GetParseResult() const { return parseResult_; } - bool IsValid() const { return isValid_; } - const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } - const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } - const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } - const ValueType& GetError() const { return error_; } - ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; } - -private: - InputStream& is_; - const SchemaDocumentType& sd_; - - ParseResult parseResult_; - PointerType invalidSchemaPointer_; - const Ch* invalidSchemaKeyword_; - PointerType invalidDocumentPointer_; - ValidateErrorCode invalidSchemaCode_; - StackAllocator allocator_; - ValueType error_; - bool isValid_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#endif // RAPIDJSON_SCHEMA_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stream.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stream.h deleted file mode 100644 index 1fd70915..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stream.h +++ /dev/null @@ -1,223 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#include "rapidjson.h" - -#ifndef RAPIDJSON_STREAM_H_ -#define RAPIDJSON_STREAM_H_ - -#include "encodings.h" - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Stream - -/*! \class rapidjson::Stream - \brief Concept for reading and writing characters. - - For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). - - For write-only stream, only need to implement Put() and Flush(). - -\code -concept Stream { - typename Ch; //!< Character type of the stream. - - //! Read the current character from stream without moving the read cursor. - Ch Peek() const; - - //! Read the current character from stream and moving the read cursor to next character. - Ch Take(); - - //! Get the current read cursor. - //! \return Number of characters read from start. - size_t Tell(); - - //! Begin writing operation at the current read pointer. - //! \return The begin writer pointer. - Ch* PutBegin(); - - //! Write a character. - void Put(Ch c); - - //! Flush the buffer. - void Flush(); - - //! End the writing operation. - //! \param begin The begin write pointer returned by PutBegin(). - //! \return Number of characters written. - size_t PutEnd(Ch* begin); -} -\endcode -*/ - -//! Provides additional information for stream. -/*! - By using traits pattern, this type provides a default configuration for stream. - For custom stream, this type can be specialized for other configuration. - See TEST(Reader, CustomStringStream) in readertest.cpp for example. -*/ -template -struct StreamTraits { - //! Whether to make local copy of stream for optimization during parsing. - /*! - By default, for safety, streams do not use local copy optimization. - Stream that can be copied fast should specialize this, like StreamTraits. - */ - enum { copyOptimization = 0 }; -}; - -//! Reserve n characters for writing to a stream. -template -inline void PutReserve(Stream& stream, size_t count) { - (void)stream; - (void)count; -} - -//! Write character to a stream, presuming buffer is reserved. -template -inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { - stream.Put(c); -} - -//! Put N copies of a character to a stream. -template -inline void PutN(Stream& stream, Ch c, size_t n) { - PutReserve(stream, n); - for (size_t i = 0; i < n; i++) - PutUnsafe(stream, c); -} - -/////////////////////////////////////////////////////////////////////////////// -// GenericStreamWrapper - -//! A Stream Wrapper -/*! \tThis string stream is a wrapper for any stream by just forwarding any - \treceived message to the origin stream. - \note implements Stream concept -*/ - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4702) // unreachable code -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -template > -class GenericStreamWrapper { -public: - typedef typename Encoding::Ch Ch; - GenericStreamWrapper(InputStream& is): is_(is) {} - - Ch Peek() const { return is_.Peek(); } - Ch Take() { return is_.Take(); } - size_t Tell() { return is_.Tell(); } - Ch* PutBegin() { return is_.PutBegin(); } - void Put(Ch ch) { is_.Put(ch); } - void Flush() { is_.Flush(); } - size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } - - // wrapper for MemoryStream - const Ch* Peek4() const { return is_.Peek4(); } - - // wrapper for AutoUTFInputStream - UTFType GetType() const { return is_.GetType(); } - bool HasBOM() const { return is_.HasBOM(); } - -protected: - InputStream& is_; -}; - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_POP -#endif - -/////////////////////////////////////////////////////////////////////////////// -// StringStream - -//! Read-only string stream. -/*! \note implements Stream concept -*/ -template -struct GenericStringStream { - typedef typename Encoding::Ch Ch; - - GenericStringStream(const Ch *src) : src_(src), head_(src) {} - - Ch Peek() const { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() const { return static_cast(src_ - head_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! String stream with UTF8 encoding. -typedef GenericStringStream > StringStream; - -/////////////////////////////////////////////////////////////////////////////// -// InsituStringStream - -//! A read-write string stream. -/*! This string stream is particularly designed for in-situ parsing. - \note implements Stream concept -*/ -template -struct GenericInsituStringStream { - typedef typename Encoding::Ch Ch; - - GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} - - // Read - Ch Peek() { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() { return static_cast(src_ - head_); } - - // Write - void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } - - Ch* PutBegin() { return dst_ = src_; } - size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } - void Flush() {} - - Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } - void Pop(size_t count) { dst_ -= count; } - - Ch* src_; - Ch* dst_; - Ch* head_; -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! Insitu string stream with UTF8 encoding. -typedef GenericInsituStringStream > InsituStringStream; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STREAM_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stringbuffer.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stringbuffer.h deleted file mode 100644 index 82ad3ca6..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/stringbuffer.h +++ /dev/null @@ -1,121 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRINGBUFFER_H_ -#define RAPIDJSON_STRINGBUFFER_H_ - -#include "stream.h" -#include "internal/stack.h" - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move -#endif - -#include "internal/stack.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory output stream. -/*! - \tparam Encoding Encoding of the stream. - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept -*/ -template -class GenericStringBuffer { -public: - typedef typename Encoding::Ch Ch; - - GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} - GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { - if (&rhs != this) - stack_ = std::move(rhs.stack_); - return *this; - } -#endif - - void Put(Ch c) { *stack_.template Push() = c; } - void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } - void Flush() {} - - void Clear() { stack_.Clear(); } - void ShrinkToFit() { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.ShrinkToFit(); - stack_.template Pop(1); - } - - void Reserve(size_t count) { stack_.template Reserve(count); } - Ch* Push(size_t count) { return stack_.template Push(count); } - Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } - void Pop(size_t count) { stack_.template Pop(count); } - - const Ch* GetString() const { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.template Pop(1); - - return stack_.template Bottom(); - } - - //! Get the size of string in bytes in the string buffer. - size_t GetSize() const { return stack_.GetSize(); } - - //! Get the length of string in Ch in the string buffer. - size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } - - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; - -private: - // Prohibit copy constructor & assignment operator. - GenericStringBuffer(const GenericStringBuffer&); - GenericStringBuffer& operator=(const GenericStringBuffer&); -}; - -//! String buffer with UTF8 encoding -typedef GenericStringBuffer > StringBuffer; - -template -inline void PutReserve(GenericStringBuffer& stream, size_t count) { - stream.Reserve(count); -} - -template -inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { - stream.PutUnsafe(c); -} - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { - std::memset(stream.stack_.Push(n), c, n * sizeof(c)); -} - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/uri.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/uri.h deleted file mode 100644 index f93e508a..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/uri.h +++ /dev/null @@ -1,481 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// (C) Copyright IBM Corporation 2021 -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_URI_H_ -#define RAPIDJSON_URI_H_ - -#include "internal/strfunc.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// GenericUri - -template -class GenericUri { -public: - typedef typename ValueType::Ch Ch; -#if RAPIDJSON_HAS_STDSTRING - typedef std::basic_string String; -#endif - - //! Constructors - GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - } - - GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - Parse(uri, len); - } - - GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - Parse(uri, internal::StrLen(uri)); - } - - // Use with specializations of GenericValue - template GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - const Ch* u = uri.template Get(); // TypeHelper from document.h - Parse(u, internal::StrLen(u)); - } - -#if RAPIDJSON_HAS_STDSTRING - GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - Parse(uri.c_str(), internal::StrLen(uri.c_str())); - } -#endif - - //! Copy constructor - GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() { - *this = rhs; - } - - //! Copy constructor - GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - *this = rhs; - } - - //! Destructor. - ~GenericUri() { - Free(); - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Assignment operator - GenericUri& operator=(const GenericUri& rhs) { - if (this != &rhs) { - // Do not delete ownAllocator - Free(); - Allocate(rhs.GetStringLength()); - auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength()); - path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength()); - query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength()); - frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength()); - base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength()); - uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength()); - CopyPart(uri_, rhs.uri_, rhs.GetStringLength()); - } - return *this; - } - - //! Getters - // Use with specializations of GenericValue - template void Get(T& uri, Allocator& allocator) { - uri.template Set(this->GetString(), allocator); // TypeHelper from document.h - } - - const Ch* GetString() const { return uri_; } - SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen(uri_); } - const Ch* GetBaseString() const { return base_; } - SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen(base_); } - const Ch* GetSchemeString() const { return scheme_; } - SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen(scheme_); } - const Ch* GetAuthString() const { return auth_; } - SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen(auth_); } - const Ch* GetPathString() const { return path_; } - SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen(path_); } - const Ch* GetQueryString() const { return query_; } - SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen(query_); } - const Ch* GetFragString() const { return frag_; } - SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen(frag_); } - -#if RAPIDJSON_HAS_STDSTRING - static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); } - static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); } - static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); } - static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); } - static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); } - static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); } - static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); } -#endif - - //! Equality operators - bool operator==(const GenericUri& rhs) const { - return Match(rhs, true); - } - - bool operator!=(const GenericUri& rhs) const { - return !Match(rhs, true); - } - - bool Match(const GenericUri& uri, bool full = true) const { - Ch* s1; - Ch* s2; - if (full) { - s1 = uri_; - s2 = uri.uri_; - } else { - s1 = base_; - s2 = uri.base_; - } - if (s1 == s2) return true; - if (s1 == 0 || s2 == 0) return false; - return internal::StrCmp(s1, s2) == 0; - } - - //! Resolve this URI against another (base) URI in accordance with URI resolution rules. - // See https://tools.ietf.org/html/rfc3986 - // Use for resolving an id or $ref with an in-scope id. - // Returns a new GenericUri for the resolved URI. - GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) { - GenericUri resuri; - resuri.allocator_ = allocator; - // Ensure enough space for combining paths - resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash - - if (!(GetSchemeStringLength() == 0)) { - // Use all of this URI - resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength()); - resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); - resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - resuri.RemoveDotSegments(); - } else { - // Use the base scheme - resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength()); - if (!(GetAuthStringLength() == 0)) { - // Use this auth, path, query - resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); - resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - resuri.RemoveDotSegments(); - } else { - // Use the base auth - resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength()); - if (GetPathStringLength() == 0) { - // Use the base path - resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength()); - if (GetQueryStringLength() == 0) { - // Use the base query - resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength()); - } else { - // Use this query - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - } - } else { - if (path_[0] == '/') { - // Absolute path - use all of this path - resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); - resuri.RemoveDotSegments(); - } else { - // Relative path - append this path to base path after base path's last slash - size_t pos = 0; - if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) { - resuri.path_[pos] = '/'; - pos++; - } - size_t lastslashpos = baseuri.GetPathStringLength(); - while (lastslashpos > 0) { - if (baseuri.path_[lastslashpos - 1] == '/') break; - lastslashpos--; - } - std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch)); - pos += lastslashpos; - resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength()); - resuri.RemoveDotSegments(); - } - // Use this query - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - } - } - } - // Always use this frag - resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength()); - - // Re-constitute base_ and uri_ - resuri.SetBase(); - resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1; - resuri.SetUri(); - return resuri; - } - - //! Get the allocator of this GenericUri. - Allocator& GetAllocator() { return *allocator_; } - -private: - // Allocate memory for a URI - // Returns total amount allocated - std::size_t Allocate(std::size_t len) { - // Create own allocator if user did not supply. - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated. - // Order: scheme, auth, path, query, frag, base, uri - // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. - size_t total = (3 * len + 7) * sizeof(Ch); - scheme_ = static_cast(allocator_->Malloc(total)); - *scheme_ = '\0'; - auth_ = scheme_; - auth_++; - *auth_ = '\0'; - path_ = auth_; - path_++; - *path_ = '\0'; - query_ = path_; - query_++; - *query_ = '\0'; - frag_ = query_; - frag_++; - *frag_ = '\0'; - base_ = frag_; - base_++; - *base_ = '\0'; - uri_ = base_; - uri_++; - *uri_ = '\0'; - return total; - } - - // Free memory for a URI - void Free() { - if (scheme_) { - Allocator::Free(scheme_); - scheme_ = 0; - } - } - - // Parse a URI into constituent scheme, authority, path, query, & fragment parts - // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per - // https://tools.ietf.org/html/rfc3986 - void Parse(const Ch* uri, std::size_t len) { - std::size_t start = 0, pos1 = 0, pos2 = 0; - Allocate(len); - - // Look for scheme ([^:/?#]+):)? - if (start < len) { - while (pos1 < len) { - if (uri[pos1] == ':') break; - pos1++; - } - if (pos1 != len) { - while (pos2 < len) { - if (uri[pos2] == '/') break; - if (uri[pos2] == '?') break; - if (uri[pos2] == '#') break; - pos2++; - } - if (pos1 < pos2) { - pos1++; - std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch)); - scheme_[pos1] = '\0'; - start = pos1; - } - } - } - // Look for auth (//([^/?#]*))? - // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. - auth_ = scheme_ + GetSchemeStringLength(); - auth_++; - *auth_ = '\0'; - if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') { - pos2 = start + 2; - while (pos2 < len) { - if (uri[pos2] == '/') break; - if (uri[pos2] == '?') break; - if (uri[pos2] == '#') break; - pos2++; - } - std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch)); - auth_[pos2 - start] = '\0'; - start = pos2; - } - // Look for path ([^?#]*) - // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. - path_ = auth_ + GetAuthStringLength(); - path_++; - *path_ = '\0'; - if (start < len) { - pos2 = start; - while (pos2 < len) { - if (uri[pos2] == '?') break; - if (uri[pos2] == '#') break; - pos2++; - } - if (start != pos2) { - std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch)); - path_[pos2 - start] = '\0'; - if (path_[0] == '/') - RemoveDotSegments(); // absolute path - normalize - start = pos2; - } - } - // Look for query (\?([^#]*))? - // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. - query_ = path_ + GetPathStringLength(); - query_++; - *query_ = '\0'; - if (start < len && uri[start] == '?') { - pos2 = start + 1; - while (pos2 < len) { - if (uri[pos2] == '#') break; - pos2++; - } - if (start != pos2) { - std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch)); - query_[pos2 - start] = '\0'; - start = pos2; - } - } - // Look for fragment (#(.*))? - // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. - frag_ = query_ + GetQueryStringLength(); - frag_++; - *frag_ = '\0'; - if (start < len && uri[start] == '#') { - std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch)); - frag_[len - start] = '\0'; - } - - // Re-constitute base_ and uri_ - base_ = frag_ + GetFragStringLength() + 1; - SetBase(); - uri_ = base_ + GetBaseStringLength() + 1; - SetUri(); - } - - // Reconstitute base - void SetBase() { - Ch* next = base_; - std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch)); - next+= GetSchemeStringLength(); - std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch)); - next+= GetAuthStringLength(); - std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch)); - next+= GetPathStringLength(); - std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch)); - next+= GetQueryStringLength(); - *next = '\0'; - } - - // Reconstitute uri - void SetUri() { - Ch* next = uri_; - std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch)); - next+= GetBaseStringLength(); - std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch)); - next+= GetFragStringLength(); - *next = '\0'; - } - - // Copy a part from one GenericUri to another - // Return the pointer to the next part to be copied to - Ch* CopyPart(Ch* to, Ch* from, std::size_t len) { - RAPIDJSON_ASSERT(to != 0); - RAPIDJSON_ASSERT(from != 0); - std::memcpy(to, from, len * sizeof(Ch)); - to[len] = '\0'; - Ch* next = to + len + 1; - return next; - } - - // Remove . and .. segments from the path_ member. - // https://tools.ietf.org/html/rfc3986 - // This is done in place as we are only removing segments. - void RemoveDotSegments() { - std::size_t pathlen = GetPathStringLength(); - std::size_t pathpos = 0; // Position in path_ - std::size_t newpos = 0; // Position in new path_ - - // Loop through each segment in original path_ - while (pathpos < pathlen) { - // Get next segment, bounded by '/' or end - size_t slashpos = 0; - while ((pathpos + slashpos) < pathlen) { - if (path_[pathpos + slashpos] == '/') break; - slashpos++; - } - // Check for .. and . segments - if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') { - // Backup a .. segment in the new path_ - // We expect to find a previously added slash at the end or nothing - RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/'); - size_t lastslashpos = newpos; - // Make sure we don't go beyond the start segment - if (lastslashpos > 1) { - // Find the next to last slash and back up to it - lastslashpos--; - while (lastslashpos > 0) { - if (path_[lastslashpos - 1] == '/') break; - lastslashpos--; - } - // Set the new path_ position - newpos = lastslashpos; - } - } else if (slashpos == 1 && path_[pathpos] == '.') { - // Discard . segment, leaves new path_ unchanged - } else { - // Move any other kind of segment to the new path_ - RAPIDJSON_ASSERT(newpos <= pathpos); - std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch)); - newpos += slashpos; - // Add slash if not at end - if ((pathpos + slashpos) < pathlen) { - path_[newpos] = '/'; - newpos++; - } - } - // Move to next segment - pathpos += slashpos + 1; - } - path_[newpos] = '\0'; - } - - Ch* uri_; // Everything - Ch* base_; // Everything except fragment - Ch* scheme_; // Includes the : - Ch* auth_; // Includes the // - Ch* path_; // Absolute if starts with / - Ch* query_; // Includes the ? - Ch* frag_; // Includes the # - - Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. - Allocator* ownAllocator_; //!< Allocator owned by this Uri. -}; - -//! GenericUri for Value (UTF-8, default allocator). -typedef GenericUri Uri; - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_URI_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/writer.h b/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/writer.h deleted file mode 100644 index 8b389219..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/rapidjson/writer.h +++ /dev/null @@ -1,710 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_WRITER_H_ -#define RAPIDJSON_WRITER_H_ - -#include "stream.h" -#include "internal/clzll.h" -#include "internal/meta.h" -#include "internal/stack.h" -#include "internal/strfunc.h" -#include "internal/dtoa.h" -#include "internal/itoa.h" -#include "stringbuffer.h" -#include // placement new - -#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -#endif -#ifdef RAPIDJSON_SSE42 -#include -#elif defined(RAPIDJSON_SSE2) -#include -#elif defined(RAPIDJSON_NEON) -#include -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(c++98-compat) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// WriteFlag - -/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kWriteDefaultFlags definition. - - User can define this as any \c WriteFlag combinations. -*/ -#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS -#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags -#endif - -//! Combination of writeFlags -enum WriteFlag { - kWriteNoFlags = 0, //!< No flags are set. - kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. - kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. - kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS -}; - -//! JSON writer -/*! Writer implements the concept Handler. - It generates JSON text by events to an output os. - - User may programmatically calls the functions of a writer to generate JSON text. - - On the other side, a writer can also be passed to objects that generates events, - - for example Reader::Parse() and Document::Accept(). - - \tparam OutputStream Type of output stream. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam StackAllocator Type of allocator for allocating memory of stack. - \note implements Handler concept -*/ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> -class Writer { -public: - typedef typename SourceEncoding::Ch Ch; - - static const int kDefaultMaxDecimalPlaces = 324; - - //! Constructor - /*! \param os Output stream. - \param stackAllocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - explicit - Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} - - explicit - Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Writer(Writer&& rhs) : - os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { - rhs.os_ = 0; - } -#endif - - //! Reset the writer with a new stream. - /*! - This function reset the writer with a new stream and default settings, - in order to make a Writer object reusable for output multiple JSONs. - - \param os New output stream. - \code - Writer writer(os1); - writer.StartObject(); - // ... - writer.EndObject(); - - writer.Reset(os2); - writer.StartObject(); - // ... - writer.EndObject(); - \endcode - */ - void Reset(OutputStream& os) { - os_ = &os; - hasRoot_ = false; - level_stack_.Clear(); - } - - //! Checks whether the output is a complete JSON. - /*! - A complete JSON has a complete root object or array. - */ - bool IsComplete() const { - return hasRoot_ && level_stack_.Empty(); - } - - int GetMaxDecimalPlaces() const { - return maxDecimalPlaces_; - } - - //! Sets the maximum number of decimal places for double output. - /*! - This setting truncates the output with specified number of decimal places. - - For example, - - \code - writer.SetMaxDecimalPlaces(3); - writer.StartArray(); - writer.Double(0.12345); // "0.123" - writer.Double(0.0001); // "0.0" - writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) - writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) - writer.EndArray(); - \endcode - - The default setting does not truncate any decimal places. You can restore to this setting by calling - \code - writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); - \endcode - */ - void SetMaxDecimalPlaces(int maxDecimalPlaces) { - maxDecimalPlaces_ = maxDecimalPlaces; - } - - /*!@name Implementation of Handler - \see Handler - */ - //@{ - - bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } - bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } - bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } - bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } - bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } - bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } - - //! Writes the given \c double value to the stream - /*! - \param d The value to be written. - \return Whether it is succeed. - */ - bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } - - bool RawNumber(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - Prefix(kNumberType); - return EndValue(WriteString(str, length)); - } - - bool String(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - Prefix(kStringType); - return EndValue(WriteString(str, length)); - } - -#if RAPIDJSON_HAS_STDSTRING - bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); - } -#endif - - bool StartObject() { - Prefix(kObjectType); - new (level_stack_.template Push()) Level(false); - return WriteStartObject(); - } - - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - -#if RAPIDJSON_HAS_STDSTRING - bool Key(const std::basic_string& str) - { - return Key(str.data(), SizeType(str.size())); - } -#endif - - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object - RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value - level_stack_.template Pop(1); - return EndValue(WriteEndObject()); - } - - bool StartArray() { - Prefix(kArrayType); - new (level_stack_.template Push()) Level(true); - return WriteStartArray(); - } - - bool EndArray(SizeType elementCount = 0) { - (void)elementCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); - level_stack_.template Pop(1); - return EndValue(WriteEndArray()); - } - //@} - - /*! @name Convenience extensions */ - //@{ - - //! Simpler but slower overload. - bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } - - //@} - - //! Write a raw JSON value. - /*! - For user to write a stringified JSON as a value. - - \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. - \param length Length of the json. - \param type Type of the root of json. - */ - bool RawValue(const Ch* json, size_t length, Type type) { - RAPIDJSON_ASSERT(json != 0); - Prefix(type); - return EndValue(WriteRawValue(json, length)); - } - - //! Flush the output stream. - /*! - Allows the user to flush the output stream immediately. - */ - void Flush() { - os_->Flush(); - } - - static const size_t kDefaultLevelDepth = 32; - -protected: - //! Information for each nested level - struct Level { - Level(bool inArray_) : valueCount(0), inArray(inArray_) {} - size_t valueCount; //!< number of values in this level - bool inArray; //!< true if in array, otherwise in object - }; - - bool WriteNull() { - PutReserve(*os_, 4); - PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; - } - - bool WriteBool(bool b) { - if (b) { - PutReserve(*os_, 4); - PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); - } - else { - PutReserve(*os_, 5); - PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); - } - return true; - } - - bool WriteInt(int i) { - char buffer[11]; - const char* end = internal::i32toa(i, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteUint(unsigned u) { - char buffer[10]; - const char* end = internal::u32toa(u, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteInt64(int64_t i64) { - char buffer[21]; - const char* end = internal::i64toa(i64, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char* end = internal::u64toa(u64, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - if (!(writeFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; - } - - char buffer[25]; - char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); - PutReserve(*os_, static_cast(end - buffer)); - for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteString(const Ch* str, SizeType length) { - static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - static const char escape[256] = { -#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 - 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - Z16, Z16, // 30~4F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF -#undef Z16 - }; - - if (TargetEncoding::supportUnicode) - PutReserve(*os_, 2 + length * 6); // "\uxxxx..." - else - PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." - - PutUnsafe(*os_, '\"'); - GenericStringStream is(str); - while (ScanWriteUnescapedString(is, length)) { - const Ch c = is.Peek(); - if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { - // Unicode escaping - unsigned codepoint; - if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) - return false; - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, 'u'); - if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); - } - else { - RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); - // Surrogate pair - unsigned s = codepoint - 0x010000; - unsigned lead = (s >> 10) + 0xD800; - unsigned trail = (s & 0x3FF) + 0xDC00; - PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(lead ) & 15]); - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, 'u'); - PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(trail ) & 15]); - } - } - else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { - is.Take(); - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, static_cast(escape[static_cast(c)])); - if (escape[static_cast(c)] == 'u') { - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); - PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); - } - } - else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? - Transcoder::Validate(is, *os_) : - Transcoder::TranscodeUnsafe(is, *os_)))) - return false; - } - PutUnsafe(*os_, '\"'); - return true; - } - - bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { - return RAPIDJSON_LIKELY(is.Tell() < length); - } - - bool WriteStartObject() { os_->Put('{'); return true; } - bool WriteEndObject() { os_->Put('}'); return true; } - bool WriteStartArray() { os_->Put('['); return true; } - bool WriteEndArray() { os_->Put(']'); return true; } - - bool WriteRawValue(const Ch* json, size_t length) { - PutReserve(*os_, length); - GenericStringStream is(json); - while (RAPIDJSON_LIKELY(is.Tell() < length)) { - RAPIDJSON_ASSERT(is.Peek() != '\0'); - if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? - Transcoder::Validate(is, *os_) : - Transcoder::TranscodeUnsafe(is, *os_)))) - return false; - } - return true; - } - - void Prefix(Type type) { - (void)type; - if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root - Level* level = level_stack_.template Top(); - if (level->valueCount > 0) { - if (level->inArray) - os_->Put(','); // add comma if it is not the first element in array - else // in object - os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. - hasRoot_ = true; - } - } - - // Flush the value if it is the top level one. - bool EndValue(bool ret) { - if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text - Flush(); - return ret; - } - - OutputStream* os_; - internal::Stack level_stack_; - int maxDecimalPlaces_; - bool hasRoot_; - -private: - // Prohibit copy constructor & assignment operator. - Writer(const Writer&); - Writer& operator=(const Writer&); -}; - -// Full specialization for StringStream to prevent memory copying - -template<> -inline bool Writer::WriteInt(int i) { - char *buffer = os_->Push(11); - const char* end = internal::i32toa(i, buffer); - os_->Pop(static_cast(11 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteUint(unsigned u) { - char *buffer = os_->Push(10); - const char* end = internal::u32toa(u, buffer); - os_->Pop(static_cast(10 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteInt64(int64_t i64) { - char *buffer = os_->Push(21); - const char* end = internal::i64toa(i64, buffer); - os_->Pop(static_cast(21 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteUint64(uint64_t u) { - char *buffer = os_->Push(20); - const char* end = internal::u64toa(u, buffer); - os_->Pop(static_cast(20 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). - if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; - } - - char *buffer = os_->Push(25); - char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); - os_->Pop(static_cast(25 - (end - buffer))); - return true; -} - -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) -template<> -inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { - if (length < 16) - return RAPIDJSON_LIKELY(is.Tell() < length); - - if (!RAPIDJSON_LIKELY(is.Tell() < length)) - return false; - - const char* p = is.src_; - const char* end = is.head_ + length; - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); - if (nextAligned > end) - return true; - - while (p != nextAligned) - if (*p < 0x20 || *p == '\"' || *p == '\\') { - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); - } - else - os_->PutUnsafe(*p++); - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (; p != endAligned; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - SizeType len; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - len = offset; -#else - len = static_cast(__builtin_ffs(r) - 1); -#endif - char* q = reinterpret_cast(os_->PushUnsafe(len)); - for (size_t i = 0; i < len; i++) - q[i] = p[i]; - - p += len; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); - } - - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); -} -#elif defined(RAPIDJSON_NEON) -template<> -inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { - if (length < 16) - return RAPIDJSON_LIKELY(is.Tell() < length); - - if (!RAPIDJSON_LIKELY(is.Tell() < length)) - return false; - - const char* p = is.src_; - const char* end = is.head_ + length; - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); - if (nextAligned > end) - return true; - - while (p != nextAligned) - if (*p < 0x20 || *p == '\"' || *p == '\\') { - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); - } - else - os_->PutUnsafe(*p++); - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (; p != endAligned; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - SizeType len = 0; - bool escaped = false; - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - len = 8 + (lz >> 3); - escaped = true; - } - } else { - uint32_t lz = internal::clzll(low); - len = lz >> 3; - escaped = true; - } - if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped - char* q = reinterpret_cast(os_->PushUnsafe(len)); - for (size_t i = 0; i < len; i++) - q[i] = p[i]; - - p += len; - break; - } - vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); - } - - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); -} -#endif // RAPIDJSON_NEON - -RAPIDJSON_NAMESPACE_END - -#if defined(_MSC_VER) || defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/thorvg_lottie.h b/godot/thirdparty/thorvg/src/loaders/lottie/thorvg_lottie.h deleted file mode 100644 index 2fe88f01..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/thorvg_lottie.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _THORVG_LOTTIE_H_ -#define _THORVG_LOTTIE_H_ - -#include - -namespace tvg -{ - -/** - * @class LottieAnimation - * - * @brief The LottieAnimation class enables control of advanced Lottie features. - * - * This class extends the Animation and has additional interfaces. - * - * @see Animation - * - * @since 0.15 - */ -class TVG_API LottieAnimation final : public Animation -{ -public: - ~LottieAnimation(); - - /** - * @brief Override Lottie properties using slot data. - * - * @param[in] slot The Lottie slot data in JSON format to override, or @c nullptr to reset. - * - * @retval Result::Success When succeed. - * @retval Result::InsufficientCondition In case the animation is not loaded. - * @retval Result::InvalidArguments When the given parameter is invalid. - * - * @note Experimental API - */ - Result override(const char* slot) noexcept; - - /** - * @brief Specifies a segment by marker. - * - * Markers are used to control animation playback by specifying start and end points, - * eliminating the need to know the exact frame numbers. - * Generally, markers are designated at the design level, - * meaning the callers must know the marker name in advance to use it. - * - * @param[in] marker The name of the segment marker. - * - * @retval Result::Success When successful. - * @retval Result::InsufficientCondition If the animation is not loaded. - * @retval Result::InvalidArguments When the given parameter is invalid. - * @retval Result::NonSupport When it's not animatable. - * - * @note If a @c marker is specified, the previously set segment will be disregarded. - * @note Set @c nullptr to reset the specified segment. - * @see Animation::segment(float begin, float end) - * @note Experimental API - */ - Result segment(const char* marker) noexcept; - - /** - * @brief Gets the marker count of the animation. - * - * @retval The count of the markers, zero if there is no marker. - * - * @see LottieAnimation::marker() - * @note Experimental API - */ - uint32_t markersCnt() noexcept; - - /** - * @brief Gets the marker name by a given index. - * - * @param[in] idx The index of the animation marker, starts from 0. - * - * @retval The name of marker when succeed, @c nullptr otherwise. - * - * @see LottieAnimation::markersCnt() - * @note Experimental API - */ - const char* marker(uint32_t idx) noexcept; - - /** - * @brief Creates a new LottieAnimation object. - * - * @return A new LottieAnimation object. - * - * @since 0.15 - */ - static std::unique_ptr gen() noexcept; -}; - -} //namespace - -#endif //_THORVG_LOTTIE_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieAnimation.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieAnimation.cpp deleted file mode 100644 index 4ae6396e..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieAnimation.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "tvgCommon.h" -#include "thorvg_lottie.h" -#include "tvgLottieLoader.h" -#include "tvgAnimation.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -LottieAnimation::~LottieAnimation() -{ -} - - -Result LottieAnimation::override(const char* slot) noexcept -{ - if (!pImpl->picture->pImpl->loader) return Result::InsufficientCondition; - - if (static_cast(pImpl->picture->pImpl->loader)->override(slot)) return Result::Success; - - return Result::InvalidArguments; -} - - -Result LottieAnimation::segment(const char* marker) noexcept -{ - auto loader = pImpl->picture->pImpl->loader; - if (!loader) return Result::InsufficientCondition; - - if (!marker) { - static_cast(loader)->segment(0.0f, 1.0f); - return Result::Success; - } - - float begin, end; - if (!static_cast(loader)->segment(marker, begin, end)) return Result::InvalidArguments; - - return static_cast(this)->segment(begin, end); -} - - -uint32_t LottieAnimation::markersCnt() noexcept -{ - auto loader = pImpl->picture->pImpl->loader; - if (!loader) return 0; - return static_cast(loader)->markersCnt(); -} - - -const char* LottieAnimation::marker(uint32_t idx) noexcept -{ - auto loader = pImpl->picture->pImpl->loader; - if (!loader) return nullptr; - return static_cast(loader)->markers(idx); -} - - -unique_ptr LottieAnimation::gen() noexcept -{ - return unique_ptr(new LottieAnimation); -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.cpp deleted file mode 100644 index b92a5db1..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.cpp +++ /dev/null @@ -1,1434 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include - -#include "tvgCommon.h" -#include "tvgMath.h" -#include "tvgLottieModel.h" -#include "tvgLottieBuilder.h" -#include "tvgLottieExpressions.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -static bool _buildComposition(LottieComposition* comp, LottieLayer* parent); -static bool _draw(LottieGroup* parent, LottieShape* shape, RenderContext* ctx); - - -static void _rotationXYZ(Matrix* m, float degreeX, float degreeY, float degreeZ) -{ - auto radianX = deg2rad(degreeX); - auto radianY = deg2rad(degreeY); - auto radianZ = deg2rad(degreeZ); - - auto cx = cosf(radianX), sx = sinf(radianX); - auto cy = cosf(radianY), sy = sinf(radianY);; - auto cz = cosf(radianZ), sz = sinf(radianZ);; - m->e11 = cy * cz; - m->e12 = -cy * sz; - m->e21 = sx * sy * cz + cx * sz; - m->e22 = -sx * sy * sz + cx * cz; -} - - -static void _rotationZ(Matrix* m, float degree) -{ - if (degree == 0.0f) return; - auto radian = deg2rad(degree); - m->e11 = cosf(radian); - m->e12 = -sinf(radian); - m->e21 = sinf(radian); - m->e22 = cosf(radian); -} - - -static void _skew(Matrix* m, float angleDeg, float axisDeg) -{ - auto angle = -deg2rad(angleDeg); - float tanVal = tanf(angle); - - axisDeg = fmod(axisDeg, 180.0f); - if (fabsf(axisDeg) < 0.01f || fabsf(axisDeg - 180.0f) < 0.01f || fabsf(axisDeg + 180.0f) < 0.01f) { - float cosVal = cosf(deg2rad(axisDeg)); - auto B = cosVal * cosVal * tanVal; - m->e12 += B * m->e11; - m->e22 += B * m->e21; - return; - } else if (fabsf(axisDeg - 90.0f) < 0.01f || fabsf(axisDeg + 90.0f) < 0.01f) { - float sinVal = -sinf(deg2rad(axisDeg)); - auto C = sinVal * sinVal * tanVal; - m->e11 -= C * m->e12; - m->e21 -= C * m->e22; - return; - } - - auto axis = -deg2rad(axisDeg); - float cosVal = cosf(axis); - float sinVal = sinf(axis); - auto A = sinVal * cosVal * tanVal; - auto B = cosVal * cosVal * tanVal; - auto C = sinVal * sinVal * tanVal; - - auto e11 = m->e11; - auto e21 = m->e21; - m->e11 = (1.0f - A) * e11 - C * m->e12; - m->e12 = B * e11 + (1.0f + A) * m->e12; - m->e21 = (1.0f - A) * e21 - C * m->e22; - m->e22 = B * e21 + (1.0f + A) * m->e22; -} - - -static bool _updateTransform(LottieTransform* transform, float frameNo, bool autoOrient, Matrix& matrix, uint8_t& opacity, LottieExpressions* exps) -{ - identity(&matrix); - - if (!transform) { - opacity = 255; - return false; - } - - if (transform->coords) { - translate(&matrix, transform->coords->x(frameNo, exps), transform->coords->y(frameNo, exps)); - } else { - auto position = transform->position(frameNo, exps); - translate(&matrix, position.x, position.y); - } - - auto angle = 0.0f; - if (autoOrient) angle = transform->position.angle(frameNo); - if (transform->rotationEx) _rotationXYZ(&matrix, transform->rotationEx->x(frameNo, exps), transform->rotationEx->y(frameNo, exps), transform->rotation(frameNo, exps) + angle); - else _rotationZ(&matrix, transform->rotation(frameNo, exps) + angle); - - - auto skewAngle = transform->skewAngle(frameNo, exps); - if (skewAngle != 0.0f) { - // For angles where tangent explodes, the shape degenerates into an infinitely thin line. - // This is handled by zeroing out the matrix due to finite numerical precision. - skewAngle = fmod(skewAngle, 180.0f); - if (fabsf(skewAngle - 90.0f) < 0.01f || fabsf(skewAngle + 90.0f) < 0.01f) return false; - _skew(&matrix, skewAngle, transform->skewAxis(frameNo, exps)); - } - - auto scale = transform->scale(frameNo, exps); - scaleR(&matrix, scale.x * 0.01f, scale.y * 0.01f); - - //Lottie specific anchor transform. - auto anchor = transform->anchor(frameNo, exps); - translateR(&matrix, -anchor.x, -anchor.y); - - //invisible just in case. - if (scale.x == 0.0f || scale.y == 0.0f) opacity = 0; - else opacity = transform->opacity(frameNo, exps); - - return true; -} - - -void LottieBuilder::updateTransform(LottieLayer* layer, float frameNo) -{ - if (!layer || tvg::equal(layer->cache.frameNo, frameNo)) return; - - auto transform = layer->transform; - auto parent = layer->parent; - - if (parent) updateTransform(parent, frameNo); - - auto& matrix = layer->cache.matrix; - - _updateTransform(transform, frameNo, layer->autoOrient, matrix, layer->cache.opacity, exps); - - if (parent) { - if (!identity((const Matrix*) &parent->cache.matrix)) { - if (identity((const Matrix*) &matrix)) layer->cache.matrix = parent->cache.matrix; - else layer->cache.matrix = parent->cache.matrix * matrix; - } - } - layer->cache.frameNo = frameNo; -} - - -void LottieBuilder::updateTransform(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto transform = static_cast(*child); - if (!transform) return; - - uint8_t opacity; - - if (parent->mergeable()) { - if (!ctx->transform) ctx->transform = (Matrix*)malloc(sizeof(Matrix)); - _updateTransform(transform, frameNo, false, *ctx->transform, opacity, exps); - return; - } - - ctx->merging = nullptr; - - Matrix matrix; - if (!_updateTransform(transform, frameNo, false, matrix, opacity, exps)) return; - - ctx->propagator->transform(PP(ctx->propagator)->transform() * matrix); - ctx->propagator->opacity(MULTIPLY(opacity, PP(ctx->propagator)->opacity)); - - //FIXME: preserve the stroke width. too workaround, need a better design. - if (P(ctx->propagator)->rs.strokeWidth() > 0.0f) { - auto denominator = sqrtf(matrix.e11 * matrix.e11 + matrix.e12 * matrix.e12); - if (denominator > 1.0f) ctx->propagator->stroke(ctx->propagator->strokeWidth() / denominator); - } -} - - -void LottieBuilder::updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& pcontexts, RenderContext* ctx) -{ - auto group = static_cast(*child); - - if (!group->visible) return; - - //Prepare render data - group->scene = parent->scene; - group->reqFragment |= ctx->reqFragment; - - //generate a merging shape to consolidate partial shapes into a single entity - if (group->mergeable()) _draw(parent, nullptr, ctx); - - Inlist contexts; - auto propagator = group->mergeable() ? ctx->propagator : static_cast(PP(ctx->propagator)->duplicate(group->pooling())); - contexts.back(new RenderContext(*ctx, propagator, group->mergeable())); - - updateChildren(group, frameNo, contexts); - - contexts.free(); -} - - -static void _updateStroke(LottieStroke* stroke, float frameNo, RenderContext* ctx, LottieExpressions* exps) -{ - ctx->propagator->stroke(stroke->width(frameNo, exps)); - ctx->propagator->stroke(stroke->cap); - ctx->propagator->stroke(stroke->join); - ctx->propagator->strokeMiterlimit(stroke->miterLimit); - - if (stroke->dashattr) { - float dashes[2]; - dashes[0] = stroke->dashSize(frameNo, exps); - dashes[1] = dashes[0] + stroke->dashGap(frameNo, exps); - P(ctx->propagator)->strokeDash(dashes, 2, stroke->dashOffset(frameNo, exps)); - } else { - ctx->propagator->stroke(nullptr, 0); - } -} - - -static bool _fragmented(LottieGroup* parent, LottieObject** child, Inlist& contexts, RenderContext* ctx) -{ - if (!ctx->reqFragment) return false; - if (ctx->fragmenting) return true; - - contexts.back(new RenderContext(*ctx, static_cast(PP(ctx->propagator)->duplicate(parent->pooling())))); - auto fragment = contexts.tail; - fragment->begin = child - 1; - ctx->fragmenting = true; - - return false; -} - - -void LottieBuilder::updateSolidStroke(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx) -{ - if (_fragmented(parent, child, contexts, ctx)) return; - - auto stroke = static_cast(*child); - - ctx->merging = nullptr; - auto color = stroke->color(frameNo, exps); - ctx->propagator->stroke(color.rgb[0], color.rgb[1], color.rgb[2], stroke->opacity(frameNo, exps)); - _updateStroke(static_cast(stroke), frameNo, ctx, exps); -} - - -void LottieBuilder::updateGradientStroke(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx) -{ - if (_fragmented(parent, child, contexts, ctx)) return; - - auto stroke = static_cast(*child); - - ctx->merging = nullptr; - ctx->propagator->stroke(unique_ptr(stroke->fill(frameNo, exps))); - _updateStroke(static_cast(stroke), frameNo, ctx, exps); -} - - -void LottieBuilder::updateSolidFill(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx) -{ - if (_fragmented(parent, child, contexts, ctx)) return; - - auto fill = static_cast(*child); - - ctx->merging = nullptr; - auto color = fill->color(frameNo, exps); - ctx->propagator->fill(color.rgb[0], color.rgb[1], color.rgb[2], fill->opacity(frameNo, exps)); - ctx->propagator->fill(fill->rule); - - if (ctx->propagator->strokeWidth() > 0) ctx->propagator->order(true); -} - - -void LottieBuilder::updateGradientFill(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx) -{ - if (_fragmented(parent, child, contexts, ctx)) return; - - auto fill = static_cast(*child); - - ctx->merging = nullptr; - //TODO: reuse the fill instance? - ctx->propagator->fill(unique_ptr(fill->fill(frameNo, exps))); - ctx->propagator->fill(fill->rule); - - if (ctx->propagator->strokeWidth() > 0) ctx->propagator->order(true); -} - - -static bool _draw(LottieGroup* parent, LottieShape* shape, RenderContext* ctx) -{ - if (ctx->merging) return false; - - if (shape) { - ctx->merging = shape->pooling(); - PP(ctx->propagator)->duplicate(ctx->merging); - } else { - ctx->merging = static_cast(ctx->propagator->duplicate()); - } - - parent->scene->push(cast(ctx->merging)); - - return true; -} - - -static void _repeat(LottieGroup* parent, Shape* path, RenderContext* ctx) -{ - Array propagators; - propagators.push(ctx->propagator); - Array shapes; - - for (auto repeater = ctx->repeaters.end() - 1; repeater >= ctx->repeaters.begin(); --repeater) { - shapes.reserve(repeater->cnt); - - for (int i = 0; i < repeater->cnt; ++i) { - auto multiplier = repeater->offset + static_cast(i); - - for (auto propagator = propagators.begin(); propagator < propagators.end(); ++propagator) { - auto shape = static_cast((*propagator)->duplicate()); - P(shape)->rs.path = P(path)->rs.path; - - auto opacity = repeater->interpOpacity ? lerp(repeater->startOpacity, repeater->endOpacity, static_cast(i + 1) / repeater->cnt) : repeater->startOpacity; - shape->opacity(opacity); - - Matrix m; - identity(&m); - translate(&m, repeater->position.x * multiplier + repeater->anchor.x, repeater->position.y * multiplier + repeater->anchor.y); - scale(&m, powf(repeater->scale.x * 0.01f, multiplier), powf(repeater->scale.y * 0.01f, multiplier)); - rotate(&m, repeater->rotation * multiplier); - translateR(&m, -repeater->anchor.x, -repeater->anchor.y); - m = repeater->transform * m; - - Matrix inv; - inverse(&repeater->transform, &inv); - shape->transform(m * (inv * PP(shape)->transform())); - shapes.push(shape); - } - } - - propagators.clear(); - propagators.reserve(shapes.count); - - //push repeat shapes in order. - if (repeater->inorder) { - for (auto shape = shapes.begin(); shape < shapes.end(); ++shape) { - parent->scene->push(cast(*shape)); - propagators.push(*shape); - } - } else if (!shapes.empty()) { - for (auto shape = shapes.end() - 1; shape >= shapes.begin(); --shape) { - parent->scene->push(cast(*shape)); - propagators.push(*shape); - } - } - shapes.clear(); - } -} - - -static void _appendRect(Shape* shape, float x, float y, float w, float h, float r, const LottieOffsetModifier* offsetPath, Matrix* transform, bool clockwise) -{ - //sharp rect - if (tvg::zero(r)) { - PathCommand commands[] = { - PathCommand::MoveTo, PathCommand::LineTo, PathCommand::LineTo, - PathCommand::LineTo, PathCommand::Close - }; - - Point points[4]; - if (clockwise) { - points[0] = {x + w, y}; - points[1] = {x + w, y + h}; - points[2] = {x, y + h}; - points[3] = {x, y}; - } else { - points[0] = {x + w, y}; - points[1] = {x, y}; - points[2] = {x, y + h}; - points[3] = {x + w, y + h}; - } - if (transform) { - for (int i = 0; i < 4; i++) { - points[i] *= *transform; - } - } - - if (offsetPath) offsetPath->modifyRect(commands, 5, points, 4, P(shape)->rs.path.cmds, P(shape)->rs.path.pts); - else shape->appendPath(commands, 5, points, 4); - //round rect - } else { - constexpr int cmdCnt = 10; - PathCommand commands[cmdCnt]; - - auto halfW = w * 0.5f; - auto halfH = h * 0.5f; - auto rx = r > halfW ? halfW : r; - auto ry = r > halfH ? halfH : r; - auto hrx = rx * PATH_KAPPA; - auto hry = ry * PATH_KAPPA; - - constexpr int ptsCnt = 17; - Point points[ptsCnt]; - if (clockwise) { - commands[0] = PathCommand::MoveTo; commands[1] = PathCommand::LineTo; commands[2] = PathCommand::CubicTo; - commands[3] = PathCommand::LineTo; commands[4] = PathCommand::CubicTo;commands[5] = PathCommand::LineTo; - commands[6] = PathCommand::CubicTo; commands[7] = PathCommand::LineTo; commands[8] = PathCommand::CubicTo; - commands[9] = PathCommand::Close; - - points[0] = {x + w, y + ry}; //moveTo - points[1] = {x + w, y + h - ry}; //lineTo - points[2] = {x + w, y + h - ry + hry}; points[3] = {x + w - rx + hrx, y + h}; points[4] = {x + w - rx, y + h}; //cubicTo - points[5] = {x + rx, y + h}, //lineTo - points[6] = {x + rx - hrx, y + h}; points[7] = {x, y + h - ry + hry}; points[8] = {x, y + h - ry}; //cubicTo - points[9] = {x, y + ry}, //lineTo - points[10] = {x, y + ry - hry}; points[11] = {x + rx - hrx, y}; points[12] = {x + rx, y}; //cubicTo - points[13] = {x + w - rx, y}; //lineTo - points[14] = {x + w - rx + hrx, y}; points[15] = {x + w, y + ry - hry}; points[16] = {x + w, y + ry}; //cubicTo - } else { - commands[0] = PathCommand::MoveTo; commands[1] = PathCommand::CubicTo; commands[2] = PathCommand::LineTo; - commands[3] = PathCommand::CubicTo; commands[4] = PathCommand::LineTo; commands[5] = PathCommand::CubicTo; - commands[6] = PathCommand::LineTo; commands[7] = PathCommand::CubicTo; commands[8] = PathCommand::LineTo; - commands[9] = PathCommand::Close; - - points[0] = {x + w, y + ry}; //moveTo - points[1] = {x + w, y + ry - hry}; points[2] = {x + w - rx + hrx, y}; points[3] = {x + w - rx, y}; //cubicTo - points[4] = {x + rx, y}, //lineTo - points[5] = {x + rx - hrx, y}; points[6] = {x, y + ry - hry}; points[7] = {x, y + ry}; //cubicTo - points[8] = {x, y + h - ry}; //lineTo - points[9] = {x, y + h - ry + hry}; points[10] = {x + rx - hrx, y + h}; points[11] = {x + rx, y + h}; //cubicTo - points[12] = {x + w - rx, y + h}; //lineTo - points[13] = {x + w - rx + hrx, y + h}; points[14] = {x + w, y + h - ry + hry}; points[15] = {x + w, y + h - ry}; //cubicTo - points[16] = {x + w, y + ry}; //lineTo - } - if (transform) { - for (int i = 0; i < ptsCnt; i++) { - points[i] *= *transform; - } - } - - if (offsetPath) offsetPath->modifyRect(commands, cmdCnt, points, ptsCnt, P(shape)->rs.path.cmds, P(shape)->rs.path.pts); - else shape->appendPath(commands, cmdCnt, points, ptsCnt); - } -} - - -void LottieBuilder::updateRect(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto rect = static_cast(*child); - - auto position = rect->position(frameNo, exps); - auto size = rect->size(frameNo, exps); - auto r = rect->radius(frameNo, exps); - if (r == 0.0f) { - if (ctx->roundness) ctx->roundness->modifyRect(size, r); - } else { - r = std::min({r, size.x * 0.5f, size.y * 0.5f}); - } - - if (!ctx->repeaters.empty()) { - auto shape = rect->pooling(); - shape->reset(); - _appendRect(shape, position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, r, ctx->offsetPath, ctx->transform, rect->clockwise); - _repeat(parent, shape, ctx); - } else { - _draw(parent, rect, ctx); - _appendRect(ctx->merging, position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, r, ctx->offsetPath, ctx->transform, rect->clockwise); - } -} - - -static void _appendCircle(Shape* shape, float cx, float cy, float rx, float ry, const LottieOffsetModifier* offsetPath, Matrix* transform, bool clockwise) -{ - if (offsetPath) offsetPath->modifyEllipse(rx, ry); - - if (rx == 0.0f || ry == 0.0f) return; - - auto rxKappa = rx * PATH_KAPPA; - auto ryKappa = ry * PATH_KAPPA; - - constexpr int cmdsCnt = 6; - PathCommand commands[cmdsCnt] = { - PathCommand::MoveTo, PathCommand::CubicTo, PathCommand::CubicTo, - PathCommand::CubicTo, PathCommand::CubicTo, PathCommand::Close - }; - - constexpr int ptsCnt = 13; - Point points[ptsCnt]; - - if (clockwise) { - points[0] = {cx, cy - ry}; //moveTo - points[1] = {cx + rxKappa, cy - ry}; points[2] = {cx + rx, cy - ryKappa}; points[3] = {cx + rx, cy}; //cubicTo - points[4] = {cx + rx, cy + ryKappa}; points[5] = {cx + rxKappa, cy + ry}; points[6] = {cx, cy + ry}; //cubicTo - points[7] = {cx - rxKappa, cy + ry}; points[8] = {cx - rx, cy + ryKappa}; points[9] = {cx - rx, cy}; //cubicTo - points[10] = {cx - rx, cy - ryKappa}; points[11] = {cx - rxKappa, cy - ry}; points[12] = {cx, cy - ry}; //cubicTo - } else { - points[0] = {cx, cy - ry}; //moveTo - points[1] = {cx - rxKappa, cy - ry}; points[2] = {cx - rx, cy - ryKappa}; points[3] = {cx - rx, cy}; //cubicTo - points[4] = {cx - rx, cy + ryKappa}; points[5] = {cx - rxKappa, cy + ry}; points[6] = {cx, cy + ry}; //cubicTo - points[7] = {cx + rxKappa, cy + ry}; points[8] = {cx + rx, cy + ryKappa}; points[9] = {cx + rx, cy}; //cubicTo - points[10] = {cx + rx, cy - ryKappa}; points[11] = {cx + rxKappa, cy - ry}; points[12] = {cx, cy - ry}; //cubicTo - } - - if (transform) { - for (int i = 0; i < ptsCnt; ++i) { - points[i] *= *transform; - } - } - - shape->appendPath(commands, cmdsCnt, points, ptsCnt); -} - - -void LottieBuilder::updateEllipse(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto ellipse = static_cast(*child); - - auto position = ellipse->position(frameNo, exps); - auto size = ellipse->size(frameNo, exps); - - if (!ctx->repeaters.empty()) { - auto shape = ellipse->pooling(); - shape->reset(); - _appendCircle(shape, position.x, position.y, size.x * 0.5f, size.y * 0.5f, ctx->offsetPath, ctx->transform, ellipse->clockwise); - _repeat(parent, shape, ctx); - } else { - _draw(parent, ellipse, ctx); - _appendCircle(ctx->merging, position.x, position.y, size.x * 0.5f, size.y * 0.5f, ctx->offsetPath, ctx->transform, ellipse->clockwise); - } -} - - -void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto path = static_cast(*child); - - if (!ctx->repeaters.empty()) { - auto shape = path->pooling(); - shape->reset(); - path->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, ctx->transform, ctx->roundness, ctx->offsetPath, exps); - _repeat(parent, shape, ctx); - } else { - _draw(parent, path, ctx); - if (path->pathset(frameNo, P(ctx->merging)->rs.path.cmds, P(ctx->merging)->rs.path.pts, ctx->transform, ctx->roundness, ctx->offsetPath, exps)) { - P(ctx->merging)->update(RenderUpdateFlag::Path); - } - } -} - - -static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offsetPath, float frameNo, Shape* merging, LottieExpressions* exps) -{ - static constexpr auto POLYSTAR_MAGIC_NUMBER = 0.47829f / 0.28f; - - auto ptsCnt = star->ptsCnt(frameNo, exps); - auto innerRadius = star->innerRadius(frameNo, exps); - auto outerRadius = star->outerRadius(frameNo, exps); - auto innerRoundness = star->innerRoundness(frameNo, exps) * 0.01f; - auto outerRoundness = star->outerRoundness(frameNo, exps) * 0.01f; - - auto angle = deg2rad(-90.0f); - auto partialPointRadius = 0.0f; - auto anglePerPoint = (2.0f * MATH_PI / ptsCnt); - auto halfAnglePerPoint = anglePerPoint * 0.5f; - auto partialPointAmount = ptsCnt - floorf(ptsCnt); - auto longSegment = false; - auto numPoints = size_t(ceilf(ptsCnt) * 2); - auto direction = star->clockwise ? 1.0f : -1.0f; - auto hasRoundness = false; - bool roundedCorner = roundness && (tvg::zero(innerRoundness) || tvg::zero(outerRoundness)); - - Shape* shape; - if (roundedCorner || offsetPath) { - shape = star->pooling(); - shape->reset(); - } else { - shape = merging; - } - - float x, y; - - if (!tvg::zero(partialPointAmount)) { - angle += halfAnglePerPoint * (1.0f - partialPointAmount) * direction; - } - - if (!tvg::zero(partialPointAmount)) { - partialPointRadius = innerRadius + partialPointAmount * (outerRadius - innerRadius); - x = partialPointRadius * cosf(angle); - y = partialPointRadius * sinf(angle); - angle += anglePerPoint * partialPointAmount * 0.5f * direction; - } else { - x = outerRadius * cosf(angle); - y = outerRadius * sinf(angle); - angle += halfAnglePerPoint * direction; - } - - if (tvg::zero(innerRoundness) && tvg::zero(outerRoundness)) { - P(shape)->rs.path.pts.reserve(numPoints + 2); - P(shape)->rs.path.cmds.reserve(numPoints + 3); - } else { - P(shape)->rs.path.pts.reserve(numPoints * 3 + 2); - P(shape)->rs.path.cmds.reserve(numPoints + 3); - hasRoundness = true; - } - - Point in = {x, y}; - if (transform) in *= *transform; - shape->moveTo(in.x, in.y); - - for (size_t i = 0; i < numPoints; i++) { - auto radius = longSegment ? outerRadius : innerRadius; - auto dTheta = halfAnglePerPoint; - if (!tvg::zero(partialPointRadius) && i == numPoints - 2) { - dTheta = anglePerPoint * partialPointAmount * 0.5f; - } - if (!tvg::zero(partialPointRadius) && i == numPoints - 1) { - radius = partialPointRadius; - } - auto previousX = x; - auto previousY = y; - x = radius * cosf(angle); - y = radius * sinf(angle); - - if (hasRoundness) { - auto cp1Theta = (tvg::atan2(previousY, previousX) - MATH_PI2 * direction); - auto cp1Dx = cosf(cp1Theta); - auto cp1Dy = sinf(cp1Theta); - auto cp2Theta = (tvg::atan2(y, x) - MATH_PI2 * direction); - auto cp2Dx = cosf(cp2Theta); - auto cp2Dy = sinf(cp2Theta); - - auto cp1Roundness = longSegment ? innerRoundness : outerRoundness; - auto cp2Roundness = longSegment ? outerRoundness : innerRoundness; - auto cp1Radius = longSegment ? innerRadius : outerRadius; - auto cp2Radius = longSegment ? outerRadius : innerRadius; - - auto cp1x = cp1Radius * cp1Roundness * POLYSTAR_MAGIC_NUMBER * cp1Dx / ptsCnt; - auto cp1y = cp1Radius * cp1Roundness * POLYSTAR_MAGIC_NUMBER * cp1Dy / ptsCnt; - auto cp2x = cp2Radius * cp2Roundness * POLYSTAR_MAGIC_NUMBER * cp2Dx / ptsCnt; - auto cp2y = cp2Radius * cp2Roundness * POLYSTAR_MAGIC_NUMBER * cp2Dy / ptsCnt; - - if (!tvg::zero(partialPointAmount) && ((i == 0) || (i == numPoints - 1))) { - cp1x *= partialPointAmount; - cp1y *= partialPointAmount; - cp2x *= partialPointAmount; - cp2y *= partialPointAmount; - } - Point in2 = {previousX - cp1x, previousY - cp1y}; - Point in3 = {x + cp2x, y + cp2y}; - Point in4 = {x, y}; - if (transform) { - in2 *= *transform; - in3 *= *transform; - in4 *= *transform; - } - shape->cubicTo(in2.x, in2.y, in3.x, in3.y, in4.x, in4.y); - } else { - Point in = {x, y}; - if (transform) in *= *transform; - shape->lineTo(in.x, in.y); - } - angle += dTheta * direction; - longSegment = !longSegment; - } - shape->close(); - - if (roundedCorner) { - if (offsetPath) { - auto intermediate = Shape::gen(); - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, outerRoundness, hasRoundness); - offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); - } else { - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, outerRoundness, hasRoundness); - } - } else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); -} - - -static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offsetPath, float frameNo, Shape* merging, LottieExpressions* exps) -{ - static constexpr auto POLYGON_MAGIC_NUMBER = 0.25f; - - auto ptsCnt = size_t(floor(star->ptsCnt(frameNo, exps))); - auto radius = star->outerRadius(frameNo, exps); - auto outerRoundness = star->outerRoundness(frameNo, exps) * 0.01f; - - auto angle = deg2rad(-90.0f); - auto anglePerPoint = 2.0f * MATH_PI / float(ptsCnt); - auto direction = star->clockwise ? 1.0f : -1.0f; - auto hasRoundness = !tvg::zero(outerRoundness); - bool roundedCorner = roundness && !hasRoundness; - auto x = radius * cosf(angle); - auto y = radius * sinf(angle); - - angle += anglePerPoint * direction; - - Shape* shape; - if (roundedCorner || offsetPath) { - shape = star->pooling(); - shape->reset(); - } else { - shape = merging; - if (hasRoundness) { - P(shape)->rs.path.pts.reserve(ptsCnt * 3 + 2); - P(shape)->rs.path.cmds.reserve(ptsCnt + 3); - } else { - P(shape)->rs.path.pts.reserve(ptsCnt + 2); - P(shape)->rs.path.cmds.reserve(ptsCnt + 3); - } - } - - Point in = {x, y}; - if (transform) in *= *transform; - shape->moveTo(in.x, in.y); - - for (size_t i = 0; i < ptsCnt; i++) { - auto previousX = x; - auto previousY = y; - x = (radius * cosf(angle)); - y = (radius * sinf(angle)); - - if (hasRoundness) { - auto cp1Theta = tvg::atan2(previousY, previousX) - MATH_PI2 * direction; - auto cp1Dx = cosf(cp1Theta); - auto cp1Dy = sinf(cp1Theta); - auto cp2Theta = tvg::atan2(y, x) - MATH_PI2 * direction; - auto cp2Dx = cosf(cp2Theta); - auto cp2Dy = sinf(cp2Theta); - - auto cp1x = radius * outerRoundness * POLYGON_MAGIC_NUMBER * cp1Dx; - auto cp1y = radius * outerRoundness * POLYGON_MAGIC_NUMBER * cp1Dy; - auto cp2x = radius * outerRoundness * POLYGON_MAGIC_NUMBER * cp2Dx; - auto cp2y = radius * outerRoundness * POLYGON_MAGIC_NUMBER * cp2Dy; - - Point in2 = {previousX - cp1x, previousY - cp1y}; - Point in3 = {x + cp2x, y + cp2y}; - Point in4 = {x, y}; - if (transform) { - in2 *= *transform; - in3 *= *transform; - in4 *= *transform; - } - shape->cubicTo(in2.x, in2.y, in3.x, in3.y, in4.x, in4.y); - } else { - Point in = {x, y}; - if (transform) in *= *transform; - shape->lineTo(in.x, in.y); - } - angle += anglePerPoint * direction; - } - shape->close(); - - if (roundedCorner) { - if (offsetPath) { - auto intermediate = Shape::gen(); - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, 0.0f, false); - offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); - } else { - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, 0.0f, false); - } - } else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); -} - - -void LottieBuilder::updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto star = static_cast(*child); - - //Optimize: Can we skip the individual coords transform? - Matrix matrix; - identity(&matrix); - auto position = star->position(frameNo, exps); - translate(&matrix, position.x, position.y); - rotate(&matrix, star->rotation(frameNo, exps)); - - if (ctx->transform) matrix = *ctx->transform * matrix; - - auto identity = tvg::identity((const Matrix*)&matrix); - - if (!ctx->repeaters.empty()) { - auto shape = star->pooling(); - shape->reset(); - if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offsetPath, frameNo, shape, exps); - else _updatePolygon(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offsetPath, frameNo, shape, exps); - _repeat(parent, shape, ctx); - } else { - _draw(parent, star, ctx); - if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offsetPath, frameNo, ctx->merging, exps); - else _updatePolygon(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offsetPath, frameNo, ctx->merging, exps); - P(ctx->merging)->update(RenderUpdateFlag::Path); - } -} - - -void LottieBuilder::updateRoundedCorner(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto roundedCorner = static_cast(*child); - auto r = roundedCorner->radius(frameNo, exps); - if (r < LottieRoundnessModifier::ROUNDNESS_EPSILON) return; - - if (!ctx->roundness) ctx->roundness = new LottieRoundnessModifier(r); - else if (ctx->roundness->r < r) ctx->roundness->r = r; -} - - -void LottieBuilder::updateOffsetPath(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto offsetPath = static_cast(*child); - if (!ctx->offsetPath) ctx->offsetPath = new LottieOffsetModifier(offsetPath->offset(frameNo, exps), offsetPath->miterLimit(frameNo, exps), offsetPath->join); -} - - -void LottieBuilder::updateRepeater(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto repeater = static_cast(*child); - - RenderRepeater r; - r.cnt = static_cast(repeater->copies(frameNo, exps)); - r.transform = PP(ctx->propagator)->transform(); - r.offset = repeater->offset(frameNo, exps); - r.position = repeater->position(frameNo, exps); - r.anchor = repeater->anchor(frameNo, exps); - r.scale = repeater->scale(frameNo, exps); - r.rotation = repeater->rotation(frameNo, exps); - r.startOpacity = repeater->startOpacity(frameNo, exps); - r.endOpacity = repeater->endOpacity(frameNo, exps); - r.inorder = repeater->inorder; - r.interpOpacity = (r.startOpacity == r.endOpacity) ? false : true; - ctx->repeaters.push(r); - - ctx->merging = nullptr; -} - - -void LottieBuilder::updateTrimpath(TVG_UNUSED LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist& contexts, RenderContext* ctx) -{ - auto trimpath = static_cast(*child); - - float begin, end; - trimpath->segment(frameNo, begin, end, exps); - - if (P(ctx->propagator)->rs.stroke) { - auto pbegin = P(ctx->propagator)->rs.stroke->trim.begin; - auto pend = P(ctx->propagator)->rs.stroke->trim.end; - auto length = fabsf(pend - pbegin); - begin = (length * begin) + pbegin; - end = (length * end) + pbegin; - } - - P(ctx->propagator)->strokeTrim(begin, end, trimpath->type == LottieTrimpath::Type::Simultaneous); - ctx->merging = nullptr; -} - - -void LottieBuilder::updateChildren(LottieGroup* parent, float frameNo, Inlist& contexts) -{ - contexts.head->begin = parent->children.end() - 1; - - while (!contexts.empty()) { - auto ctx = contexts.front(); - ctx->reqFragment = parent->reqFragment; - for (auto child = ctx->begin; child >= parent->children.data; --child) { - //Here switch-case statements are more performant than virtual methods. - switch ((*child)->type) { - case LottieObject::Group: { - updateGroup(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Transform: { - updateTransform(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::SolidFill: { - updateSolidFill(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::SolidStroke: { - updateSolidStroke(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::GradientFill: { - updateGradientFill(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::GradientStroke: { - updateGradientStroke(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Rect: { - updateRect(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Ellipse: { - updateEllipse(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Path: { - updatePath(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Polystar: { - updatePolystar(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Trimpath: { - updateTrimpath(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::Repeater: { - updateRepeater(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::RoundedCorner: { - updateRoundedCorner(parent, child, frameNo, contexts, ctx); - break; - } - case LottieObject::OffsetPath: { - updateOffsetPath(parent, child, frameNo, contexts, ctx); - break; - } - default: break; - } - if (ctx->propagator->opacity() == 0) break; - } - delete(ctx); - } -} - - -void LottieBuilder::updatePrecomp(LottieComposition* comp, LottieLayer* precomp, float frameNo) -{ - if (precomp->children.empty()) return; - - frameNo = precomp->remap(comp, frameNo, exps); - - for (auto c = precomp->children.end() - 1; c >= precomp->children.begin(); --c) { - auto child = static_cast(*c); - if (!child->matteSrc) updateLayer(comp, precomp->scene, child, frameNo); - } - - //clip the layer viewport - auto clipper = precomp->statical.pooling(true); - clipper->transform(precomp->cache.matrix); - precomp->scene->clip(cast(clipper)); -} - - -void LottieBuilder::updateSolid(LottieLayer* layer) -{ - auto solidFill = layer->statical.pooling(true); - solidFill->opacity(layer->cache.opacity); - layer->scene->push(cast(solidFill)); -} - - -void LottieBuilder::updateImage(LottieGroup* layer) -{ - auto image = static_cast(layer->children.first()); - layer->scene->push(tvg::cast(image->pooling(true))); -} - - -void LottieBuilder::updateText(LottieLayer* layer, float frameNo) -{ - auto text = static_cast(layer->children.first()); - auto& doc = text->doc(frameNo); - auto p = doc.text; - - if (!p || !text->font) return; - - auto scale = doc.size; - Point cursor = {0.0f, 0.0f}; - auto scene = Scene::gen(); - int line = 0; - int space = 0; - auto lineSpacing = 0.0f; - auto totalLineSpacing = 0.0f; - - //text string - int idx = 0; - auto totalChars = strlen(p); - while (true) { - //TODO: remove nested scenes. - //end of text, new line of the cursor position - if (*p == 13 || *p == 3 || *p == '\0') { - //text layout position - auto ascent = text->font->ascent * scale; - if (ascent > doc.bbox.size.y) ascent = doc.bbox.size.y; - Point layout = {doc.bbox.pos.x, doc.bbox.pos.y + ascent - doc.shift}; - - //adjust the layout - if (doc.justify == 1) layout.x += doc.bbox.size.x - (cursor.x * scale); //right aligned - else if (doc.justify == 2) layout.x += (doc.bbox.size.x * 0.5f) - (cursor.x * 0.5f * scale); //center aligned - - scene->translate(layout.x, layout.y); - scene->scale(scale); - - layer->scene->push(std::move(scene)); - - if (*p == '\0') break; - ++p; - - totalLineSpacing += lineSpacing; - lineSpacing = 0.0f; - - //new text group, single scene for each line - scene = Scene::gen(); - cursor.x = 0.0f; - cursor.y = (++line * doc.height + totalLineSpacing) / scale; - continue; - } - - if (*p == ' ') ++space; - - //find the glyph - bool found = false; - for (auto g = text->font->chars.begin(); g < text->font->chars.end(); ++g) { - auto glyph = *g; - //draw matched glyphs - if (!strncmp(glyph->code, p, glyph->len)) { - auto shape = text->pooling(); - shape->reset(); - for (auto g = glyph->children.begin(); g < glyph->children.end(); ++g) { - auto group = static_cast(*g); - for (auto p = group->children.begin(); p < group->children.end(); ++p) { - if (static_cast(*p)->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, nullptr, nullptr)) { - P(shape)->update(RenderUpdateFlag::Path); - } - } - } - shape->fill(doc.color.rgb[0], doc.color.rgb[1], doc.color.rgb[2]); - shape->translate(cursor.x, cursor.y); - shape->opacity(255); - - if (doc.stroke.render) { - shape->stroke(StrokeJoin::Round); - shape->stroke(doc.stroke.width / scale); - shape->stroke(doc.stroke.color.rgb[0], doc.stroke.color.rgb[1], doc.stroke.color.rgb[2]); - } - - if (!text->ranges.empty()) { - Point scaling = {1.0f, 1.0f}; - auto rotation = 0.0f; - Point translation = {0.0f, 0.0f}; - - //text range process - for (auto s = text->ranges.begin(); s < text->ranges.end(); ++s) { - float start, end; - (*s)->range(frameNo, float(totalChars), start, end); - - auto basedIdx = idx; - if ((*s)->based == LottieTextRange::Based::CharsExcludingSpaces) basedIdx = idx - space; - else if ((*s)->based == LottieTextRange::Based::Words) basedIdx = line + space; - else if ((*s)->based == LottieTextRange::Based::Lines) basedIdx = line; - - if (basedIdx < start || basedIdx >= end) continue; - - translation = translation + (*s)->style.position(frameNo); - auto temp = (*s)->style.scale(frameNo); - scaling.x *= temp.x * 0.01f; - scaling.y *= temp.y * 0.01f; - rotation += (*s)->style.rotation(frameNo); - - shape->opacity((*s)->style.opacity(frameNo)); - - auto color = (*s)->style.fillColor(frameNo); - shape->fill(color.rgb[0], color.rgb[1], color.rgb[2], (*s)->style.fillOpacity(frameNo)); - - if (doc.stroke.render) { - auto strokeColor = (*s)->style.strokeColor(frameNo); - shape->stroke((*s)->style.strokeWidth(frameNo) / scale); - shape->stroke(strokeColor.rgb[0], strokeColor.rgb[1], strokeColor.rgb[2], (*s)->style.strokeOpacity(frameNo)); - } - cursor.x += (*s)->style.letterSpacing(frameNo); - - auto spacing = (*s)->style.lineSpacing(frameNo); - if (spacing > lineSpacing) lineSpacing = spacing; - } - Matrix matrix; - identity(&matrix); - translate(&matrix, translation.x / scale + cursor.x, translation.y / scale + cursor.y); - tvg::scale(&matrix, scaling.x, scaling.y); - rotate(&matrix, rotation); - shape->transform(matrix); - } - - scene->push(cast(shape)); - - p += glyph->len; - idx += glyph->len; - - //advance the cursor position horizontally - cursor.x += glyph->width + doc.tracking; - - found = true; - break; - } - } - - if (!found) { - ++p; - ++idx; - } - } -} - - -void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo) -{ - if (layer->masks.count == 0) return; - - //Apply the base mask - auto pMask = static_cast(layer->masks[0]); - auto pMethod = pMask->method; - auto opacity = pMask->opacity(frameNo); - auto expand = pMask->expand(frameNo); - - auto pShape = layer->pooling(); - pShape->reset(); - pShape->fill(255, 255, 255, opacity); - pShape->transform(layer->cache.matrix); - - //Apply Masking Expansion (Offset) - if (expand == 0.0f) { - pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); - } else { - //TODO: Once path direction support is implemented, ensure that the direction is ignored here - auto offset = LottieOffsetModifier(pMask->expand(frameNo)); - pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, &offset, exps); - } - - auto compMethod = (pMethod == CompositeMethod::SubtractMask || pMethod == CompositeMethod::InvAlphaMask) ? CompositeMethod::InvAlphaMask : CompositeMethod::AlphaMask; - - //Cheaper. Replace the masking with a clipper - if (layer->masks.count == 1 && compMethod == CompositeMethod::AlphaMask && opacity == 255) { - layer->scene->clip(tvg::cast(pShape)); - return; - } - - //Introduce an intermediate scene for embracing the matte + masking - if (layer->matteTarget) { - auto scene = Scene::gen().release(); - scene->push(cast(layer->scene)); - layer->scene = scene; - } - - layer->scene->composite(tvg::cast(pShape), compMethod); - - //Apply the subsquent masks - for (auto m = layer->masks.begin() + 1; m < layer->masks.end(); ++m) { - auto mask = static_cast(*m); - auto method = mask->method; - if (method == CompositeMethod::None) continue; - - //Append the mask shape - if (pMethod == method && (method == CompositeMethod::SubtractMask || method == CompositeMethod::DifferenceMask)) { - mask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); - //Chain composition - } else { - auto shape = layer->pooling(); - shape->reset(); - shape->fill(255, 255, 255, mask->opacity(frameNo)); - shape->transform(layer->cache.matrix); - mask->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps); - pShape->composite(tvg::cast(shape), method); - pShape = shape; - pMethod = method; - } - } -} - - -bool LottieBuilder::updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer) -{ - auto target = layer->matteTarget; - if (!target) return true; - - updateLayer(comp, scene, target, frameNo); - - if (target->scene) { - layer->scene->composite(cast(target->scene), layer->matteType); - } else if (layer->matteType == CompositeMethod::AlphaMask || layer->matteType == CompositeMethod::LumaMask) { - //matte target is not exist. alpha blending definitely bring an invisible result - delete(layer->scene); - layer->scene = nullptr; - return false; - } - return true; -} - - -void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo) -{ - if (layer->effects.count == 0) return; - - for (auto ef = layer->effects.begin(); ef < layer->effects.end(); ++ef) { - if (!(*ef)->enable) continue; - switch ((*ef)->type) { - case LottieEffect::GaussianBlur: { - auto effect = static_cast(*ef); - layer->scene->push(SceneEffect::GaussianBlur, sqrt(effect->blurness(frameNo)), effect->direction(frameNo) - 1, effect->wrap(frameNo), 25); - break; - } - default: break; - } - } -} - - -void LottieBuilder::updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo) -{ - layer->scene = nullptr; - - //visibility - if (frameNo < layer->inFrame || frameNo >= layer->outFrame) return; - - updateTransform(layer, frameNo); - - //full transparent scene. no need to perform - if (layer->type != LottieLayer::Null && layer->cache.opacity == 0) return; - - //Prepare render data - layer->scene = Scene::gen().release(); - layer->scene->id = layer->id; - - //ignore opacity when Null layer? - if (layer->type != LottieLayer::Null) layer->scene->opacity(layer->cache.opacity); - - layer->scene->transform(layer->cache.matrix); - - if (!updateMatte(comp, frameNo, scene, layer)) return; - - switch (layer->type) { - case LottieLayer::Precomp: { - updatePrecomp(comp, layer, frameNo); - break; - } - case LottieLayer::Solid: { - updateSolid(layer); - break; - } - case LottieLayer::Image: { - updateImage(layer); - break; - } - case LottieLayer::Text: { - updateText(layer, frameNo); - break; - } - default: { - if (!layer->children.empty()) { - Inlist contexts; - contexts.back(new RenderContext(layer->pooling())); - updateChildren(layer, frameNo, contexts); - contexts.free(); - } - break; - } - } - - updateMaskings(layer, frameNo); - - layer->scene->blend(layer->blendMethod); - - updateEffect(layer, frameNo); - - //the given matte source was composited by the target earlier. - if (!layer->matteSrc) scene->push(cast(layer->scene)); -} - - -static void _buildReference(LottieComposition* comp, LottieLayer* layer) -{ - for (auto asset = comp->assets.begin(); asset < comp->assets.end(); ++asset) { - if (layer->rid != (*asset)->id) continue; - if (layer->type == LottieLayer::Precomp) { - auto assetLayer = static_cast(*asset); - if (_buildComposition(comp, assetLayer)) { - layer->children = assetLayer->children; - layer->reqFragment = assetLayer->reqFragment; - } - } else if (layer->type == LottieLayer::Image) { - layer->children.push(*asset); - } - break; - } -} - - -static void _buildHierarchy(LottieGroup* parent, LottieLayer* child) -{ - if (child->pidx == -1) return; - - if (child->matteTarget && child->pidx == child->matteTarget->idx) { - child->parent = child->matteTarget; - return; - } - - for (auto p = parent->children.begin(); p < parent->children.end(); ++p) { - auto parent = static_cast(*p); - if (child == parent) continue; - if (child->pidx == parent->idx) { - child->parent = parent; - break; - } - if (parent->matteTarget && parent->matteTarget->idx == child->pidx) { - child->parent = parent->matteTarget; - break; - } - } -} - - -static void _attachFont(LottieComposition* comp, LottieLayer* parent) -{ - //TODO: Consider to migrate this attachment to the frame update time. - for (auto c = parent->children.begin(); c < parent->children.end(); ++c) { - auto text = static_cast(*c); - auto& doc = text->doc(0); - if (!doc.name) continue; - auto len = strlen(doc.name); - for (uint32_t i = 0; i < comp->fonts.count; ++i) { - auto font = comp->fonts[i]; - auto len2 = strlen(font->name); - if (len == len2 && !strcmp(font->name, doc.name)) { - text->font = font; - break; - } - } - } -} - - -static bool _buildComposition(LottieComposition* comp, LottieLayer* parent) -{ - if (parent->children.count == 0) return false; - if (parent->buildDone) return true; - parent->buildDone = true; - - for (auto c = parent->children.begin(); c < parent->children.end(); ++c) { - auto child = static_cast(*c); - - //attach the precomp layer. - if (child->rid) _buildReference(comp, child); - - if (child->matteType != CompositeMethod::None) { - //no index of the matte layer is provided: the layer above is used as the matte source - if (child->mid == -1) { - if (c > parent->children.begin()) { - child->matteTarget = static_cast(*(c - 1)); - } - //matte layer is specified by an index. - } else child->matteTarget = parent->layerByIdx(child->mid); - } - - if (child->matteTarget) { - //parenting - _buildHierarchy(parent, child->matteTarget); - //precomp referencing - if (child->matteTarget->rid) _buildReference(comp, child->matteTarget); - } - _buildHierarchy(parent, child); - - //attach the necessary font data - if (child->type == LottieLayer::Text) _attachFont(comp, child); - } - return true; -} - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -bool LottieBuilder::update(LottieComposition* comp, float frameNo) -{ - if (comp->root->children.empty()) return false; - - frameNo += comp->root->inFrame; - if (frameNo root->inFrame) frameNo = comp->root->inFrame; - if (frameNo >= comp->root->outFrame) frameNo = (comp->root->outFrame - 1); - - //update children layers - auto root = comp->root; - root->scene->clear(); - - if (exps && comp->expressions) exps->update(comp->timeAtFrame(frameNo)); - - for (auto child = root->children.end() - 1; child >= root->children.begin(); --child) { - auto layer = static_cast(*child); - if (!layer->matteSrc) updateLayer(comp, root->scene, layer, frameNo); - } - - return true; -} - - -void LottieBuilder::build(LottieComposition* comp) -{ - if (!comp) return; - - comp->root->scene = Scene::gen().release(); - - _buildComposition(comp, comp->root); - - if (!update(comp, 0)) return; - - //viewport clip - auto clip = Shape::gen(); - clip->appendRect(0, 0, comp->w, comp->h); - comp->root->scene->clip(std::move(clip)); -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.h deleted file mode 100644 index b5b01ae9..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieBuilder.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_BUILDER_H_ -#define _TVG_LOTTIE_BUILDER_H_ - -#include "tvgCommon.h" -#include "tvgInlist.h" -#include "tvgPaint.h" -#include "tvgShape.h" -#include "tvgLottieExpressions.h" -#include "tvgLottieModifier.h" - -struct LottieComposition; - -struct RenderRepeater -{ - int cnt; - Matrix transform; - float offset; - Point position; - Point anchor; - Point scale; - float rotation; - uint8_t startOpacity; - uint8_t endOpacity; - bool interpOpacity; - bool inorder; -}; - -struct RenderContext -{ - INLIST_ITEM(RenderContext); - - Shape* propagator = nullptr; //for propagating the shape properties excluding paths - Shape* merging = nullptr; //merging shapes if possible (if shapes have same properties) - LottieObject** begin = nullptr; //iteration entry point - Array repeaters; - Matrix* transform = nullptr; - LottieRoundnessModifier* roundness = nullptr; - LottieOffsetModifier* offsetPath = nullptr; - bool fragmenting = false; //render context has been fragmented by filling - bool reqFragment = false; //requirement to fragment the render context - - RenderContext(Shape* propagator) - { - P(propagator)->reset(); - PP(propagator)->ref(); - this->propagator = propagator; - } - - ~RenderContext() - { - PP(propagator)->unref(); - free(transform); - delete(roundness); - delete(offsetPath); - } - - RenderContext(const RenderContext& rhs, Shape* propagator, bool mergeable = false) - { - if (mergeable) merging = rhs.merging; - PP(propagator)->ref(); - this->propagator = propagator; - this->repeaters = rhs.repeaters; - if (rhs.roundness) this->roundness = new LottieRoundnessModifier(rhs.roundness->r); - if (rhs.offsetPath) this->offsetPath = new LottieOffsetModifier(rhs.offsetPath->offset, rhs.offsetPath->miterLimit, rhs.offsetPath->join); - } -}; - -struct LottieBuilder -{ - LottieBuilder() - { - exps = LottieExpressions::instance(); - } - - ~LottieBuilder() - { - LottieExpressions::retrieve(exps); - } - - bool update(LottieComposition* comp, float progress); - void build(LottieComposition* comp); - -private: - void updateEffect(LottieLayer* layer, float frameNo); - void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo); - bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer); - void updatePrecomp(LottieComposition* comp, LottieLayer* precomp, float frameNo); - void updateSolid(LottieLayer* layer); - void updateImage(LottieGroup* layer); - void updateText(LottieLayer* layer, float frameNo); - void updateMaskings(LottieLayer* layer, float frameNo); - void updateTransform(LottieLayer* layer, float frameNo); - void updateChildren(LottieGroup* parent, float frameNo, Inlist& contexts); - void updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& pcontexts, RenderContext* ctx); - void updateTransform(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateSolidFill(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateSolidStroke(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateGradientFill(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateGradientStroke(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateRect(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateEllipse(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updatePath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateTrimpath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateRepeater(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateRoundedCorner(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - void updateOffsetPath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); - - LottieExpressions* exps; -}; - -#endif //_TVG_LOTTIE_BUILDER_H diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieCommon.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieCommon.h deleted file mode 100644 index 5cdbdc3e..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieCommon.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_COMMON_ -#define _TVG_LOTTIE_COMMON_ - -#include -#include "tvgCommon.h" -#include "tvgArray.h" - -struct PathSet -{ - Point* pts = nullptr; - PathCommand* cmds = nullptr; - uint16_t ptsCnt = 0; - uint16_t cmdsCnt = 0; -}; - - -struct RGB24 -{ - int32_t rgb[3]; -}; - - -struct ColorStop -{ - Fill::ColorStop* data = nullptr; - Array* input = nullptr; -}; - - -struct TextDocument -{ - char* text = nullptr; - float height; - float shift; - RGB24 color; - struct { - Point pos; - Point size; - } bbox; - struct { - RGB24 color; - float width; - bool render = false; - } stroke; - char* name = nullptr; - float size; - float tracking = 0.0f; - uint8_t justify; -}; - - -static inline int32_t REMAP255(float val) -{ - return (int32_t)nearbyintf(val * 255.0f); -} - - -static inline RGB24 operator-(const RGB24& lhs, const RGB24& rhs) -{ - return {lhs.rgb[0] - rhs.rgb[0], lhs.rgb[1] - rhs.rgb[1], lhs.rgb[2] - rhs.rgb[2]}; -} - - -static inline RGB24 operator+(const RGB24& lhs, const RGB24& rhs) -{ - return {lhs.rgb[0] + rhs.rgb[0], lhs.rgb[1] + rhs.rgb[1], lhs.rgb[2] + rhs.rgb[2]}; -} - - -static inline RGB24 operator*(const RGB24& lhs, float rhs) -{ - return {(int32_t)nearbyintf(lhs.rgb[0] * rhs), (int32_t)nearbyintf(lhs.rgb[1] * rhs), (int32_t)nearbyintf(lhs.rgb[2] * rhs)}; -} - - -#endif //_TVG_LOTTIE_COMMON_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.cpp deleted file mode 100644 index cb752c45..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.cpp +++ /dev/null @@ -1,1423 +0,0 @@ -/* - * Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - -#include "tvgMath.h" -#include "tvgCompressor.h" -#include "tvgLottieModel.h" -#include "tvgLottieExpressions.h" - -#ifdef THORVG_LOTTIE_EXPRESSIONS_SUPPORT - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -struct ExpContent -{ - LottieExpression* exp; - LottieObject* obj; - float frameNo; -}; - -static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt); - -//reserved expressions specifiers -static const char* EXP_NAME = "name"; -static const char* EXP_CONTENT = "content"; -static const char* EXP_WIDTH = "width"; -static const char* EXP_HEIGHT = "height"; -static const char* EXP_CYCLE = "cycle"; -static const char* EXP_PINGPONG = "pingpong"; -static const char* EXP_OFFSET = "offset"; -static const char* EXP_CONTINUE = "continue"; -static const char* EXP_TIME = "time"; -static const char* EXP_VALUE = "value"; -static const char* EXP_INDEX = "index"; -static const char* EXP_EFFECT= "effect"; - -static LottieExpressions* exps = nullptr; //singleton instance engine - - -static ExpContent* _expcontent(LottieExpression* exp, float frameNo, LottieObject* obj) -{ - auto data = (ExpContent*)malloc(sizeof(ExpContent)); - data->exp = exp; - data->frameNo = frameNo; - data->obj = obj; - return data; -} - - -static void contentFree(void *native_p, struct jerry_object_native_info_t *info_p) -{ - free(native_p); -} - -static jerry_object_native_info_t freeCb {contentFree, 0, 0}; -static uint32_t engineRefCnt = 0; //Expressions Engine reference count - - -static char* _name(jerry_value_t args) -{ - auto arg0 = jerry_value_to_string(args); - auto len = jerry_string_length(arg0); - auto name = (jerry_char_t*)malloc(len * sizeof(jerry_char_t) + 1); - jerry_string_to_buffer(arg0, JERRY_ENCODING_UTF8, name, len); - name[len] = '\0'; - jerry_value_free(arg0); - return (char*) name; -} - - -static unsigned long _idByName(jerry_value_t args) -{ - auto name = _name(args); - auto id = djb2Encode(name); - free(name); - return id; -} - - -static jerry_value_t _toComp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - TVGLOG("LOTTIE", "toComp is not supported in expressions!"); - - return jerry_undefined(); -} - - -static jerry_value_t _value(float frameNo, LottieProperty* property) -{ - switch (property->type) { - case LottieProperty::Type::Point: { - auto value = jerry_object(); - auto pos = (*static_cast(property))(frameNo); - auto val1 = jerry_number(pos.x); - auto val2 = jerry_number(pos.y); - jerry_object_set_index(value, 0, val1); - jerry_object_set_index(value, 1, val2); - jerry_value_free(val1); - jerry_value_free(val2); - return value; - } - case LottieProperty::Type::Float: { - return jerry_number((*static_cast(property))(frameNo)); - } - case LottieProperty::Type::Opacity: { - return jerry_number((*static_cast(property))(frameNo)); - } - case LottieProperty::Type::PathSet: { - auto value = jerry_object(); - jerry_object_set_native_ptr(value, nullptr, property); - return value; - } - case LottieProperty::Type::Position: { - auto value = jerry_object(); - auto pos = (*static_cast(property))(frameNo); - auto val1 = jerry_number(pos.x); - auto val2 = jerry_number(pos.y); - jerry_object_set_index(value, 0, val1); - jerry_object_set_index(value, 1, val2); - jerry_value_free(val1); - jerry_value_free(val2); - return value; - } - default: { - TVGERR("LOTTIE", "Non supported type for value? = %d", (int) property->type); - } - } - return jerry_undefined(); -} - - -static void _buildTransform(jerry_value_t context, float frameNo, LottieTransform* transform) -{ - if (!transform) return; - - auto obj = jerry_object(); - jerry_object_set_sz(context, "transform", obj); - - auto anchorPoint = _value(frameNo, &transform->anchor); - jerry_object_set_sz(obj, "anchorPoint", anchorPoint); - jerry_value_free(anchorPoint); - - auto position = _value(frameNo, &transform->position); - jerry_object_set_sz(obj, "position", position); - jerry_value_free(position); - - auto scale = _value(frameNo, &transform->scale); - jerry_object_set_sz(obj, "scale", scale); - jerry_value_free(scale); - - auto rotation = _value(frameNo, &transform->rotation); - jerry_object_set_sz(obj, "rotation", rotation); - jerry_value_free(rotation); - - auto opacity = _value(frameNo, &transform->opacity); - jerry_object_set_sz(obj, "opacity", opacity); - jerry_value_free(opacity); - - jerry_value_free(obj); -} - - -static jerry_value_t _buildGroup(LottieGroup* group, float frameNo) -{ - auto obj = jerry_function_external(_content); - - //attach a transform - for (auto c = group->children.begin(); c < group->children.end(); ++c) { - if ((*c)->type == LottieObject::Type::Transform) { - _buildTransform(obj, frameNo, static_cast(*c)); - break; - } - } - jerry_object_set_native_ptr(obj, &freeCb, _expcontent(nullptr, frameNo, group)); - jerry_object_set_sz(obj, EXP_CONTENT, obj); - return obj; -} - - -static jerry_value_t _buildPolystar(LottiePolyStar* polystar, float frameNo) -{ - auto obj = jerry_object(); - auto position = jerry_object(); - jerry_object_set_native_ptr(position, nullptr, &polystar->position); - jerry_object_set_sz(obj, "position", position); - jerry_value_free(position); - auto innerRadius = jerry_number(polystar->innerRadius(frameNo)); - jerry_object_set_sz(obj, "innerRadius", innerRadius); - jerry_value_free(innerRadius); - auto outerRadius = jerry_number(polystar->outerRadius(frameNo)); - jerry_object_set_sz(obj, "outerRadius", outerRadius); - jerry_value_free(outerRadius); - auto innerRoundness = jerry_number(polystar->innerRoundness(frameNo)); - jerry_object_set_sz(obj, "innerRoundness", innerRoundness); - jerry_value_free(innerRoundness); - auto outerRoundness = jerry_number(polystar->outerRoundness(frameNo)); - jerry_object_set_sz(obj, "outerRoundness", outerRoundness); - jerry_value_free(outerRoundness); - auto rotation = jerry_number(polystar->rotation(frameNo)); - jerry_object_set_sz(obj, "rotation", rotation); - jerry_value_free(rotation); - auto ptsCnt = jerry_number(polystar->ptsCnt(frameNo)); - jerry_object_set_sz(obj, "points", ptsCnt); - jerry_value_free(ptsCnt); - - return obj; -} - - -static jerry_value_t _buildTrimpath(LottieTrimpath* trimpath, float frameNo) -{ - jerry_value_t obj = jerry_object(); - auto start = jerry_number(trimpath->start(frameNo)); - jerry_object_set_sz(obj, "start", start); - jerry_value_free(start); - auto end = jerry_number(trimpath->end(frameNo)); - jerry_object_set_sz(obj, "end", end); - jerry_value_free(end); - auto offset = jerry_number(trimpath->offset(frameNo)); - jerry_object_set_sz(obj, "offset", end); - jerry_value_free(offset); - - return obj; -} - - -static void _buildLayer(jerry_value_t context, float frameNo, LottieLayer* layer, LottieLayer* comp, LottieExpression* exp) -{ - auto width = jerry_number(layer->w); - jerry_object_set_sz(context, EXP_WIDTH, width); - jerry_value_free(width); - - auto height = jerry_number(layer->h); - jerry_object_set_sz(context, EXP_HEIGHT, height); - jerry_value_free(height); - - auto index = jerry_number(layer->idx); - jerry_object_set_sz(context, EXP_INDEX, index); - jerry_value_free(index); - - auto parent = jerry_object(); - jerry_object_set_native_ptr(parent, nullptr, layer->parent); - jerry_object_set_sz(context, "parent", parent); - jerry_value_free(parent); - - auto hasParent = jerry_boolean(layer->parent ? true : false); - jerry_object_set_sz(context, "hasParent", hasParent); - jerry_value_free(hasParent); - - auto inPoint = jerry_number(layer->inFrame); - jerry_object_set_sz(context, "inPoint", inPoint); - jerry_value_free(inPoint); - - auto outPoint = jerry_number(layer->outFrame); - jerry_object_set_sz(context, "outPoint", outPoint); - jerry_value_free(outPoint); - - //TODO: Confirm exp->layer->comp->timeAtFrame() ? - auto startTime = jerry_number(exp->comp->timeAtFrame(layer->startFrame)); - jerry_object_set_sz(context, "startTime", startTime); - jerry_value_free(startTime); - - auto hasVideo = jerry_boolean(false); - jerry_object_set_sz(context, "hasVideo", hasVideo); - jerry_value_free(hasVideo); - - auto hasAudio = jerry_boolean(false); - jerry_object_set_sz(context, "hasAudio", hasAudio); - jerry_value_free(hasAudio); - - //active, #current in the animation range? - - auto enabled = jerry_boolean(!layer->hidden); - jerry_object_set_sz(context, "enabled", enabled); - jerry_value_free(enabled); - - auto audioActive = jerry_boolean(false); - jerry_object_set_sz(context, "audioActive", audioActive); - jerry_value_free(audioActive); - - //sampleImage(point, radius = [.5, .5], postEffect=true, t=time) - - _buildTransform(context, frameNo, layer->transform); - - //audioLevels, #the value of the Audio Levels property of the layer in decibels - - auto timeRemap = jerry_object(); - jerry_object_set_native_ptr(timeRemap, nullptr, &layer->timeRemap); - jerry_object_set_sz(context, "timeRemap", timeRemap); - jerry_value_free(timeRemap); - - //marker.key(index) - //marker.key(name) - //marker.nearestKey(t) - //marker.numKeys - - auto name = jerry_string_sz(layer->name); - jerry_object_set_sz(context, EXP_NAME, name); - jerry_value_free(name); - - auto toComp = jerry_function_external(_toComp); - jerry_object_set_sz(context, "toComp", toComp); - jerry_object_set_native_ptr(toComp, nullptr, comp); - jerry_value_free(toComp); - - //content("name"), #look for the named property from a layer - auto content = jerry_function_external(_content); - jerry_object_set_sz(context, EXP_CONTENT, content); - jerry_object_set_native_ptr(content, &freeCb, _expcontent(exp, frameNo, layer)); - jerry_value_free(content); -} - - -static jerry_value_t _addsub(const jerry_value_t args[], float addsub) -{ - auto n1 = jerry_value_is_number(args[0]); - auto n2 = jerry_value_is_number(args[1]); - - //1d + 1d - if (n1 && n2) return jerry_number(jerry_value_as_number(args[0]) + addsub * jerry_value_as_number(args[1])); - - auto val1 = jerry_object_get_index(args[n1 ? 1 : 0], 0); - auto val2 = jerry_object_get_index(args[n1 ? 1 : 0], 1); - auto x = jerry_value_as_number(val1); - auto y = jerry_value_as_number(val2); - jerry_value_free(val1); - jerry_value_free(val2); - - //2d + 1d - if (n1 || n2) { - auto secondary = n1 ? 0 : 1; - auto val3 = jerry_value_as_number(args[secondary]); - if (secondary == 0) x = (x * addsub) + val3; - else x += (addsub * val3); - //2d + 2d - } else { - auto val3 = jerry_object_get_index(args[1], 0); - auto val4 = jerry_object_get_index(args[1], 1); - x += (addsub * jerry_value_as_number(val3)); - y += (addsub * jerry_value_as_number(val4)); - jerry_value_free(val3); - jerry_value_free(val4); - } - - auto obj = jerry_object(); - val1 = jerry_number(x); - val2 = jerry_number(y); - jerry_object_set_index(obj, 0, val1); - jerry_object_set_index(obj, 1, val2); - jerry_value_free(val1); - jerry_value_free(val2); - - return obj; -} - - -static jerry_value_t _muldiv(const jerry_value_t arg1, float arg2) -{ - //1d - if (jerry_value_is_number(arg1)) return jerry_number(jerry_value_as_number(arg1) * arg2); - - //2d - auto val1 = jerry_object_get_index(arg1, 0); - auto val2 = jerry_object_get_index(arg1, 1); - auto x = jerry_value_as_number(val1) * arg2; - auto y = jerry_value_as_number(val2) * arg2; - - jerry_value_free(val1); - jerry_value_free(val2); - - auto obj = jerry_object(); - val1 = jerry_number(x); - val2 = jerry_number(y); - jerry_object_set_index(obj, 0, val1); - jerry_object_set_index(obj, 1, val2); - jerry_value_free(val1); - jerry_value_free(val2); - - return obj; -} - - -static jerry_value_t _add(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - return _addsub(args, 1.0f); -} - - -static jerry_value_t _sub(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - return _addsub(args, -1.0f); -} - - -static jerry_value_t _mul(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - return _muldiv(args[0], jerry_value_as_number(args[1])); -} - - -static jerry_value_t _div(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - return _muldiv(args[0], 1.0f / jerry_value_as_number(args[1])); -} - - -static jerry_value_t _interp(float t, const jerry_value_t args[], int argsCnt) -{ - auto tMin = 0.0f; - auto tMax = 1.0f; - int idx = 0; - - tMin = jerry_value_as_number(args[1]); - tMax = jerry_value_as_number(args[2]); - idx += 2; - - t = (t - tMin) / (tMax - tMin); - if (t < 0) t = 0.0f; - else if (t > 1) t = 1.0f; - - //2d - if (jerry_value_is_object(args[idx + 1]) && jerry_value_is_object(args[idx + 2])) { - auto val1 = jerry_object_get_index(args[idx + 1], 0); - auto val2 = jerry_object_get_index(args[idx + 1], 1); - auto val3 = jerry_object_get_index(args[idx + 2], 0); - auto val4 = jerry_object_get_index(args[idx + 2], 1); - - Point pt1 = {(float)jerry_value_as_number(val1), (float)jerry_value_as_number(val2)}; - Point pt2 = {(float)jerry_value_as_number(val3), (float)jerry_value_as_number(val4)}; - Point ret; - ret = lerp(pt1, pt2, t); - - jerry_value_free(val1); - jerry_value_free(val2); - jerry_value_free(val3); - jerry_value_free(val4); - - auto obj = jerry_object(); - val1 = jerry_number(ret.x); - val2 = jerry_number(ret.y); - jerry_object_set_index(obj, 0, val1); - jerry_object_set_index(obj, 1, val2); - jerry_value_free(val1); - jerry_value_free(val2); - - return obj; - } - - //1d - auto val1 = (float) jerry_value_as_number(args[idx + 1]); - auto val2 = (float) jerry_value_as_number(args[idx + 2]); - return jerry_number(lerp(val1, val2, t)); -} - - -static jerry_value_t _linear(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto t = (float) jerry_value_as_number(args[0]); - return _interp(t, args, jerry_value_as_uint32(argsCnt)); -} - - -static jerry_value_t _ease(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto t = (float) jerry_value_as_number(args[0]); - t = (t < 0.5) ? (4 * t * t * t) : (1.0f - pow(-2.0f * t + 2.0f, 3) * 0.5f); - return _interp(t, args, jerry_value_as_uint32(argsCnt)); -} - - - -static jerry_value_t _easeIn(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto t = (float) jerry_value_as_number(args[0]); - t = t * t * t; - return _interp(t, args, jerry_value_as_uint32(argsCnt)); -} - - -static jerry_value_t _easeOut(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto t = (float) jerry_value_as_number(args[0]); - t = 1.0f - pow(1.0f - t, 3); - return _interp(t, args, jerry_value_as_uint32(argsCnt)); -} - - -static jerry_value_t _clamp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto num = jerry_value_as_number(args[0]); - auto limit1 = jerry_value_as_number(args[1]); - auto limit2 = jerry_value_as_number(args[2]); - - //clamping - if (num < limit1) num = limit1; - if (num > limit2) num = limit2; - - return jerry_number(num); -} - - -static jerry_value_t _dot(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto val1 = jerry_object_get_index(args[0], 0); - auto val2 = jerry_object_get_index(args[0], 1); - auto val3 = jerry_object_get_index(args[1], 0); - auto val4 = jerry_object_get_index(args[1], 1); - - auto x = jerry_value_as_number(val1) * jerry_value_as_number(val3); - auto y = jerry_value_as_number(val2) * jerry_value_as_number(val4); - - jerry_value_free(val1); - jerry_value_free(val2); - jerry_value_free(val3); - jerry_value_free(val4); - - return jerry_number(x + y); -} - - -static jerry_value_t _cross(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto val1 = jerry_object_get_index(args[0], 0); - auto val2 = jerry_object_get_index(args[0], 1); - auto val3 = jerry_object_get_index(args[1], 0); - auto val4 = jerry_object_get_index(args[1], 1); - - auto x = jerry_value_as_number(val1) * jerry_value_as_number(val4); - auto y = jerry_value_as_number(val2) * jerry_value_as_number(val3); - - jerry_value_free(val1); - jerry_value_free(val2); - jerry_value_free(val3); - jerry_value_free(val4); - - return jerry_number(x - y); -} - - -static jerry_value_t _normalize(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto val1 = jerry_object_get_index(args[0], 0); - auto val2 = jerry_object_get_index(args[0], 1); - auto x = jerry_value_as_number(val1); - auto y = jerry_value_as_number(val2); - - jerry_value_free(val1); - jerry_value_free(val2); - - auto length = sqrtf(x * x + y * y); - - x /= length; - y /= length; - - auto obj = jerry_object(); - val1 = jerry_number(x); - val2 = jerry_number(y); - jerry_object_set_index(obj, 0, val1); - jerry_object_set_index(obj, 0, val2); - jerry_value_free(val1); - jerry_value_free(val2); - - return obj; -} - - -static jerry_value_t _length(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto val1 = jerry_object_get_index(args[0], 0); - auto val2 = jerry_object_get_index(args[0], 1); - auto x = jerry_value_as_number(val1); - auto y = jerry_value_as_number(val2); - - jerry_value_free(val1); - jerry_value_free(val2); - - return jerry_number(sqrtf(x * x + y * y)); -} - - -static jerry_value_t _random(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto val = (float)(rand() % 10000001); - return jerry_number(val * 0.0000001f); -} - - -static jerry_value_t _deg2rad(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - return jerry_number(deg2rad((float)jerry_value_as_number(args[0]))); -} - - -static jerry_value_t _rad2deg(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - return jerry_number(rad2deg((float)jerry_value_as_number(args[0]))); -} - - -static jerry_value_t _effect(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - TVGLOG("LOTTIE", "effect is not supported in expressions!"); - - return jerry_undefined(); -} - - -static jerry_value_t _fromCompToSurface(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - TVGLOG("LOTTIE", "fromCompToSurface is not supported in expressions!"); - - return jerry_undefined(); -} - - -static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto data = static_cast(jerry_object_get_native_ptr(info->function, &freeCb)); - auto group = static_cast(data->obj); - auto target = group->content(_idByName(args[0])); - if (!target) return jerry_undefined(); - - //find the a path property(sh) in the group layer? - switch (target->type) { - case LottieObject::Group: return _buildGroup(static_cast(target), data->frameNo); - case LottieObject::Path: { - jerry_value_t obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, &static_cast(target)->pathset); - jerry_object_set_sz(obj, "path", obj); - return obj; - } - case LottieObject::Polystar: return _buildPolystar(static_cast(target), data->frameNo); - case LottieObject::Trimpath: return _buildTrimpath(static_cast(target), data->frameNo); - default: break; - } - return jerry_undefined(); -} - - -static jerry_value_t _layer(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto data = static_cast(jerry_object_get_native_ptr(info->function, &freeCb)); - auto comp = static_cast(data->obj); - LottieLayer* layer; - - //layer index - if (jerry_value_is_number(args[0])) { - auto idx = (uint16_t)jerry_value_as_int32(args[0]); - layer = comp->layerByIdx(idx); - jerry_value_free(idx); - //layer name - } else { - layer = comp->layerById(_idByName(args[0])); - } - - if (!layer) return jerry_undefined(); - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, layer); - _buildLayer(obj, data->frameNo, layer, comp, data->exp); - - return obj; -} - - -static jerry_value_t _nearestKey(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - auto time = jerry_value_as_number(args[0]); - auto frameNo = exp->comp->frameAtTime(time); - auto index = jerry_number(exp->property->nearest(frameNo)); - - auto obj = jerry_object(); - jerry_object_set_sz(obj, EXP_INDEX, index); - jerry_value_free(index); - - return obj; -} - -static jerry_value_t _property(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto data = static_cast(jerry_object_get_native_ptr(info->function, &freeCb)); - auto property = data->obj->property(jerry_value_as_int32(args[0])); - if (!property) return jerry_undefined(); - return _value(data->frameNo, property); -} - - -static jerry_value_t _propertyGroup(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto data = static_cast(jerry_object_get_native_ptr(info->function, &freeCb)); - auto level = jerry_value_as_int32(args[0]); - - //intermediate group - if (level == 1) { - auto group = jerry_function_external(_property); - jerry_object_set_native_ptr(group, &freeCb, _expcontent(data->exp, data->frameNo, data->obj)); - jerry_object_set_sz(group, "", group); - return group; - } - - TVGLOG("LOTTIE", "propertyGroup(%d)?", level); - - return jerry_undefined(); -} - - -static jerry_value_t _valueAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - auto time = jerry_value_as_number(args[0]); - auto frameNo = exp->comp->frameAtTime(time); - return _value(frameNo, exp->property); -} - - -static jerry_value_t _velocity(float px, float cx, float py, float cy, float elapsed) -{ - float velocity[] = {(cx - px) / elapsed, (cy - py) / elapsed}; - auto obj = jerry_object(); - auto val1 = jerry_number(velocity[0]); - auto val2 = jerry_number(velocity[1]); - jerry_object_set_index(obj, 0, val1); - jerry_object_set_index(obj, 1, val2); - jerry_value_free(val1); - jerry_value_free(val2); - return obj; -} - - -static jerry_value_t _velocityAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - auto time = jerry_value_as_number(args[0]); - auto frameNo = exp->comp->frameAtTime(time); - auto key = exp->property->nearest(frameNo); - auto pframe = exp->property->frameNo(key - 1); - auto cframe = exp->property->frameNo(key); - auto elapsed = (cframe - pframe) / (exp->comp->frameRate); - - //compute the velocity - switch (exp->property->type) { - case LottieProperty::Type::Point: { - auto prv = (*static_cast(exp->property))(pframe); - auto cur = (*static_cast(exp->property))(cframe); - return _velocity(prv.x, cur.x, prv.y, cur.y, elapsed); - } - case LottieProperty::Type::Position: { - auto prv = (*static_cast(exp->property))(pframe); - auto cur = (*static_cast(exp->property))(cframe); - return _velocity(prv.x, cur.x, prv.y, cur.y, elapsed); - } - case LottieProperty::Type::Float: { - auto prv = (*static_cast(exp->property))(pframe); - auto cur = (*static_cast(exp->property))(cframe); - auto velocity = (cur - prv) / elapsed; - return jerry_number(velocity); - } - default: TVGLOG("LOTTIE", "Non supported type for velocityAtTime?"); - } - return jerry_undefined(); -} - - -static jerry_value_t _speedAtTime(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - auto time = jerry_value_as_number(args[0]); - auto frameNo = exp->comp->frameAtTime(time); - auto key = exp->property->nearest(frameNo); - auto pframe = exp->property->frameNo(key - 1); - auto cframe = exp->property->frameNo(key); - auto elapsed = (cframe - pframe) / (exp->comp->frameRate); - - Point cur, prv; - - //compute the velocity - switch (exp->property->type) { - case LottieProperty::Type::Point: { - prv = (*static_cast(exp->property))(pframe); - cur = (*static_cast(exp->property))(cframe); - break; - } - case LottieProperty::Type::Position: { - prv = (*static_cast(exp->property))(pframe); - cur = (*static_cast(exp->property))(cframe); - break; - } - default: { - TVGLOG("LOTTIE", "Non supported type for speedAtTime?"); - return jerry_undefined(); - } - } - - auto speed = sqrtf(pow(cur.x - prv.x, 2) + pow(cur.y - prv.y, 2)) / elapsed; - auto obj = jerry_number(speed); - return obj; -} - - -static bool _loopOutCommon(LottieExpression* exp, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - exp->loop.mode = LottieExpression::LoopMode::OutCycle; - - if (argsCnt > 0) { - auto name = _name(args[0]); - if (!strcmp(name, EXP_CYCLE)) exp->loop.mode = LottieExpression::LoopMode::OutCycle; - else if (!strcmp(name, EXP_PINGPONG)) exp->loop.mode = LottieExpression::LoopMode::OutPingPong; - else if (!strcmp(name, EXP_OFFSET)) exp->loop.mode = LottieExpression::LoopMode::OutOffset; - else if (!strcmp(name, EXP_CONTINUE)) exp->loop.mode = LottieExpression::LoopMode::OutContinue; - free(name); - } - - if (exp->loop.mode != LottieExpression::LoopMode::OutCycle && exp->loop.mode != LottieExpression::LoopMode::OutPingPong) { - TVGLOG("LOTTIE", "Not supported loopOut type = %d", exp->loop.mode); - return false; - } - - return true; -} - - -static jerry_value_t _loopOut(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - - if (!_loopOutCommon(exp, args, argsCnt)) return jerry_undefined(); - - if (argsCnt > 1) exp->loop.key = jerry_value_as_int32(args[1]); - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, exp->property); - return obj; -} - - -static jerry_value_t _loopOutDuration(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - - if (!_loopOutCommon(exp, args, argsCnt)) return jerry_undefined(); - - if (argsCnt > 1) { - exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1])); - } - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, exp->property); - return obj; -} - - -static bool _loopInCommon(LottieExpression* exp, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - exp->loop.mode = LottieExpression::LoopMode::InCycle; - - if (argsCnt > 0) { - auto name = _name(args[0]); - if (!strcmp(name, EXP_CYCLE)) exp->loop.mode = LottieExpression::LoopMode::InCycle; - else if (!strcmp(name, EXP_PINGPONG)) exp->loop.mode = LottieExpression::LoopMode::InPingPong; - else if (!strcmp(name, EXP_OFFSET)) exp->loop.mode = LottieExpression::LoopMode::InOffset; - else if (!strcmp(name, EXP_CONTINUE)) exp->loop.mode = LottieExpression::LoopMode::InContinue; - free(name); - } - - if (exp->loop.mode != LottieExpression::LoopMode::InCycle && exp->loop.mode != LottieExpression::LoopMode::InPingPong) { - TVGLOG("LOTTIE", "Not supported loopIn type = %d", exp->loop.mode); - return false; - } - - return true; -} - -static jerry_value_t _loopIn(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - - if (!_loopInCommon(exp, args, argsCnt)) return jerry_undefined(); - - if (argsCnt > 1) exp->loop.key = jerry_value_as_int32(args[1]); - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, exp->property); - return obj; -} - - -static jerry_value_t _loopInDuration(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - - if (argsCnt > 1) { - exp->loop.in = exp->comp->frameAtTime((float)jerry_value_as_int32(args[1])); - } - - if (!_loopInCommon(exp, args, argsCnt)) return jerry_undefined(); - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, exp->property); - return obj; -} - - -static jerry_value_t _key(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto exp = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - auto key = jerry_value_as_int32(args[0]); - auto frameNo = exp->property->frameNo(key); - auto time = jerry_number(exp->comp->timeAtFrame(frameNo)); - auto value = _value(frameNo, exp->property); - - auto obj = jerry_object(); - jerry_object_set_sz(obj, EXP_TIME, time); - jerry_object_set_sz(obj, EXP_INDEX, args[0]); - jerry_object_set_sz(obj, EXP_VALUE, value); - - //direct access, key[0], key[1] - if (exp->property->type == LottieProperty::Type::Float) { - jerry_object_set_index(obj, 0, value); - } else if (exp->property->type == LottieProperty::Type::Point || exp->property->type == LottieProperty::Type::Position) { - jerry_object_set_index(obj, 0, jerry_object_get_index(value, 0)); - jerry_object_set_index(obj, 1, jerry_object_get_index(value, 1)); - } - - jerry_value_free(time); - jerry_value_free(value); - - return obj; -} - - -static jerry_value_t _createPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - //TODO: arg1: points, arg2: inTangents, arg3: outTangents, arg4: isClosed - auto arg1 = jerry_value_to_object(args[0]); - auto pathset = jerry_object_get_native_ptr(arg1, nullptr); - if (!pathset) { - TVGERR("LOTTIE", "failed createPath()"); - return jerry_undefined(); - } - - jerry_value_free(arg1); - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, pathset); - return obj; -} - - -static jerry_value_t _uniformPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto pathset = static_cast(jerry_object_get_native_ptr(info->function, nullptr)); - - /* TODO: ThorVG prebuilds the path data for performance. - It actually need to constructs the Array for points, inTangents, outTangents and then return here... */ - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, pathset); - return obj; -} - - -static jerry_value_t _isClosed(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - //TODO: Not used - return jerry_boolean(true); -} - - -static void _buildPath(jerry_value_t context, LottieExpression* exp) -{ - //Trick for fast building path. - auto points = jerry_function_external(_uniformPath); - jerry_object_set_native_ptr(points, nullptr, exp->property); - jerry_object_set_sz(context, "points", points); - jerry_value_free(points); - - auto inTangents = jerry_function_external(_uniformPath); - jerry_object_set_native_ptr(inTangents, nullptr, exp->property); - jerry_object_set_sz(context, "inTangents", inTangents); - jerry_value_free(inTangents); - - auto outTangents = jerry_function_external(_uniformPath); - jerry_object_set_native_ptr(outTangents, nullptr, exp->property); - jerry_object_set_sz(context, "outTangents", outTangents); - jerry_value_free(outTangents); - - auto isClosed = jerry_function_external(_isClosed); - jerry_object_set_native_ptr(isClosed, nullptr, exp->property); - jerry_object_set_sz(context, "isClosed", isClosed); - jerry_value_free(isClosed); - -} - - -static void _buildProperty(float frameNo, jerry_value_t context, LottieExpression* exp) -{ - auto value = _value(frameNo, exp->property); - jerry_object_set_sz(context, EXP_VALUE, value); - jerry_value_free(value); - - auto valueAtTime = jerry_function_external(_valueAtTime); - jerry_object_set_sz(context, "valueAtTime", valueAtTime); - jerry_object_set_native_ptr(valueAtTime, nullptr, exp); - jerry_value_free(valueAtTime); - - auto velocity = jerry_number(0.0f); - jerry_object_set_sz(context, "velocity", velocity); - jerry_value_free(velocity); - - auto velocityAtTime = jerry_function_external(_velocityAtTime); - jerry_object_set_sz(context, "velocityAtTime", velocityAtTime); - jerry_object_set_native_ptr(velocityAtTime, nullptr, exp); - jerry_value_free(velocityAtTime); - - auto speed = jerry_number(0.0f); - jerry_object_set_sz(context, "speed", speed); - jerry_value_free(speed); - - auto speedAtTime = jerry_function_external(_speedAtTime); - jerry_object_set_sz(context, "speedAtTime", speedAtTime); - jerry_object_set_native_ptr(speedAtTime, nullptr, exp); - jerry_value_free(speedAtTime); - - //wiggle(freq, amp, octaves=1, amp_mult=.5, t=time) - //temporalWiggle(freq, amp, octaves=1, amp_mult=.5, t=time) - //smooth(width=.2, samples=5, t=time) - - auto loopIn = jerry_function_external(_loopIn); - jerry_object_set_sz(context, "loopIn", loopIn); - jerry_object_set_native_ptr(loopIn, nullptr, exp); - jerry_value_free(loopIn); - - auto loopOut = jerry_function_external(_loopOut); - jerry_object_set_sz(context, "loopOut", loopOut); - jerry_object_set_native_ptr(loopOut, nullptr, exp); - jerry_value_free(loopOut); - - auto loopInDuration = jerry_function_external(_loopInDuration); - jerry_object_set_sz(context, "loopInDuration", loopInDuration); - jerry_object_set_native_ptr(loopInDuration, nullptr, exp); - jerry_value_free(loopInDuration); - - auto loopOutDuration = jerry_function_external(_loopOutDuration); - jerry_object_set_sz(context, "loopOutDuration", loopOutDuration); - jerry_object_set_native_ptr(loopOutDuration, nullptr, exp); - jerry_value_free(loopOutDuration); - - auto key = jerry_function_external(_key); - jerry_object_set_sz(context, "key", key); - jerry_object_set_native_ptr(key, nullptr, exp); - jerry_value_free(key); - - //key(markerName) - - auto nearestKey = jerry_function_external(_nearestKey); - jerry_object_set_native_ptr(nearestKey, nullptr, exp); - jerry_object_set_sz(context, "nearestKey", nearestKey); - jerry_value_free(nearestKey); - - auto numKeys = jerry_number(exp->property->frameCnt()); - jerry_object_set_sz(context, "numKeys", numKeys); - jerry_value_free(numKeys); - - auto propertyGroup = jerry_function_external(_propertyGroup); - jerry_object_set_native_ptr(propertyGroup, &freeCb, _expcontent(exp, frameNo, exp->object)); - jerry_object_set_sz(context, "propertyGroup", propertyGroup); - jerry_value_free(propertyGroup); - - //propertyIndex - - //name - - //content("name"), #look for the named property from a layer - auto content = jerry_function_external(_content); - jerry_object_set_sz(context, EXP_CONTENT, content); - jerry_object_set_native_ptr(content, &freeCb, _expcontent(exp, frameNo, exp->layer)); - jerry_value_free(content); - - //expansions per types - if (exp->property->type == LottieProperty::Type::PathSet) _buildPath(context, exp); -} - - -static jerry_value_t _comp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) -{ - auto data = static_cast(jerry_object_get_native_ptr(info->function, &freeCb)); - auto comp = static_cast(data->obj); - auto layer = comp->layerById(_idByName(args[0])); - - if (!layer) return jerry_undefined(); - - auto obj = jerry_object(); - jerry_object_set_native_ptr(obj, nullptr, layer); - _buildLayer(obj, data->frameNo, layer, comp, data->exp); - - return obj; -} - - -static void _buildMath(jerry_value_t context) -{ - auto bm_mul = jerry_function_external(_mul); - jerry_object_set_sz(context, "$bm_mul", bm_mul); - jerry_value_free(bm_mul); - - auto bm_sum = jerry_function_external(_add); - jerry_object_set_sz(context, "$bm_sum", bm_sum); - jerry_value_free(bm_sum); - - auto bm_add = jerry_function_external(_add); - jerry_object_set_sz(context, "$bm_add", bm_add); - jerry_value_free(bm_add); - - auto bm_sub = jerry_function_external(_sub); - jerry_object_set_sz(context, "$bm_sub", bm_sub); - jerry_value_free(bm_sub); - - auto bm_div = jerry_function_external(_div); - jerry_object_set_sz(context, "$bm_div", bm_div); - jerry_value_free(bm_div); - - auto mul = jerry_function_external(_mul); - jerry_object_set_sz(context, "mul", mul); - jerry_value_free(mul); - - auto sum = jerry_function_external(_add); - jerry_object_set_sz(context, "sum", sum); - jerry_value_free(sum); - - auto add = jerry_function_external(_add); - jerry_object_set_sz(context, "add", add); - jerry_value_free(add); - - auto sub = jerry_function_external(_sub); - jerry_object_set_sz(context, "sub", sub); - jerry_value_free(sub); - - auto div = jerry_function_external(_div); - jerry_object_set_sz(context, "div", div); - jerry_value_free(div); - - auto clamp = jerry_function_external(_clamp); - jerry_object_set_sz(context, "clamp", clamp); - jerry_value_free(clamp); - - auto dot = jerry_function_external(_dot); - jerry_object_set_sz(context, "dot", dot); - jerry_value_free(dot); - - auto cross = jerry_function_external(_cross); - jerry_object_set_sz(context, "cross", cross); - jerry_value_free(cross); - - auto normalize = jerry_function_external(_normalize); - jerry_object_set_sz(context, "normalize", normalize); - jerry_value_free(normalize); - - auto length = jerry_function_external(_length); - jerry_object_set_sz(context, "length", length); - jerry_value_free(length); - - auto random = jerry_function_external(_random); - jerry_object_set_sz(context, "random", random); - jerry_value_free(random); - - auto deg2rad = jerry_function_external(_deg2rad); - jerry_object_set_sz(context, "degreesToRadians", deg2rad); - jerry_value_free(deg2rad); - - auto rad2deg = jerry_function_external(_rad2deg); - jerry_object_set_sz(context, "radiansToDegrees", rad2deg); - jerry_value_free(rad2deg); - - auto linear = jerry_function_external(_linear); - jerry_object_set_sz(context, "linear", linear); - jerry_value_free(linear); - - auto ease = jerry_function_external(_ease); - jerry_object_set_sz(context, "ease", ease); - jerry_value_free(ease); - - auto easeIn = jerry_function_external(_easeIn); - jerry_object_set_sz(context, "easeIn", easeIn); - jerry_value_free(easeIn); - - auto easeOut = jerry_function_external(_easeOut); - jerry_object_set_sz(context, "easeOut", easeOut); - jerry_value_free(easeOut); - - //lookAt -} - - -void LottieExpressions::buildGlobal(LottieExpression* exp) -{ - auto index = jerry_number(exp->layer->idx); - jerry_object_set_sz(global, EXP_INDEX, index); - jerry_value_free(index); -} - - -void LottieExpressions::buildComp(jerry_value_t context, float frameNo, LottieLayer* comp, LottieExpression* exp) -{ - auto data = static_cast(jerry_object_get_native_ptr(context, &freeCb)); - data->exp = exp; - data->frameNo = frameNo; - data->obj = comp; - - //layer(index) / layer(name) / layer(otherLayer, reIndex) - auto layer = jerry_function_external(_layer); - jerry_object_set_sz(context, "layer", layer); - - jerry_object_set_native_ptr(layer, &freeCb, _expcontent(exp, frameNo, comp)); - jerry_value_free(layer); - - auto numLayers = jerry_number(comp->children.count); - jerry_object_set_sz(context, "numLayers", numLayers); - jerry_value_free(numLayers); -} - - -void LottieExpressions::buildComp(LottieComposition* comp, float frameNo, LottieExpression* exp) -{ - buildComp(this->comp, frameNo, comp->root, exp); - - //marker - //marker.key(index) - //marker.key(name) - //marker.nearestKey(t) - //marker.numKeys - - //activeCamera - - auto width = jerry_number(comp->w); - jerry_object_set_sz(thisComp, EXP_WIDTH, width); - jerry_value_free(width); - - auto height = jerry_number(comp->h); - jerry_object_set_sz(thisComp, EXP_HEIGHT, height); - jerry_value_free(height); - - auto duration = jerry_number(comp->duration()); - jerry_object_set_sz(thisComp, "duration", duration); - jerry_value_free(duration); - - //ntscDropFrame - //displayStartTime - - auto frameDuration = jerry_number(1.0f / comp->frameRate); - jerry_object_set_sz(thisComp, "frameDuration", frameDuration); - jerry_value_free(frameDuration); - - //shutterAngle - //shutterPhase - //bgColor - //pixelAspect - - auto name = jerry_string((jerry_char_t*)comp->name, strlen(comp->name), JERRY_ENCODING_UTF8); - jerry_object_set_sz(thisComp, EXP_NAME, name); - jerry_value_free(name); -} - - -jerry_value_t LottieExpressions::buildGlobal() -{ - global = jerry_current_realm(); - - //comp(name) - comp = jerry_function_external(_comp); - jerry_object_set_native_ptr(comp, &freeCb, _expcontent(nullptr, 0.0f, nullptr)); - jerry_object_set_sz(global, "comp", comp); - - //footage(name) - - thisComp = jerry_object(); - jerry_object_set_native_ptr(thisComp, &freeCb, _expcontent(nullptr, 0.0f, nullptr)); - jerry_object_set_sz(global, "thisComp", thisComp); - - thisLayer = jerry_object(); - jerry_object_set_sz(global, "thisLayer", thisLayer); - - thisProperty = jerry_object(); - jerry_object_set_sz(global, "thisProperty", thisProperty); - - auto effect = jerry_function_external(_effect); - jerry_object_set_sz(global, EXP_EFFECT, effect); - jerry_value_free(effect); - - auto fromCompToSurface = jerry_function_external(_fromCompToSurface); - jerry_object_set_sz(global, "fromCompToSurface", fromCompToSurface); - jerry_value_free(fromCompToSurface); - - auto createPath = jerry_function_external(_createPath); - jerry_object_set_sz(global, "createPath", createPath); - jerry_value_free(createPath); - - //posterizeTime(framesPerSecond) - //value - - return global; -} - - -jerry_value_t LottieExpressions::evaluate(float frameNo, LottieExpression* exp) -{ - if (exp->disabled) return jerry_undefined(); - - buildGlobal(exp); - - //main composition - buildComp(exp->comp, frameNo, exp); - - //this composition - buildComp(thisComp, frameNo, exp->layer->comp, exp); - - //update global context values - _buildProperty(frameNo, global, exp); - - //this layer - jerry_object_set_native_ptr(thisLayer, nullptr, exp->layer); - _buildLayer(thisLayer, frameNo, exp->layer, exp->comp->root, exp); - - //this property - jerry_object_set_native_ptr(thisProperty, nullptr, exp->property); - _buildProperty(frameNo, thisProperty, exp); - - //expansions per object type - if (exp->object->type == LottieObject::Transform) _buildTransform(global, frameNo, static_cast(exp->object)); - - //evaluate the code - auto eval = jerry_eval((jerry_char_t *) exp->code, strlen(exp->code), JERRY_PARSE_NO_OPTS); - - if (jerry_value_is_exception(eval) || jerry_value_is_undefined(eval)) { - TVGERR("LOTTIE", "Failed to dispatch the expressions!"); - exp->disabled = true; - return jerry_undefined(); - } - - jerry_value_free(eval); - - return jerry_object_get_sz(global, "$bm_rt"); -} - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -LottieExpressions::~LottieExpressions() -{ - jerry_value_free(thisProperty); - jerry_value_free(thisLayer); - jerry_value_free(thisComp); - jerry_value_free(comp); - jerry_value_free(global); - jerry_cleanup(); -} - - -LottieExpressions::LottieExpressions() -{ - jerry_init(JERRY_INIT_EMPTY); - _buildMath(buildGlobal()); -} - - -void LottieExpressions::update(float curTime) -{ - //time, #current time in seconds - auto time = jerry_number(curTime); - jerry_object_set_sz(global, EXP_TIME, time); - jerry_value_free(time); -} - - -//FIXME: Threads support -#include "tvgTaskScheduler.h" - -LottieExpressions* LottieExpressions::instance() -{ - //FIXME: Threads support - if (TaskScheduler::threads() > 1) { - TVGLOG("LOTTIE", "Lottie Expressions are not supported with tvg threads"); - return nullptr; - } - - if (!exps) exps = new LottieExpressions; - ++engineRefCnt; - return exps; -} - - -void LottieExpressions::retrieve(LottieExpressions* instance) -{ - if (--engineRefCnt == 0) { - delete(instance); - exps = nullptr; - } -} - - -#endif //THORVG_LOTTIE_EXPRESSIONS_SUPPORT diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.h deleted file mode 100644 index 69e3c818..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieExpressions.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_EXPRESSIONS_H_ -#define _TVG_LOTTIE_EXPRESSIONS_H_ - -#include "tvgCommon.h" -#include "tvgLottieCommon.h" - -struct LottieExpression; -struct LottieComposition; -struct LottieLayer; -struct LottieRoundnessModifier; -struct LottieOffsetModifier; - -#ifdef THORVG_LOTTIE_EXPRESSIONS_SUPPORT - -#include "jerryscript.h" - - -struct LottieExpressions -{ -public: - template - bool result(float frameNo, NumType& out, LottieExpression* exp) - { - auto bm_rt = evaluate(frameNo, exp); - if (jerry_value_is_undefined(bm_rt)) return false; - - if (jerry_value_is_number(bm_rt)) { - out = (NumType) jerry_value_as_number(bm_rt); - } else if (auto prop = static_cast(jerry_object_get_native_ptr(bm_rt, nullptr))) { - out = (*prop)(frameNo); - } - jerry_value_free(bm_rt); - return true; - } - - template - bool result(float frameNo, Point& out, LottieExpression* exp) - { - auto bm_rt = evaluate(frameNo, exp); - if (jerry_value_is_undefined(bm_rt)) return false; - - if (auto prop = static_cast(jerry_object_get_native_ptr(bm_rt, nullptr))) { - out = (*prop)(frameNo); - } else { - auto x = jerry_object_get_index(bm_rt, 0); - auto y = jerry_object_get_index(bm_rt, 1); - out.x = jerry_value_as_number(x); - out.y = jerry_value_as_number(y); - jerry_value_free(x); - jerry_value_free(y); - } - jerry_value_free(bm_rt); - return true; - } - - template - bool result(float frameNo, RGB24& out, LottieExpression* exp) - { - auto bm_rt = evaluate(frameNo, exp); - if (jerry_value_is_undefined(bm_rt)) return false; - - if (auto color = static_cast(jerry_object_get_native_ptr(bm_rt, nullptr))) { - out = (*color)(frameNo); - } else { - auto r = jerry_object_get_index(bm_rt, 0); - auto g = jerry_object_get_index(bm_rt, 1); - auto b = jerry_object_get_index(bm_rt, 2); - out.rgb[0] = REMAP255(jerry_value_as_number(r)); - out.rgb[1] = REMAP255(jerry_value_as_number(g)); - out.rgb[2] = REMAP255(jerry_value_as_number(b)); - jerry_value_free(r); - jerry_value_free(g); - jerry_value_free(b); - } - jerry_value_free(bm_rt); - return true; - } - - template - bool result(float frameNo, Fill* fill, LottieExpression* exp) - { - auto bm_rt = evaluate(frameNo, exp); - if (jerry_value_is_undefined(bm_rt)) return false; - - if (auto colorStop = static_cast(jerry_object_get_native_ptr(bm_rt, nullptr))) { - (*colorStop)(frameNo, fill, this); - } - jerry_value_free(bm_rt); - return true; - } - - template - bool result(float frameNo, Array& cmds, Array& pts, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offsetPath, LottieExpression* exp) - { - auto bm_rt = evaluate(frameNo, exp); - if (jerry_value_is_undefined(bm_rt)) return false; - - if (auto pathset = static_cast(jerry_object_get_native_ptr(bm_rt, nullptr))) { - (*pathset)(frameNo, cmds, pts, transform, roundness, offsetPath); - } - jerry_value_free(bm_rt); - return true; - } - - void update(float curTime); - - //singleton (no thread safety) - static LottieExpressions* instance(); - static void retrieve(LottieExpressions* instance); - -private: - LottieExpressions(); - ~LottieExpressions(); - - jerry_value_t evaluate(float frameNo, LottieExpression* exp); - jerry_value_t buildGlobal(); - - void buildComp(LottieComposition* comp, float frameNo, LottieExpression* exp); - void buildComp(jerry_value_t context, float frameNo, LottieLayer* comp, LottieExpression* exp); - void buildGlobal(LottieExpression* exp); - - //global object, attributes, methods - jerry_value_t global; - jerry_value_t comp; - jerry_value_t thisComp; - jerry_value_t thisLayer; - jerry_value_t thisProperty; -}; - -#else - -struct LottieExpressions -{ - template bool result(TVG_UNUSED float, TVG_UNUSED NumType&, TVG_UNUSED LottieExpression*) { return false; } - template bool result(TVG_UNUSED float, TVG_UNUSED Point&, LottieExpression*) { return false; } - template bool result(TVG_UNUSED float, TVG_UNUSED RGB24&, TVG_UNUSED LottieExpression*) { return false; } - template bool result(TVG_UNUSED float, TVG_UNUSED Fill*, TVG_UNUSED LottieExpression*) { return false; } - template bool result(TVG_UNUSED float, TVG_UNUSED Array&, TVG_UNUSED Array&, TVG_UNUSED Matrix* transform, TVG_UNUSED const LottieRoundnessModifier*, TVG_UNUSED const LottieOffsetModifier*, TVG_UNUSED LottieExpression*) { return false; } - void update(TVG_UNUSED float) {} - static LottieExpressions* instance() { return nullptr; } - static void retrieve(TVG_UNUSED LottieExpressions* instance) {} -}; - -#endif //THORVG_LOTTIE_EXPRESSIONS_SUPPORT - -#endif //_TVG_LOTTIE_EXPRESSIONS_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.cpp deleted file mode 100644 index a75105a5..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include "tvgCommon.h" -#include "tvgMath.h" -#include "tvgLottieInterpolator.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -#define NEWTON_MIN_SLOPE 0.02f -#define NEWTON_ITERATIONS 4 -#define SUBDIVISION_PRECISION 0.0000001f -#define SUBDIVISION_MAX_ITERATIONS 10 - - -static inline float _constA(float aA1, float aA2) { return 1.0f - 3.0f * aA2 + 3.0f * aA1; } -static inline float _constB(float aA1, float aA2) { return 3.0f * aA2 - 6.0f * aA1; } -static inline float _constC(float aA1) { return 3.0f * aA1; } - - -static inline float _getSlope(float t, float aA1, float aA2) -{ - return 3.0f * _constA(aA1, aA2) * t * t + 2.0f * _constB(aA1, aA2) * t + _constC(aA1); -} - - -static inline float _calcBezier(float t, float aA1, float aA2) -{ - return ((_constA(aA1, aA2) * t + _constB(aA1, aA2)) * t + _constC(aA1)) * t; -} - - -float LottieInterpolator::getTForX(float aX) -{ - //Find interval where t lies - auto intervalStart = 0.0f; - auto currentSample = &samples[1]; - auto lastSample = &samples[SPLINE_TABLE_SIZE - 1]; - - for (; currentSample != lastSample && *currentSample <= aX; ++currentSample) { - intervalStart += SAMPLE_STEP_SIZE; - } - - --currentSample; // t now lies between *currentSample and *currentSample+1 - - // Interpolate to provide an initial guess for t - auto dist = (aX - *currentSample) / (*(currentSample + 1) - *currentSample); - auto guessForT = intervalStart + dist * SAMPLE_STEP_SIZE; - - // Check the slope to see what strategy to use. If the slope is too small - // Newton-Raphson iteration won't converge on a root so we use bisection - // instead. - auto initialSlope = _getSlope(guessForT, outTangent.x, inTangent.x); - if (initialSlope >= NEWTON_MIN_SLOPE) return NewtonRaphsonIterate(aX, guessForT); - else if (initialSlope == 0.0) return guessForT; - else return binarySubdivide(aX, intervalStart, intervalStart + SAMPLE_STEP_SIZE); -} - - -float LottieInterpolator::binarySubdivide(float aX, float aA, float aB) -{ - float x, t; - int i = 0; - - do { - t = aA + (aB - aA) / 2.0f; - x = _calcBezier(t, outTangent.x, inTangent.x) - aX; - if (x > 0.0f) aB = t; - else aA = t; - } while (fabsf(x) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); - return t; -} - - -float LottieInterpolator::NewtonRaphsonIterate(float aX, float aGuessT) -{ - // Refine guess with Newton-Raphson iteration - for (int i = 0; i < NEWTON_ITERATIONS; ++i) { - // We're trying to find where f(t) = aX, - // so we're actually looking for a root for: CalcBezier(t) - aX - auto currentX = _calcBezier(aGuessT, outTangent.x, inTangent.x) - aX; - auto currentSlope = _getSlope(aGuessT, outTangent.x, inTangent.x); - if (currentSlope == 0.0f) return aGuessT; - aGuessT -= currentX / currentSlope; - } - return aGuessT; -} - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -float LottieInterpolator::progress(float t) -{ - if (outTangent.x == outTangent.y && inTangent.x == inTangent.y) return t; - return _calcBezier(getTForX(t), outTangent.y, inTangent.y); -} - - -void LottieInterpolator::set(const char* key, Point& inTangent, Point& outTangent) -{ - this->key = strdup(key); - this->inTangent = inTangent; - this->outTangent = outTangent; - - if (outTangent.x == outTangent.y && inTangent.x == inTangent.y) return; - - //calculates sample values - for (int i = 0; i < SPLINE_TABLE_SIZE; ++i) { - samples[i] = _calcBezier(float(i) * SAMPLE_STEP_SIZE, outTangent.x, inTangent.x); - } -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.h deleted file mode 100644 index 6d8c7317..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieInterpolator.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_INTERPOLATOR_H_ -#define _TVG_LOTTIE_INTERPOLATOR_H_ - -#define SPLINE_TABLE_SIZE 11 - -struct LottieInterpolator -{ - char* key; - Point outTangent, inTangent; - - float progress(float t); - void set(const char* key, Point& inTangent, Point& outTangent); - -private: - static constexpr float SAMPLE_STEP_SIZE = 1.0f / float(SPLINE_TABLE_SIZE - 1); - float samples[SPLINE_TABLE_SIZE]; - - float getTForX(float aX); - float binarySubdivide(float aX, float aA, float aB); - float NewtonRaphsonIterate(float aX, float aGuessT); -}; - -#endif //_TVG_LOTTIE_INTERPOLATOR_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.cpp deleted file mode 100644 index 2c1426c6..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "tvgLottieLoader.h" -#include "tvgLottieModel.h" -#include "tvgLottieParser.h" -#include "tvgLottieBuilder.h" -#include "tvgStr.h" - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -void LottieLoader::run(unsigned tid) -{ - //update frame - if (comp) { - builder->update(comp, frameNo); - //initial loading - } else { - LottieParser parser(content, dirName); - if (!parser.parse()) return; - { - ScopedLock lock(key); - comp = parser.comp; - } - builder->build(comp); - - release(); - } - rebuild = false; -} - - -void LottieLoader::release() -{ - if (copy) { - free((char*)content); - content = nullptr; - } - free(dirName); - dirName = nullptr; -} - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -LottieLoader::LottieLoader() : FrameModule(FileType::Lottie), builder(new LottieBuilder) -{ - -} - - -LottieLoader::~LottieLoader() -{ - done(); - - release(); - - //TODO: correct position? - delete(comp); - delete(builder); -} - - -bool LottieLoader::header() -{ - //A single thread doesn't need to perform intensive tasks. - if (TaskScheduler::threads() == 0) { - LoadModule::read(); - run(0); - if (comp) { - w = static_cast(comp->w); - h = static_cast(comp->h); - frameDuration = comp->duration(); - frameCnt = comp->frameCnt(); - frameRate = comp->frameRate; - return true; - } else { - return false; - } - } - - //Quickly validate the given Lottie file without parsing in order to get the animation info. - auto startFrame = 0.0f; - auto endFrame = 0.0f; - uint32_t depth = 0; - - auto p = content; - - while (*p != '\0') { - if (*p == '{') { - ++depth; - ++p; - continue; - } - if (*p == '}') { - --depth; - ++p; - continue; - } - if (depth != 1) { - ++p; - continue; - } - //version. - if (!strncmp(p, "\"v\":", 4)) { - p += 4; - continue; - } - - //framerate - if (!strncmp(p, "\"fr\":", 5)) { - p += 5; - auto e = strstr(p, ","); - if (!e) e = strstr(p, "}"); - frameRate = strToFloat(p, nullptr); - p = e; - continue; - } - - //start frame - if (!strncmp(p, "\"ip\":", 5)) { - p += 5; - auto e = strstr(p, ","); - if (!e) e = strstr(p, "}"); - startFrame = strToFloat(p, nullptr); - p = e; - continue; - } - - //end frame - if (!strncmp(p, "\"op\":", 5)) { - p += 5; - auto e = strstr(p, ","); - if (!e) e = strstr(p, "}"); - endFrame = strToFloat(p, nullptr); - p = e; - continue; - } - - //width - if (!strncmp(p, "\"w\":", 4)) { - p += 4; - auto e = strstr(p, ","); - if (!e) e = strstr(p, "}"); - w = strToFloat(p, nullptr); - p = e; - continue; - } - //height - if (!strncmp(p, "\"h\":", 4)) { - p += 4; - auto e = strstr(p, ","); - if (!e) e = strstr(p, "}"); - h = strToFloat(p, nullptr); - p = e; - continue; - } - ++p; - } - - if (frameRate < FLOAT_EPSILON) { - TVGLOG("LOTTIE", "Not a Lottie file? Frame rate is 0!"); - return false; - } - - frameCnt = (endFrame - startFrame); - frameDuration = frameCnt / frameRate; - - TVGLOG("LOTTIE", "info: frame rate = %f, duration = %f size = %f x %f", frameRate, frameDuration, w, h); - - return true; -} - - -bool LottieLoader::open(const char* data, uint32_t size, bool copy) -{ - if (copy) { - content = (char*)malloc(size + 1); - if (!content) return false; - memcpy((char*)content, data, size); - const_cast(content)[size] = '\0'; - } else content = data; - - this->dirName = strdup("."); - - this->size = size; - this->copy = copy; - - return header(); -} - - -bool LottieLoader::open(const string& path) -{ - auto f = fopen(path.c_str(), "r"); - if (!f) return false; - - fseek(f, 0, SEEK_END); - - size = ftell(f); - if (size == 0) { - fclose(f); - return false; - } - - auto content = (char*)(malloc(sizeof(char) * size + 1)); - fseek(f, 0, SEEK_SET); - auto ret = fread(content, sizeof(char), size, f); - if (ret < size) { - fclose(f); - return false; - } - content[size] = '\0'; - - fclose(f); - - this->dirName = strDirname(path.c_str()); - this->content = content; - this->copy = true; - - return header(); -} - - -bool LottieLoader::resize(Paint* paint, float w, float h) -{ - if (!paint) return false; - - auto sx = w / this->w; - auto sy = h / this->h; - Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1}; - paint->transform(m); - - //apply the scale to the base clipper - const Paint* clipper; - paint->composite(&clipper); - if (clipper) const_cast(clipper)->transform(m); - - return true; -} - - -bool LottieLoader::read() -{ - //the loading has been already completed - if (!LoadModule::read()) return true; - - if (!content || size == 0) return false; - - TaskScheduler::request(this); - - return true; -} - - -Paint* LottieLoader::paint() -{ - done(); - - if (!comp) return nullptr; - comp->initiated = true; - return comp->root->scene; -} - - -bool LottieLoader::override(const char* slot) -{ - if (!ready() || comp->slots.count == 0) return false; - - auto success = true; - - //override slots - if (slot) { - //Copy the input data because the JSON parser will encode the data immediately. - auto temp = strdup(slot); - - //parsing slot json - LottieParser parser(temp, dirName); - parser.comp = comp; - - auto idx = 0; - while (auto sid = parser.sid(idx == 0)) { - for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) { - if (strcmp((*s)->sid, sid)) continue; - if (!parser.apply(*s)) success = false; - break; - } - ++idx; - } - - if (idx < 1) success = false; - free(temp); - rebuild = overridden = success; - //reset slots - } else if (overridden) { - for (auto s = comp->slots.begin(); s < comp->slots.end(); ++s) { - (*s)->reset(); - } - overridden = false; - rebuild = true; - } - return success; -} - - -bool LottieLoader::frame(float no) -{ - auto frameNo = no + startFrame(); - - //This ensures that the target frame number is reached. - frameNo *= 10000.0f; - frameNo = nearbyintf(frameNo); - frameNo *= 0.0001f; - - //Skip update if frame diff is too small. - if (fabsf(this->frameNo - frameNo) <= 0.0009f) return false; - - this->done(); - - this->frameNo = frameNo; - - TaskScheduler::request(this); - - return true; -} - - -float LottieLoader::startFrame() -{ - return frameCnt * segmentBegin; -} - - -float LottieLoader::totalFrame() -{ - return (segmentEnd - segmentBegin) * frameCnt; -} - - -float LottieLoader::curFrame() -{ - return frameNo - startFrame(); -} - - -float LottieLoader::duration() -{ - if (segmentBegin == 0.0f && segmentEnd == 1.0f) return frameDuration; - return frameCnt * (segmentEnd - segmentBegin) / frameRate; -} - - -void LottieLoader::sync() -{ - done(); - - if (rebuild) run(0); -} - - -uint32_t LottieLoader::markersCnt() -{ - return ready() ? comp->markers.count : 0; -} - - -const char* LottieLoader::markers(uint32_t index) -{ - if (!ready() || index >= comp->markers.count) return nullptr; - auto marker = comp->markers.begin() + index; - return (*marker)->name; -} - - -bool LottieLoader::segment(const char* marker, float& begin, float& end) -{ - if (!ready() || comp->markers.count == 0) return false; - - for (auto m = comp->markers.begin(); m < comp->markers.end(); ++m) { - if (!strcmp(marker, (*m)->name)) { - begin = (*m)->time / frameCnt; - end = ((*m)->time + (*m)->duration) / frameCnt; - return true; - } - } - return false; -} - - -bool LottieLoader::ready() -{ - { - ScopedLock lock(key); - if (comp) return true; - } - done(); - if (comp) return true; - return false; -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.h deleted file mode 100644 index 4e6b30a1..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieLoader.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_LOADER_H_ -#define _TVG_LOTTIE_LOADER_H_ - -#include "tvgCommon.h" -#include "tvgFrameModule.h" -#include "tvgTaskScheduler.h" - -struct LottieComposition; -struct LottieBuilder; - -class LottieLoader : public FrameModule, public Task -{ -public: - const char* content = nullptr; //lottie file data - uint32_t size = 0; //lottie data size - float frameNo = 0.0f; //current frame number - float frameCnt = 0.0f; - float frameDuration = 0.0f; - float frameRate = 0.0f; - - LottieBuilder* builder; - LottieComposition* comp = nullptr; - - Key key; - char* dirName = nullptr; //base resource directory - bool copy = false; //"content" is owned by this loader - bool overridden = false; //overridden properties with slots - bool rebuild = false; //require building the lottie scene - - LottieLoader(); - ~LottieLoader(); - - bool open(const string& path) override; - bool open(const char* data, uint32_t size, bool copy) override; - bool resize(Paint* paint, float w, float h) override; - bool read() override; - Paint* paint() override; - bool override(const char* slot); - - //Frame Controls - bool frame(float no) override; - float totalFrame() override; - float curFrame() override; - float duration() override; - void sync() override; - - //Marker Supports - uint32_t markersCnt(); - const char* markers(uint32_t index); - bool segment(const char* marker, float& begin, float& end); - -private: - bool ready(); - bool header(); - void clear(); - float startFrame(); - void run(unsigned tid) override; - void release(); -}; - - -#endif //_TVG_LOTTIELOADER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.cpp deleted file mode 100644 index aa302190..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "tvgMath.h" -#include "tvgPaint.h" -#include "tvgFill.h" -#include "tvgTaskScheduler.h" -#include "tvgLottieModel.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -void LottieSlot::reset() -{ - if (!overridden) return; - - for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) { - switch (type) { - case LottieProperty::Type::ColorStop: { - static_cast(pair->obj)->colorStops.release(); - static_cast(pair->obj)->colorStops = *static_cast(pair->prop); - static_cast(pair->prop)->frames = nullptr; - break; - } - case LottieProperty::Type::Color: { - static_cast(pair->obj)->color.release(); - static_cast(pair->obj)->color = *static_cast(pair->prop); - static_cast(pair->prop)->frames = nullptr; - break; - } - case LottieProperty::Type::TextDoc: { - static_cast(pair->obj)->doc.release(); - static_cast(pair->obj)->doc = *static_cast(pair->prop); - static_cast(pair->prop)->frames = nullptr; - break; - } - default: break; - } - delete(pair->prop); - pair->prop = nullptr; - } - overridden = false; -} - - -void LottieSlot::assign(LottieObject* target) -{ - //apply slot object to all targets - for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) { - //backup the original properties before overwriting - switch (type) { - case LottieProperty::Type::ColorStop: { - if (!overridden) { - pair->prop = new LottieColorStop; - *static_cast(pair->prop) = static_cast(pair->obj)->colorStops; - } - - pair->obj->override(&static_cast(target)->colorStops); - break; - } - case LottieProperty::Type::Color: { - if (!overridden) { - pair->prop = new LottieColor; - *static_cast(pair->prop) = static_cast(pair->obj)->color; - } - - pair->obj->override(&static_cast(target)->color); - break; - } - case LottieProperty::Type::TextDoc: { - if (!overridden) { - pair->prop = new LottieTextDoc; - *static_cast(pair->prop) = static_cast(pair->obj)->doc; - } - - pair->obj->override(&static_cast(target)->doc); - break; - } - default: break; - } - } - overridden = true; -} - - -void LottieTextRange::range(float frameNo, float totalLen, float& start, float& end) -{ - auto divisor = (rangeUnit == Unit::Percent) ? (100.0f / totalLen) : 1.0f; - auto offset = this->offset(frameNo) / divisor; - start = nearbyintf(this->start(frameNo) / divisor) + offset; - end = nearbyintf(this->end(frameNo) / divisor) + offset; - - if (start > end) std::swap(start, end); - - if (random == 0) return; - - auto range = end - start; - auto len = (rangeUnit == Unit::Percent) ? 100.0f : totalLen; - start = static_cast(random % int(len - range)); - end = start + range; -} - - -LottieImage::~LottieImage() -{ - free(b64Data); - free(mimeType); -} - - -void LottieImage::prepare() -{ - LottieObject::type = LottieObject::Image; - - auto picture = Picture::gen().release(); - - //force to load a picture on the same thread - TaskScheduler::async(false); - - if (size > 0) picture->load((const char*)b64Data, size, mimeType, false); - else picture->load(path); - - TaskScheduler::async(true); - - picture->size(width, height); - PP(picture)->ref(); - - pooler.push(picture); -} - - -void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpressions* exps) -{ - start = this->start(frameNo, exps) * 0.01f; - tvg::clamp(start, 0.0f, 1.0f); - end = this->end(frameNo, exps) * 0.01f; - tvg::clamp(end, 0.0f, 1.0f); - - auto o = fmodf(this->offset(frameNo, exps), 360.0f) / 360.0f; //0 ~ 1 - - auto diff = fabs(start - end); - if (tvg::zero(diff)) { - start = 0.0f; - end = 0.0f; - return; - } - if (tvg::equal(diff, 1.0f) || tvg::equal(diff, 2.0f)) { - start = 0.0f; - end = 1.0f; - return; - } - - if (start > end) std::swap(start, end); - start += o; - end += o; -} - - -uint32_t LottieGradient::populate(ColorStop& color, size_t count) -{ - if (!color.input) return 0; - - uint32_t alphaCnt = (color.input->count - (count * 4)) / 2; - Array output(count + alphaCnt); - uint32_t cidx = 0; //color count - uint32_t clast = count * 4; - if (clast > color.input->count) clast = color.input->count; - uint32_t aidx = clast; //alpha count - Fill::ColorStop cs; - - //merge color stops. - for (uint32_t i = 0; i < color.input->count; ++i) { - if (cidx == clast || aidx == color.input->count) break; - if ((*color.input)[cidx] == (*color.input)[aidx]) { - cs.offset = (*color.input)[cidx]; - cs.r = (uint8_t)nearbyint((*color.input)[cidx + 1] * 255.0f); - cs.g = (uint8_t)nearbyint((*color.input)[cidx + 2] * 255.0f); - cs.b = (uint8_t)nearbyint((*color.input)[cidx + 3] * 255.0f); - cs.a = (uint8_t)nearbyint((*color.input)[aidx + 1] * 255.0f); - cidx += 4; - aidx += 2; - } else if ((*color.input)[cidx] < (*color.input)[aidx]) { - cs.offset = (*color.input)[cidx]; - cs.r = (uint8_t)nearbyint((*color.input)[cidx + 1] * 255.0f); - cs.g = (uint8_t)nearbyint((*color.input)[cidx + 2] * 255.0f); - cs.b = (uint8_t)nearbyint((*color.input)[cidx + 3] * 255.0f); - //generate alpha value - if (output.count > 0) { - auto p = ((*color.input)[cidx] - output.last().offset) / ((*color.input)[aidx] - output.last().offset); - cs.a = lerp(output.last().a, (uint8_t)nearbyint((*color.input)[aidx + 1] * 255.0f), p); - } else cs.a = (uint8_t)nearbyint((*color.input)[aidx + 1] * 255.0f); - cidx += 4; - } else { - cs.offset = (*color.input)[aidx]; - cs.a = (uint8_t)nearbyint((*color.input)[aidx + 1] * 255.0f); - //generate color value - if (output.count > 0) { - auto p = ((*color.input)[aidx] - output.last().offset) / ((*color.input)[cidx] - output.last().offset); - cs.r = lerp(output.last().r, (uint8_t)nearbyint((*color.input)[cidx + 1] * 255.0f), p); - cs.g = lerp(output.last().g, (uint8_t)nearbyint((*color.input)[cidx + 2] * 255.0f), p); - cs.b = lerp(output.last().b, (uint8_t)nearbyint((*color.input)[cidx + 3] * 255.0f), p); - } else { - cs.r = (uint8_t)nearbyint((*color.input)[cidx + 1] * 255.0f); - cs.g = (uint8_t)nearbyint((*color.input)[cidx + 2] * 255.0f); - cs.b = (uint8_t)nearbyint((*color.input)[cidx + 3] * 255.0f); - } - aidx += 2; - } - output.push(cs); - } - - //color remains - while (cidx + 3 < clast) { - cs.offset = (*color.input)[cidx]; - cs.r = (uint8_t)nearbyint((*color.input)[cidx + 1] * 255.0f); - cs.g = (uint8_t)nearbyint((*color.input)[cidx + 2] * 255.0f); - cs.b = (uint8_t)nearbyint((*color.input)[cidx + 3] * 255.0f); - cs.a = (output.count > 0) ? output.last().a : 255; - output.push(cs); - cidx += 4; - } - - //alpha remains - while (aidx < color.input->count) { - cs.offset = (*color.input)[aidx]; - cs.a = (uint8_t)nearbyint((*color.input)[aidx + 1] * 255.0f); - if (output.count > 0) { - cs.r = output.last().r; - cs.g = output.last().g; - cs.b = output.last().b; - } else cs.r = cs.g = cs.b = 255; - output.push(cs); - aidx += 2; - } - - color.data = output.data; - output.data = nullptr; - - color.input->reset(); - delete(color.input); - - return output.count; -} - - -Fill* LottieGradient::fill(float frameNo, LottieExpressions* exps) -{ - auto opacity = this->opacity(frameNo); - if (opacity == 0) return nullptr; - - Fill* fill = nullptr; - auto s = start(frameNo, exps); - auto e = end(frameNo, exps); - - //Linear Graident - if (id == 1) { - fill = LinearGradient::gen().release(); - static_cast(fill)->linear(s.x, s.y, e.x, e.y); - } - //Radial Gradient - if (id == 2) { - fill = RadialGradient::gen().release(); - - auto w = fabsf(e.x - s.x); - auto h = fabsf(e.y - s.y); - auto r = (w > h) ? (w + 0.375f * h) : (h + 0.375f * w); - auto progress = this->height(frameNo, exps) * 0.01f; - - if (tvg::zero(progress)) { - P(static_cast(fill))->radial(s.x, s.y, r, s.x, s.y, 0.0f); - } else { - if (tvg::equal(progress, 1.0f)) progress = 0.99f; - auto startAngle = rad2deg(tvg::atan2(e.y - s.y, e.x - s.x)); - auto angle = deg2rad((startAngle + this->angle(frameNo, exps))); - auto fx = s.x + cos(angle) * progress * r; - auto fy = s.y + sin(angle) * progress * r; - // Lottie doesn't have any focal radius concept - P(static_cast(fill))->radial(s.x, s.y, r, fx, fy, 0.0f); - } - } - - if (!fill) return nullptr; - - colorStops(frameNo, fill, exps); - - //multiply the current opacity with the fill - if (opacity < 255) { - const Fill::ColorStop* colorStops; - auto cnt = fill->colorStops(&colorStops); - for (uint32_t i = 0; i < cnt; ++i) { - const_cast(&colorStops[i])->a = MULTIPLY(colorStops[i].a, opacity); - } - } - - return fill; -} - - -LottieGroup::LottieGroup() -{ - reqFragment = false; - buildDone = false; - trimpath = false; - visible = false; - allowMerge = true; -} - - -void LottieGroup::prepare(LottieObject::Type type) -{ - LottieObject::type = type; - - if (children.count == 0) return; - - size_t strokeCnt = 0; - size_t fillCnt = 0; - - for (auto c = children.end() - 1; c >= children.begin(); --c) { - auto child = static_cast(*c); - - if (child->type == LottieObject::Type::Trimpath) trimpath = true; - - /* Figure out if this group is a simple path drawing. - In that case, the rendering context can be sharable with the parent's. */ - if (allowMerge && (child->type == LottieObject::Group || !child->mergeable())) allowMerge = false; - - //Figure out this group has visible contents - switch (child->type) { - case LottieObject::Group: { - visible |= static_cast(child)->visible; - break; - } - case LottieObject::Rect: - case LottieObject::Ellipse: - case LottieObject::Path: - case LottieObject::Polystar: - case LottieObject::Image: - case LottieObject::Text: { - visible = true; - break; - } - default: break; - } - - if (reqFragment) continue; - - /* Figure out if the rendering context should be fragmented. - Multiple stroking or grouping with a stroking would occur this. - This fragment resolves the overlapped stroke outlines. */ - if (child->type == LottieObject::Group && !child->mergeable()) { - if (strokeCnt > 0 || fillCnt > 0) reqFragment = true; - } else if (child->type == LottieObject::SolidStroke || child->type == LottieObject::GradientStroke) { - if (strokeCnt > 0) reqFragment = true; - else ++strokeCnt; - } else if (child->type == LottieObject::SolidFill || child->type == LottieObject::GradientFill) { - if (fillCnt > 0) reqFragment = true; - else ++fillCnt; - } - } - - //Reverse the drawing order if this group has a trimpath. - if (!trimpath) return; - - for (uint32_t i = 0; i < children.count - 1; ) { - auto child2 = children[i + 1]; - if (!child2->mergeable() || child2->type == LottieObject::Transform) { - i += 2; - continue; - } - auto child = children[i]; - if (!child->mergeable() || child->type == LottieObject::Transform) { - i++; - continue; - } - children[i] = child2; - children[i + 1] = child; - i++; - } -} - - -LottieLayer::~LottieLayer() -{ - //No need to free assets children because the Composition owns them. - if (rid) children.clear(); - - for (auto m = masks.begin(); m < masks.end(); ++m) { - delete(*m); - } - - for (auto e = effects.begin(); e < effects.end(); ++e) { - delete(*e); - } - - delete(transform); - free(name); -} - - -void LottieLayer::prepare(RGB24* color) -{ - /* if layer is hidden, only useful data is its transform matrix. - so force it to be a Null Layer and release all resource. */ - if (hidden) { - type = LottieLayer::Null; - for (auto p = children.begin(); p < children.end(); ++p) delete(*p); - children.reset(); - return; - } - - //prepare the viewport clipper - if (type == LottieLayer::Precomp) { - auto clipper = Shape::gen().release(); - clipper->appendRect(0.0f, 0.0f, w, h); - PP(clipper)->ref(); - statical.pooler.push(clipper); - //prepare solid fill in advance if it is a layer type. - } else if (color && type == LottieLayer::Solid) { - auto solidFill = Shape::gen().release(); - solidFill->appendRect(0, 0, static_cast(w), static_cast(h)); - solidFill->fill(color->rgb[0], color->rgb[1], color->rgb[2]); - PP(solidFill)->ref(); - statical.pooler.push(solidFill); - } - - LottieGroup::prepare(LottieObject::Layer); -} - - -float LottieLayer::remap(LottieComposition* comp, float frameNo, LottieExpressions* exp) -{ - if (timeRemap.frames || timeRemap.value) { - frameNo = comp->frameAtTime(timeRemap(frameNo, exp)); - } else { - frameNo -= startFrame; - } - return (frameNo / timeStretch); -} - - -LottieComposition::~LottieComposition() -{ - if (!initiated && root) delete(root->scene); - - delete(root); - free(version); - free(name); - - //delete interpolators - for (auto i = interpolators.begin(); i < interpolators.end(); ++i) { - free((*i)->key); - free(*i); - } - - //delete assets - for (auto a = assets.begin(); a < assets.end(); ++a) { - delete(*a); - } - - //delete fonts - for (auto f = fonts.begin(); f < fonts.end(); ++f) { - delete(*f); - } - - //delete slots - for (auto s = slots.begin(); s < slots.end(); ++s) { - delete(*s); - } - - for (auto m = markers.begin(); m < markers.end(); ++m) { - delete(*m); - } -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.h deleted file mode 100644 index 91106012..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModel.h +++ /dev/null @@ -1,899 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_MODEL_H_ -#define _TVG_LOTTIE_MODEL_H_ - -#include - -#include "tvgCommon.h" -#include "tvgRender.h" -#include "tvgLottieProperty.h" -#include "tvgLottieRenderPooler.h" - - -struct LottieComposition; - -struct LottieStroke -{ - struct DashAttr - { - //0: offset, 1: dash, 2: gap - LottieFloat value[3] = {0.0f, 0.0f, 0.0f}; - }; - - virtual ~LottieStroke() - { - delete(dashattr); - } - - LottieFloat& dash(int no) - { - if (!dashattr) dashattr = new DashAttr; - return dashattr->value[no]; - } - - float dashOffset(float frameNo, LottieExpressions* exps) - { - return dash(0)(frameNo, exps); - } - - float dashGap(float frameNo, LottieExpressions* exps) - { - return dash(2)(frameNo, exps); - } - - float dashSize(float frameNo, LottieExpressions* exps) - { - auto d = dash(1)(frameNo, exps); - if (d == 0.0f) return 0.1f; - else return d; - } - - LottieFloat width = 0.0f; - DashAttr* dashattr = nullptr; - float miterLimit = 0; - StrokeCap cap = StrokeCap::Round; - StrokeJoin join = StrokeJoin::Round; -}; - - -struct LottieEffect -{ - enum Type : uint8_t - { - GaussianBlur = 0, - }; - - virtual ~LottieEffect() {} - - Type type; - bool enable = false; -}; - - -struct LottieGaussianBlur : LottieEffect -{ - LottieSlider blurness = 0.0f; - LottieCheckbox direction = 0; - LottieCheckbox wrap = 0; - - LottieGaussianBlur() - { - type = GaussianBlur; - } -}; - - -struct LottieMask -{ - LottiePathSet pathset; - LottieFloat expand = 0.0f; - LottieOpacity opacity = 255; - CompositeMethod method; - bool inverse = false; -}; - - -struct LottieObject -{ - enum Type : uint8_t - { - Composition = 0, - Layer, - Group, - Transform, - SolidFill, - SolidStroke, - GradientFill, - GradientStroke, - Rect, - Ellipse, - Path, - Polystar, - Image, - Trimpath, - Text, - Repeater, - RoundedCorner, - OffsetPath - }; - - virtual ~LottieObject() - { - } - - virtual void override(LottieProperty* prop) - { - TVGERR("LOTTIE", "Unsupported slot type"); - } - - virtual bool mergeable() { return false; } - virtual LottieProperty* property(uint16_t ix) { return nullptr; } - - unsigned long id = 0; - Type type; - bool hidden = false; //remove? -}; - - -struct LottieGlyph -{ - Array children; //glyph shapes. - float width; - char* code; - char* family = nullptr; - char* style = nullptr; - uint16_t size; - uint8_t len; - - void prepare() - { - len = strlen(code); - } - - ~LottieGlyph() - { - for (auto p = children.begin(); p < children.end(); ++p) delete(*p); - free(code); - } -}; - - -struct LottieTextStyle -{ - LottieColor fillColor = RGB24{255, 255, 255}; - LottieColor strokeColor = RGB24{255, 255, 255}; - LottiePosition position = Point{0, 0}; - LottiePoint scale = Point{100, 100}; - LottieFloat letterSpacing = 0.0f; - LottieFloat lineSpacing = 0.0f; - LottieFloat strokeWidth = 0.0f; - LottieFloat rotation = 0.0f; - LottieOpacity fillOpacity = 255; - LottieOpacity strokeOpacity = 255; - LottieOpacity opacity = 255; -}; - - -struct LottieTextRange -{ - enum Based : uint8_t { Chars = 1, CharsExcludingSpaces, Words, Lines }; - enum Shape : uint8_t { Square = 1, RampUp, RampDown, Triangle, Round, Smooth }; - enum Unit : uint8_t { Percent = 1, Index }; - - LottieTextStyle style; - LottieFloat offset = 0.0f; - LottieFloat maxEase = 0.0f; - LottieFloat minEase = 0.0f; - LottieFloat maxAmount = 0.0f; - LottieFloat smoothness = 0.0f; - LottieFloat start = 0.0f; - LottieFloat end = FLT_MAX; - Based based = Chars; - Shape shape = Square; - Unit rangeUnit = Percent; - uint8_t random = 0; - bool expressible = false; - - void range(float frameNo, float totalLen, float& start, float& end); -}; - - -struct LottieFont -{ - enum Origin : uint8_t { Local = 0, CssURL, ScriptURL, FontURL, Embedded }; - - ~LottieFont() - { - for (auto c = chars.begin(); c < chars.end(); ++c) delete(*c); - free(style); - free(family); - free(name); - } - - Array chars; - char* name = nullptr; - char* family = nullptr; - char* style = nullptr; - float ascent = 0.0f; - Origin origin = Embedded; -}; - -struct LottieMarker -{ - char* name = nullptr; - float time = 0.0f; - float duration = 0.0f; - - ~LottieMarker() - { - free(name); - } -}; - -struct LottieText : LottieObject, LottieRenderPooler -{ - void prepare() - { - LottieObject::type = LottieObject::Text; - } - - void override(LottieProperty* prop) override - { - this->doc = *static_cast(prop); - this->prepare(); - } - - LottieProperty* property(uint16_t ix) override - { - if (doc.ix == ix) return &doc; - return nullptr; - } - - LottieTextDoc doc; - LottieFont* font; - Array ranges; - - ~LottieText() - { - for (auto r = ranges.begin(); r < ranges.end(); ++r) delete(*r); - } -}; - - -struct LottieTrimpath : LottieObject -{ - enum Type : uint8_t { Simultaneous = 1, Individual = 2 }; - - void prepare() - { - LottieObject::type = LottieObject::Trimpath; - } - - bool mergeable() override - { - if (!start.frames && start.value == 0.0f && !end.frames && end.value == 100.0f && !offset.frames && offset.value == 0.0f) return true; - return false; - } - - LottieProperty* property(uint16_t ix) override - { - if (start.ix == ix) return &start; - if (end.ix == ix) return &end; - if (offset.ix == ix) return &offset; - return nullptr; - } - - void segment(float frameNo, float& start, float& end, LottieExpressions* exps); - - LottieFloat start = 0.0f; - LottieFloat end = 100.0f; - LottieFloat offset = 0.0f; - Type type = Simultaneous; -}; - - -struct LottieShape : LottieObject, LottieRenderPooler -{ - bool clockwise = true; //clockwise or counter-clockwise - - virtual ~LottieShape() {} - - bool mergeable() override - { - return true; - } - - void prepare(LottieObject::Type type) - { - LottieObject::type = type; - } -}; - - -struct LottieRoundedCorner : LottieObject -{ - void prepare() - { - LottieObject::type = LottieObject::RoundedCorner; - } - - LottieProperty* property(uint16_t ix) override - { - if (radius.ix == ix) return &radius; - return nullptr; - } - - LottieFloat radius = 0.0f; -}; - - -struct LottiePath : LottieShape -{ - void prepare() - { - LottieShape::prepare(LottieObject::Path); - } - - LottieProperty* property(uint16_t ix) override - { - if (pathset.ix == ix) return &pathset; - return nullptr; - } - - LottiePathSet pathset; -}; - - -struct LottieRect : LottieShape -{ - void prepare() - { - LottieShape::prepare(LottieObject::Rect); - } - - LottieProperty* property(uint16_t ix) override - { - if (position.ix == ix) return &position; - if (size.ix == ix) return &size; - if (radius.ix == ix) return &radius; - return nullptr; - } - - LottiePosition position = Point{0.0f, 0.0f}; - LottiePoint size = Point{0.0f, 0.0f}; - LottieFloat radius = 0.0f; //rounded corner radius -}; - - -struct LottiePolyStar : LottieShape -{ - enum Type : uint8_t {Star = 1, Polygon}; - - void prepare() - { - LottieShape::prepare(LottieObject::Polystar); - } - - LottieProperty* property(uint16_t ix) override - { - if (position.ix == ix) return &position; - if (innerRadius.ix == ix) return &innerRadius; - if (outerRadius.ix == ix) return &outerRadius; - if (innerRoundness.ix == ix) return &innerRoundness; - if (outerRoundness.ix == ix) return &outerRoundness; - if (rotation.ix == ix) return &rotation; - if (ptsCnt.ix == ix) return &ptsCnt; - return nullptr; - } - - LottiePosition position = Point{0.0f, 0.0f}; - LottieFloat innerRadius = 0.0f; - LottieFloat outerRadius = 0.0f; - LottieFloat innerRoundness = 0.0f; - LottieFloat outerRoundness = 0.0f; - LottieFloat rotation = 0.0f; - LottieFloat ptsCnt = 0.0f; - Type type = Polygon; -}; - - -struct LottieEllipse : LottieShape -{ - void prepare() - { - LottieShape::prepare(LottieObject::Ellipse); - } - - LottieProperty* property(uint16_t ix) override - { - if (position.ix == ix) return &position; - if (size.ix == ix) return &size; - return nullptr; - } - - LottiePosition position = Point{0.0f, 0.0f}; - LottiePoint size = Point{0.0f, 0.0f}; -}; - - -struct LottieTransform : LottieObject -{ - struct SeparateCoord - { - LottieFloat x = 0.0f; - LottieFloat y = 0.0f; - }; - - struct RotationEx - { - LottieFloat x = 0.0f; - LottieFloat y = 0.0f; - }; - - ~LottieTransform() - { - delete(coords); - delete(rotationEx); - } - - void prepare() - { - LottieObject::type = LottieObject::Transform; - } - - bool mergeable() override - { - if (!opacity.frames && opacity.value == 255) return true; - return false; - } - - LottieProperty* property(uint16_t ix) override - { - if (position.ix == ix) return &position; - if (rotation.ix == ix) return &rotation; - if (scale.ix == ix) return &scale; - if (anchor.ix == ix) return &anchor; - if (opacity.ix == ix) return &opacity; - if (skewAngle.ix == ix) return &skewAngle; - if (skewAxis.ix == ix) return &skewAxis; - if (coords) { - if (coords->x.ix == ix) return &coords->x; - if (coords->y.ix == ix) return &coords->y; - } - return nullptr; - } - - LottiePosition position = Point{0.0f, 0.0f}; - LottieFloat rotation = 0.0f; //z rotation - LottiePoint scale = Point{100.0f, 100.0f}; - LottiePoint anchor = Point{0.0f, 0.0f}; - LottieOpacity opacity = 255; - LottieFloat skewAngle = 0.0f; - LottieFloat skewAxis = 0.0f; - - SeparateCoord* coords = nullptr; //either a position or separate coordinates - RotationEx* rotationEx = nullptr; //extension for 3d rotation -}; - - -struct LottieSolid : LottieObject -{ - LottieColor color = RGB24{255, 255, 255}; - LottieOpacity opacity = 255; - - LottieProperty* property(uint16_t ix) override - { - if (color.ix == ix) return &color; - if (opacity.ix == ix) return &opacity; - return nullptr; - } -}; - - -struct LottieSolidStroke : LottieSolid, LottieStroke -{ - void prepare() - { - LottieObject::type = LottieObject::SolidStroke; - } - - LottieProperty* property(uint16_t ix) override - { - if (width.ix == ix) return &width; - if (dashattr) { - if (dashattr->value[0].ix == ix) return &dashattr->value[0]; - if (dashattr->value[1].ix == ix) return &dashattr->value[1]; - if (dashattr->value[2].ix == ix) return &dashattr->value[2]; - } - return LottieSolid::property(ix); - } - - void override(LottieProperty* prop) override - { - this->color = *static_cast(prop); - this->prepare(); - } -}; - - -struct LottieSolidFill : LottieSolid -{ - void prepare() - { - LottieObject::type = LottieObject::SolidFill; - } - - void override(LottieProperty* prop) override - { - this->color = *static_cast(prop); - this->prepare(); - } - - FillRule rule = FillRule::Winding; -}; - - -struct LottieGradient : LottieObject -{ - bool prepare() - { - if (!colorStops.populated) { - auto count = colorStops.count; //colorstop count can be modified after population - if (colorStops.frames) { - for (auto v = colorStops.frames->begin(); v < colorStops.frames->end(); ++v) { - colorStops.count = populate(v->value, count); - } - } else { - colorStops.count = populate(colorStops.value, count); - } - colorStops.populated = true; - } - if (start.frames || end.frames || height.frames || angle.frames || opacity.frames || colorStops.frames) return true; - return false; - } - - LottieProperty* property(uint16_t ix) override - { - if (start.ix == ix) return &start; - if (end.ix == ix) return &end; - if (height.ix == ix) return &height; - if (angle.ix == ix) return ∠ - if (opacity.ix == ix) return &opacity; - if (colorStops.ix == ix) return &colorStops; - return nullptr; - } - - - uint32_t populate(ColorStop& color, size_t count); - Fill* fill(float frameNo, LottieExpressions* exps); - - LottiePoint start = Point{0.0f, 0.0f}; - LottiePoint end = Point{0.0f, 0.0f}; - LottieFloat height = 0.0f; - LottieFloat angle = 0.0f; - LottieOpacity opacity = 255; - LottieColorStop colorStops; - uint8_t id = 0; //1: linear, 2: radial -}; - - -struct LottieGradientFill : LottieGradient -{ - void prepare() - { - LottieObject::type = LottieObject::GradientFill; - LottieGradient::prepare(); - } - - void override(LottieProperty* prop) override - { - this->colorStops = *static_cast(prop); - this->prepare(); - } - - FillRule rule = FillRule::Winding; -}; - - -struct LottieGradientStroke : LottieGradient, LottieStroke -{ - void prepare() - { - LottieObject::type = LottieObject::GradientStroke; - LottieGradient::prepare(); - } - - LottieProperty* property(uint16_t ix) override - { - if (width.ix == ix) return &width; - if (dashattr) { - if (dashattr->value[0].ix == ix) return &dashattr->value[0]; - if (dashattr->value[1].ix == ix) return &dashattr->value[1]; - if (dashattr->value[2].ix == ix) return &dashattr->value[2]; - } - return LottieGradient::property(ix); - } - - void override(LottieProperty* prop) override - { - this->colorStops = *static_cast(prop); - this->prepare(); - } -}; - - -struct LottieImage : LottieObject, LottieRenderPooler -{ - union { - char* b64Data = nullptr; - char* path; - }; - char* mimeType = nullptr; - uint32_t size = 0; - float width = 0.0f; - float height = 0.0f; - - ~LottieImage(); - void prepare(); -}; - - -struct LottieRepeater : LottieObject -{ - void prepare() - { - LottieObject::type = LottieObject::Repeater; - } - - LottieProperty* property(uint16_t ix) override - { - if (copies.ix == ix) return &copies; - if (offset.ix == ix) return &offset; - if (position.ix == ix) return &position; - if (rotation.ix == ix) return &rotation; - if (scale.ix == ix) return &scale; - if (anchor.ix == ix) return &anchor; - if (startOpacity.ix == ix) return &startOpacity; - if (endOpacity.ix == ix) return &endOpacity; - return nullptr; - } - - LottieFloat copies = 0.0f; - LottieFloat offset = 0.0f; - - //Transform - LottiePosition position = Point{0.0f, 0.0f}; - LottieFloat rotation = 0.0f; - LottiePoint scale = Point{100.0f, 100.0f}; - LottiePoint anchor = Point{0.0f, 0.0f}; - LottieOpacity startOpacity = 255; - LottieOpacity endOpacity = 255; - bool inorder = true; //true: higher, false: lower -}; - - -struct LottieOffsetPath : LottieObject -{ - void prepare() - { - LottieObject::type = LottieObject::OffsetPath; - } - - LottieFloat offset = 0.0f; - LottieFloat miterLimit = 4.0f; - StrokeJoin join = StrokeJoin::Miter; -}; - - -struct LottieGroup : LottieObject, LottieRenderPooler -{ - LottieGroup(); - - virtual ~LottieGroup() - { - for (auto p = children.begin(); p < children.end(); ++p) delete(*p); - } - - void prepare(LottieObject::Type type = LottieObject::Group); - bool mergeable() override { return allowMerge; } - - LottieObject* content(unsigned long id) - { - if (this->id == id) return this; - - //source has children, find recursively. - for (auto c = children.begin(); c < children.end(); ++c) { - auto child = *c; - if (child->type == LottieObject::Type::Group || child->type == LottieObject::Type::Layer) { - if (auto ret = static_cast(child)->content(id)) return ret; - } else if (child->id == id) return child; - } - return nullptr; - } - - Scene* scene = nullptr; - Array children; - - bool reqFragment : 1; //requirement to fragment the render context - bool buildDone : 1; //completed in building the composition. - bool trimpath : 1; //this group has a trimpath. - bool visible : 1; //this group has visible contents. - bool allowMerge : 1; //if this group is consisted of simple (transformed) shapes. -}; - - -struct LottieLayer : LottieGroup -{ - enum Type : uint8_t {Precomp = 0, Solid, Image, Null, Shape, Text}; - - ~LottieLayer(); - - uint8_t opacity(float frameNo) - { - //return zero if the visibility is false. - if (type == Null) return 255; - return transform->opacity(frameNo); - } - - bool mergeable() override { return false; } - - void prepare(RGB24* color = nullptr); - float remap(LottieComposition* comp, float frameNo, LottieExpressions* exp); - - char* name = nullptr; - LottieLayer* parent = nullptr; - LottieFloat timeRemap = 0.0f; - LottieLayer* comp = nullptr; //Precompositor, current layer is belonges. - LottieTransform* transform = nullptr; - Array masks; - Array effects; - LottieLayer* matteTarget = nullptr; - - LottieRenderPooler statical; //static pooler for solid fill and clipper - - float timeStretch = 1.0f; - float w = 0.0f, h = 0.0f; - float inFrame = 0.0f; - float outFrame = 0.0f; - float startFrame = 0.0f; - unsigned long rid = 0; //pre-composition reference id. - int16_t mid = -1; //id of the matte layer. - int16_t pidx = -1; //index of the parent layer. - int16_t idx = -1; //index of the current layer. - - struct { - float frameNo = -1.0f; - Matrix matrix; - uint8_t opacity; - } cache; - - CompositeMethod matteType = CompositeMethod::None; - BlendMethod blendMethod = BlendMethod::Normal; - Type type = Null; - bool autoOrient = false; - bool matteSrc = false; - - LottieLayer* layerById(unsigned long id) - { - for (auto child = children.begin(); child < children.end(); ++child) { - if ((*child)->type != LottieObject::Type::Layer) continue; - auto layer = static_cast(*child); - if (layer->id == id) return layer; - } - return nullptr; - } - - LottieLayer* layerByIdx(int16_t idx) - { - for (auto child = children.begin(); child < children.end(); ++child) { - if ((*child)->type != LottieObject::Type::Layer) continue; - auto layer = static_cast(*child); - if (layer->idx == idx) return layer; - } - return nullptr; - } -}; - - -struct LottieSlot -{ - struct Pair { - LottieObject* obj; - LottieProperty* prop; - }; - - void assign(LottieObject* target); - void reset(); - - LottieSlot(char* sid, LottieObject* obj, LottieProperty::Type type) : sid(sid), type(type) - { - pairs.push({obj}); - } - - ~LottieSlot() - { - free(sid); - if (!overridden) return; - for (auto pair = pairs.begin(); pair < pairs.end(); ++pair) { - delete(pair->prop); - } - } - - char* sid; - Array pairs; - LottieProperty::Type type; - bool overridden = false; -}; - - -struct LottieComposition -{ - ~LottieComposition(); - - float duration() const - { - return frameCnt() / frameRate; // in second - } - - float frameAtTime(float timeInSec) const - { - auto p = timeInSec / duration(); - if (p < 0.0f) p = 0.0f; - return p * frameCnt(); - } - - float timeAtFrame(float frameNo) - { - return (frameNo - root->inFrame) / frameRate; - } - - float frameCnt() const - { - return root->outFrame - root->inFrame; - } - - LottieLayer* asset(unsigned long id) - { - for (auto asset = assets.begin(); asset < assets.end(); ++asset) { - auto layer = static_cast(*asset); - if (layer->id == id) return layer; - } - return nullptr; - } - - LottieLayer* root = nullptr; - char* version = nullptr; - char* name = nullptr; - float w, h; - float frameRate; - Array assets; - Array interpolators; - Array fonts; - Array slots; - Array markers; - bool expressions = false; - bool initiated = false; -}; - -#endif //_TVG_LOTTIE_MODEL_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.cpp deleted file mode 100644 index 8b2abd98..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* -* Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "tvgLottieModifier.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -static void _roundCorner(Array& cmds, Array& pts, const Point& prev, const Point& curr, const Point& next, float r) -{ - auto lenPrev = length(prev - curr); - auto rPrev = lenPrev > 0.0f ? 0.5f * std::min(lenPrev * 0.5f, r) / lenPrev : 0.0f; - auto lenNext = length(next - curr); - auto rNext = lenNext > 0.0f ? 0.5f * std::min(lenNext * 0.5f, r) / lenNext : 0.0f; - - auto dPrev = rPrev * (curr - prev); - auto dNext = rNext * (curr - next); - - pts.push(curr - 2.0f * dPrev); - pts.push(curr - dPrev); - pts.push(curr - dNext); - pts.push(curr - 2.0f * dNext); - cmds.push(PathCommand::LineTo); - cmds.push(PathCommand::CubicTo); -} - - -static bool _zero(const Point& p1, const Point& p2) -{ - constexpr float epsilon = 1e-3f; - return fabsf(p1.x / p2.x - 1.0f) < epsilon && fabsf(p1.y / p2.y - 1.0f) < epsilon; -} - - -static bool _intersect(const Line& line1, const Line& line2, Point& intersection, bool& inside) -{ - if (_zero(line1.pt2, line2.pt1)) { - intersection = line1.pt2; - inside = true; - return true; - } - - constexpr float epsilon = 1e-3f; - float denom = (line1.pt2.x - line1.pt1.x) * (line2.pt2.y - line2.pt1.y) - (line1.pt2.y - line1.pt1.y) * (line2.pt2.x - line2.pt1.x); - if (fabsf(denom) < epsilon) return false; - - float t = ((line2.pt1.x - line1.pt1.x) * (line2.pt2.y - line2.pt1.y) - (line2.pt1.y - line1.pt1.y) * (line2.pt2.x - line2.pt1.x)) / denom; - float u = ((line2.pt1.x - line1.pt1.x) * (line1.pt2.y - line1.pt1.y) - (line2.pt1.y - line1.pt1.y) * (line1.pt2.x - line1.pt1.x)) / denom; - - intersection.x = line1.pt1.x + t * (line1.pt2.x - line1.pt1.x); - intersection.y = line1.pt1.y + t * (line1.pt2.y - line1.pt1.y); - inside = t >= -epsilon && t <= 1.0f + epsilon && u >= -epsilon && u <= 1.0f + epsilon; - - return true; -} - - -static Line _offset(const Point& p1, const Point& p2, float offset) -{ - auto scaledNormal = normal(p1, p2) * offset; - return {p1 + scaledNormal, p2 + scaledNormal}; -} - - -static bool _clockwise(const Point* pts, uint32_t n) -{ - auto area = 0.0f; - - for (uint32_t i = 0; i < n - 1; i++) { - area += cross(pts[i], pts[i + 1]); - } - area += cross(pts[n - 1], pts[0]);; - - return area < 0.0f; -} - - -void LottieOffsetModifier::corner(const Line& line, const Line& nextLine, uint32_t movetoOutIndex, bool nextClose, Array& outCmds, Array& outPts) const -{ - bool inside{}; - Point intersect{}; - if (_intersect(line, nextLine, intersect, inside)) { - if (inside) { - if (nextClose) outPts[movetoOutIndex] = intersect; - outPts.push(intersect); - } else { - outPts.push(line.pt2); - if (join == StrokeJoin::Round) { - outCmds.push(PathCommand::CubicTo); - outPts.push((line.pt2 + intersect) * 0.5f); - outPts.push((nextLine.pt1 + intersect) * 0.5f); - outPts.push(nextLine.pt1); - } else if (join == StrokeJoin::Miter) { - auto norm = normal(line.pt1, line.pt2); - auto nextNorm = normal(nextLine.pt1, nextLine.pt2); - auto miterDirection = (norm + nextNorm) / length(norm + nextNorm); - outCmds.push(PathCommand::LineTo); - if (1.0f <= miterLimit * fabsf(miterDirection.x * norm.x + miterDirection.y * norm.y)) outPts.push(intersect); - else outPts.push(nextLine.pt1); - } else { - outCmds.push(PathCommand::LineTo); - outPts.push(nextLine.pt1); - } - } - } else outPts.push(line.pt2); -} - - -void LottieOffsetModifier::line(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t& currentPt, uint32_t currentCmd, State& state, bool degenerated, Array& outCmds, Array& outPts, float offset) const -{ - if (tvg::zero(inPts[currentPt - 1] - inPts[currentPt])) { - ++currentPt; - return; - } - - if (inCmds[currentCmd - 1] != PathCommand::LineTo) state.line = _offset(inPts[currentPt - 1], inPts[currentPt], offset); - - if (state.moveto) { - outCmds.push(PathCommand::MoveTo); - state.movetoOutIndex = outPts.count; - outPts.push(state.line.pt1); - state.firstLine = state.line; - state.moveto = false; - } - - auto nonDegeneratedCubic = [&](uint32_t cmd, uint32_t pt) { - return inCmds[cmd] == PathCommand::CubicTo && !tvg::zero(inPts[pt] - inPts[pt + 1]) && !tvg::zero(inPts[pt + 2] - inPts[pt + 3]); - }; - - outCmds.push(PathCommand::LineTo); - - if (currentCmd + 1 == inCmdsCnt || inCmds[currentCmd + 1] == PathCommand::MoveTo || nonDegeneratedCubic(currentCmd + 1, currentPt + degenerated)) { - outPts.push(state.line.pt2); - ++currentPt; - return; - } - - Line nextLine = state.firstLine; - if (inCmds[currentCmd + 1] == PathCommand::LineTo) nextLine = _offset(inPts[currentPt + degenerated], inPts[currentPt + 1 + degenerated], offset); - else if (inCmds[currentCmd + 1] == PathCommand::CubicTo) nextLine = _offset(inPts[currentPt + 1 + degenerated], inPts[currentPt + 2 + degenerated], offset); - else if (inCmds[currentCmd + 1] == PathCommand::Close && !_zero(inPts[currentPt + degenerated], inPts[state.movetoInIndex + degenerated])) - nextLine = _offset(inPts[currentPt + degenerated], inPts[state.movetoInIndex + degenerated], offset); - - corner(state.line, nextLine, state.movetoOutIndex, inCmds[currentCmd + 1] == PathCommand::Close, outCmds, outPts); - - state.line = nextLine; - ++currentPt; -} - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -bool LottieRoundnessModifier::modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array& outCmds, Array& outPts, Matrix* transform) const -{ - outCmds.reserve(inCmdsCnt * 2); - outPts.reserve((uint32_t)(inPtsCnt * 1.5)); - auto ptsCnt = outPts.count; - - uint32_t startIndex = 0; - for (uint32_t iCmds = 0, iPts = 0; iCmds < inCmdsCnt; ++iCmds) { - switch (inCmds[iCmds]) { - case PathCommand::MoveTo: { - startIndex = outPts.count; - outCmds.push(PathCommand::MoveTo); - outPts.push(inPts[iPts++]); - break; - } - case PathCommand::CubicTo: { - auto& prev = inPts[iPts - 1]; - auto& curr = inPts[iPts + 2]; - if (iCmds < inCmdsCnt - 1 && - tvg::zero(inPts[iPts - 1] - inPts[iPts]) && - tvg::zero(inPts[iPts + 1] - inPts[iPts + 2])) { - if (inCmds[iCmds + 1] == PathCommand::CubicTo && - tvg::zero(inPts[iPts + 2] - inPts[iPts + 3]) && - tvg::zero(inPts[iPts + 4] - inPts[iPts + 5])) { - _roundCorner(outCmds, outPts, prev, curr, inPts[iPts + 5], r); - iPts += 3; - break; - } else if (inCmds[iCmds + 1] == PathCommand::Close) { - _roundCorner(outCmds, outPts, prev, curr, inPts[2], r); - outPts[startIndex] = outPts.last(); - iPts += 3; - break; - } - } - outCmds.push(PathCommand::CubicTo); - outPts.push(inPts[iPts++]); - outPts.push(inPts[iPts++]); - outPts.push(inPts[iPts++]); - break; - } - case PathCommand::Close: { - outCmds.push(PathCommand::Close); - break; - } - default: break; - } - } - if (transform) { - for (auto i = ptsCnt; i < outPts.count; ++i) { - outPts[i] *= *transform; - } - } - return true; -} - - -bool LottieRoundnessModifier::modifyPolystar(TVG_UNUSED const Array& inCmds, const Array& inPts, Array& outCmds, Array& outPts, float outerRoundness, bool hasRoundness) const -{ - static constexpr auto ROUNDED_POLYSTAR_MAGIC_NUMBER = 0.47829f; - - auto len = length(inPts[1] - inPts[2]); - auto r = len > 0.0f ? ROUNDED_POLYSTAR_MAGIC_NUMBER * std::min(len * 0.5f, this->r) / len : 0.0f; - - if (hasRoundness) { - outCmds.grow((uint32_t)(1.5 * inCmds.count)); - outPts.grow((uint32_t)(4.5 * inCmds.count)); - - int start = 3 * tvg::zero(outerRoundness); - outCmds.push(PathCommand::MoveTo); - outPts.push(inPts[start]); - - for (uint32_t i = 1 + start; i < inPts.count; i += 6) { - auto& prev = inPts[i]; - auto& curr = inPts[i + 2]; - auto& next = (i < inPts.count - start) ? inPts[i + 4] : inPts[2]; - auto& nextCtrl = (i < inPts.count - start) ? inPts[i + 5] : inPts[3]; - auto dNext = r * (curr - next); - auto dPrev = r * (curr - prev); - - auto p0 = curr - 2.0f * dPrev; - auto p1 = curr - dPrev; - auto p2 = curr - dNext; - auto p3 = curr - 2.0f * dNext; - - outCmds.push(PathCommand::CubicTo); - outPts.push(prev); outPts.push(p0); outPts.push(p0); - outCmds.push(PathCommand::CubicTo); - outPts.push(p1); outPts.push(p2); outPts.push(p3); - outCmds.push(PathCommand::CubicTo); - outPts.push(p3); outPts.push(next); outPts.push(nextCtrl); - } - } else { - outCmds.grow(2 * inCmds.count); - outPts.grow(4 * inCmds.count); - - auto dPrev = r * (inPts[1] - inPts[0]); - auto p = inPts[0] + 2.0f * dPrev; - outCmds.push(PathCommand::MoveTo); - outPts.push(p); - - for (uint32_t i = 1; i < inPts.count; ++i) { - auto& curr = inPts[i]; - auto& next = (i == inPts.count - 1) ? inPts[1] : inPts[i + 1]; - auto dNext = r * (curr - next); - - auto p0 = curr - 2.0f * dPrev; - auto p1 = curr - dPrev; - auto p2 = curr - dNext; - auto p3 = curr - 2.0f * dNext; - - outCmds.push(PathCommand::LineTo); - outPts.push(p0); - outCmds.push(PathCommand::CubicTo); - outPts.push(p1); outPts.push(p2); outPts.push(p3); - - dPrev = -1.0f * dNext; - } - } - outCmds.push(PathCommand::Close); - return true; -} - - -bool LottieRoundnessModifier::modifyRect(const Point& size, float& r) const -{ - r = std::min(this->r, std::max(size.x, size.y) * 0.5f); - return true; -} - - -bool LottieOffsetModifier::modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array& outCmds, Array& outPts) const -{ - outCmds.reserve(inCmdsCnt * 2); - outPts.reserve(inPtsCnt * (join == StrokeJoin::Round ? 4 : 2)); - - Array stack{5}; - State state; - auto offset = _clockwise(inPts, inPtsCnt) ? this->offset : -this->offset; - auto threshold = 1.0f / fabsf(offset) + 1.0f; - - for (uint32_t iCmd = 0, iPt = 0; iCmd < inCmdsCnt; ++iCmd) { - if (inCmds[iCmd] == PathCommand::MoveTo) { - state.moveto = true; - state.movetoInIndex = iPt++; - } else if (inCmds[iCmd] == PathCommand::LineTo) { - line(inCmds, inCmdsCnt, inPts, iPt, iCmd, state, false, outCmds, outPts, offset); - } else if (inCmds[iCmd] == PathCommand::CubicTo) { - //cubic degenerated to a line - if (tvg::zero(inPts[iPt - 1] - inPts[iPt]) || tvg::zero(inPts[iPt + 1] - inPts[iPt + 2])) { - ++iPt; - line(inCmds, inCmdsCnt, inPts, iPt, iCmd, state, true, outCmds, outPts, offset); - ++iPt; - continue; - } - - stack.push({inPts[iPt - 1], inPts[iPt], inPts[iPt + 1], inPts[iPt + 2]}); - while (!stack.empty()) { - auto& bezier = stack.last(); - auto len = tvg::length(bezier.start - bezier.ctrl1) + tvg::length(bezier.ctrl1 - bezier.ctrl2) + tvg::length(bezier.ctrl2 - bezier.end); - - if (len > threshold * bezier.length()) { - Bezier next; - bezier.split(0.5f, next); - stack.push(next); - continue; - } - stack.pop(); - - auto line1 = _offset(bezier.start, bezier.ctrl1, offset); - auto line2 = _offset(bezier.ctrl1, bezier.ctrl2, offset); - auto line3 = _offset(bezier.ctrl2, bezier.end, offset); - - if (state.moveto) { - outCmds.push(PathCommand::MoveTo); - state.movetoOutIndex = outPts.count; - outPts.push(line1.pt1); - state.firstLine = line1; - state.moveto = false; - } - - bool inside{}; - Point intersect{}; - _intersect(line1, line2, intersect, inside); - outPts.push(intersect); - _intersect(line2, line3, intersect, inside); - outPts.push(intersect); - outPts.push(line3.pt2); - outCmds.push(PathCommand::CubicTo); - } - - iPt += 3; - } - else { - if (!_zero(inPts[iPt - 1], inPts[state.movetoInIndex])) { - outCmds.push(PathCommand::LineTo); - corner(state.line, state.firstLine, state.movetoOutIndex, true, outCmds, outPts); - } - outCmds.push(PathCommand::Close); - } - } - return true; -} - - -bool LottieOffsetModifier::modifyPolystar(const Array& inCmds, const Array& inPts, Array& outCmds, Array& outPts) const { - return modifyPath(inCmds.data, inCmds.count, inPts.data, inPts.count, outCmds, outPts); -} - - -bool LottieOffsetModifier::modifyRect(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array& outCmds, Array& outPts) const -{ - return modifyPath(inCmds, inCmdsCnt, inPts, inPtsCnt, outCmds, outPts); -} - - -bool LottieOffsetModifier::modifyEllipse(float& rx, float& ry) const -{ - rx += offset; - ry += offset; - return true; -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.h deleted file mode 100644 index 8cfe6e98..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieModifier.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_MODIFIER_H_ -#define _TVG_LOTTIE_MODIFIER_H_ - -#include "tvgCommon.h" -#include "tvgArray.h" -#include "tvgMath.h" - - -struct LottieRoundnessModifier -{ - static constexpr float ROUNDNESS_EPSILON = 1.0f; - float r; - - LottieRoundnessModifier(float r) : r(r) {}; - - bool modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array& outCmds, Array& outPts, Matrix* transform) const; - bool modifyPolystar(const Array& inCmds, const Array& inPts, Array& outCmds, Array& outPts, float outerRoundness, bool hasRoundness) const; - bool modifyRect(const Point& size, float& r) const; -}; - - -struct LottieOffsetModifier -{ - float offset; - float miterLimit; - StrokeJoin join; - - LottieOffsetModifier(float offset, float miter = 4.0f, StrokeJoin join = StrokeJoin::Round) : offset(offset), miterLimit(miter), join(join) {}; - - bool modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array& outCmds, Array& outPts) const; - bool modifyPolystar(const Array& inCmds, const Array& inPts, Array& outCmds, Array& outPts) const; - bool modifyRect(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array& outCmds, Array& outPts) const; - bool modifyEllipse(float& rx, float& ry) const; - -private: - struct State - { - Line line{}; - Line firstLine{}; - bool moveto = false; - uint32_t movetoOutIndex = 0; - uint32_t movetoInIndex = 0; - }; - - void line(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t& currentPt, uint32_t currentCmd, State& state, bool degenerated, Array& cmds, Array& pts, float offset) const; - void corner(const Line& line, const Line& nextLine, uint32_t movetoIndex, bool nextClose, Array& cmds, Array& pts) const; -}; - -#endif diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.cpp deleted file mode 100644 index 3b63e767..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.cpp +++ /dev/null @@ -1,1511 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "tvgStr.h" -#include "tvgCompressor.h" -#include "tvgLottieModel.h" -#include "tvgLottieParser.h" -#include "tvgLottieExpressions.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -#define KEY_AS(name) !strcmp(key, name) - - -static LottieExpression* _expression(char* code, LottieComposition* comp, LottieLayer* layer, LottieObject* object, LottieProperty* property) -{ - if (!comp->expressions) comp->expressions = true; - - auto inst = new LottieExpression; - inst->code = code; - inst->comp = comp; - inst->layer = layer; - inst->object = object; - inst->property = property; - - return inst; -} - - -static unsigned long _int2str(int num) -{ - char str[20]; - snprintf(str, 20, "%d", num); - return djb2Encode(str); -} - - -LottieEffect* LottieParser::getEffect(int type) -{ - switch (type) { - case 29: return new LottieGaussianBlur; - default: return nullptr; - } -} - - -CompositeMethod LottieParser::getMaskMethod(bool inversed) -{ - auto mode = getString(); - if (!mode) return CompositeMethod::None; - - switch (mode[0]) { - case 'a': { - if (inversed) return CompositeMethod::InvAlphaMask; - else return CompositeMethod::AddMask; - } - case 's': return CompositeMethod::SubtractMask; - case 'i': return CompositeMethod::IntersectMask; - case 'f': return CompositeMethod::DifferenceMask; - case 'l': return CompositeMethod::LightenMask; - case 'd': return CompositeMethod::DarkenMask; - default: return CompositeMethod::None; - } -} - - -RGB24 LottieParser::getColor(const char *str) -{ - RGB24 color = {0, 0, 0}; - - if (!str) return color; - - auto len = strlen(str); - - // some resource has empty color string, return a default color for those cases. - if (len != 7 || str[0] != '#') return color; - - char tmp[3] = {'\0', '\0', '\0'}; - tmp[0] = str[1]; - tmp[1] = str[2]; - color.rgb[0] = uint8_t(strtol(tmp, nullptr, 16)); - - tmp[0] = str[3]; - tmp[1] = str[4]; - color.rgb[1] = uint8_t(strtol(tmp, nullptr, 16)); - - tmp[0] = str[5]; - tmp[1] = str[6]; - color.rgb[2] = uint8_t(strtol(tmp, nullptr, 16)); - - return color; -} - - -FillRule LottieParser::getFillRule() -{ - switch (getInt()) { - case 1: return FillRule::Winding; - default: return FillRule::EvenOdd; - } -} - - -CompositeMethod LottieParser::getMatteType() -{ - switch (getInt()) { - case 1: return CompositeMethod::AlphaMask; - case 2: return CompositeMethod::InvAlphaMask; - case 3: return CompositeMethod::LumaMask; - case 4: return CompositeMethod::InvLumaMask; - default: return CompositeMethod::None; - } -} - - -StrokeCap LottieParser::getStrokeCap() -{ - switch (getInt()) { - case 1: return StrokeCap::Butt; - case 2: return StrokeCap::Round; - default: return StrokeCap::Square; - } -} - - -StrokeJoin LottieParser::getStrokeJoin() -{ - switch (getInt()) { - case 1: return StrokeJoin::Miter; - case 2: return StrokeJoin::Round; - default: return StrokeJoin::Bevel; - } -} - - -void LottieParser::getValue(TextDocument& doc) -{ - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("s")) doc.size = getFloat() * 0.01f; - else if (KEY_AS("f")) doc.name = getStringCopy(); - else if (KEY_AS("t")) doc.text = getStringCopy(); - else if (KEY_AS("j")) doc.justify = getInt(); - else if (KEY_AS("tr")) doc.tracking = getFloat() * 0.1f; - else if (KEY_AS("lh")) doc.height = getFloat(); - else if (KEY_AS("ls")) doc.shift = getFloat(); - else if (KEY_AS("fc")) getValue(doc.color); - else if (KEY_AS("ps")) getValue(doc.bbox.pos); - else if (KEY_AS("sz")) getValue(doc.bbox.size); - else if (KEY_AS("sc")) getValue(doc.stroke.color); - else if (KEY_AS("sw")) doc.stroke.width = getFloat(); - else if (KEY_AS("of")) doc.stroke.render = getBool(); - else skip(key); - } -} - - -void LottieParser::getValue(PathSet& path) -{ - Array outs, ins, pts; - bool closed = false; - - /* The shape object could be wrapped by a array - if its part of the keyframe object */ - auto arrayWrapper = (peekType() == kArrayType) ? true : false; - if (arrayWrapper) enterArray(); - - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("i")) getValue(ins); - else if (KEY_AS("o")) getValue(outs); - else if (KEY_AS("v")) getValue(pts); - else if (KEY_AS("c")) closed = getBool(); - else skip(key); - } - - //exit properly from the array - if (arrayWrapper) nextArrayValue(); - - //valid path data? - if (ins.empty() || outs.empty() || pts.empty()) return; - if (ins.count != outs.count || outs.count != pts.count) return; - - //convert path - auto out = outs.begin(); - auto in = ins.begin(); - auto pt = pts.begin(); - - //Store manipulated results - Array outPts; - Array outCmds; - - //Reuse the buffers - outPts.data = path.pts; - outPts.reserved = path.ptsCnt; - outCmds.data = path.cmds; - outCmds.reserved = path.cmdsCnt; - - size_t extra = closed ? 3 : 0; - outPts.reserve(pts.count * 3 + 1 + extra); - outCmds.reserve(pts.count + 2); - - outCmds.push(PathCommand::MoveTo); - outPts.push(*pt); - - for (++pt, ++out, ++in; pt < pts.end(); ++pt, ++out, ++in) { - outCmds.push(PathCommand::CubicTo); - outPts.push(*(pt - 1) + *(out - 1)); - outPts.push(*pt + *in); - outPts.push(*pt); - } - - if (closed) { - outPts.push(pts.last() + outs.last()); - outPts.push(pts.first() + ins.first()); - outPts.push(pts.first()); - outCmds.push(PathCommand::CubicTo); - outCmds.push(PathCommand::Close); - } - - path.pts = outPts.data; - path.cmds = outCmds.data; - path.ptsCnt = outPts.count; - path.cmdsCnt = outCmds.count; - - outPts.data = nullptr; - outCmds.data = nullptr; -} - - -void LottieParser::getValue(ColorStop& color) -{ - if (peekType() == kArrayType) enterArray(); - - if (!color.input) color.input = new Array(static_cast(context.parent)->colorStops.count * 6); - else color.input->clear(); - - while (nextArrayValue()) color.input->push(getFloat()); -} - - -void LottieParser::getValue(Array& pts) -{ - enterArray(); - while (nextArrayValue()) { - enterArray(); - Point pt; - getValue(pt); - pts.push(pt); - } -} - - -void LottieParser::getValue(int8_t& val) -{ - if (peekType() == kArrayType) { - enterArray(); - if (nextArrayValue()) val = getInt(); - //discard rest - while (nextArrayValue()) getInt(); - } else { - val = getFloat(); - } -} - - -void LottieParser::getValue(uint8_t& val) -{ - if (peekType() == kArrayType) { - enterArray(); - if (nextArrayValue()) val = (uint8_t)(getFloat() * 2.55f); - //discard rest - while (nextArrayValue()) getFloat(); - } else { - val = (uint8_t)(getFloat() * 2.55f); - } -} - - -void LottieParser::getValue(float& val) -{ - if (peekType() == kArrayType) { - enterArray(); - if (nextArrayValue()) val = getFloat(); - //discard rest - while (nextArrayValue()) getFloat(); - } else { - val = getFloat(); - } -} - - -bool LottieParser::getValue(Point& pt) -{ - auto type = peekType(); - if (type == kNullType) return false; - - int i = 0; - auto ptr = (float*)(&pt); - - if (type == kArrayType) enterArray(); - - while (nextArrayValue()) { - auto val = getFloat(); - if (i < 2) ptr[i++] = val; - } - - return true; -} - - -void LottieParser::getValue(RGB24& color) -{ - int i = 0; - - if (peekType() == kArrayType) enterArray(); - - while (nextArrayValue()) { - auto val = getFloat(); - if (i < 3) color.rgb[i++] = REMAP255(val); - } - - //TODO: color filter? -} - - -void LottieParser::getInterpolatorPoint(Point& pt) -{ - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("x")) getValue(pt.x); - else if (KEY_AS("y")) getValue(pt.y); - } -} - - -template -void LottieParser::parseSlotProperty(T& prop) -{ - while (auto key = nextObjectKey()) { - if (KEY_AS("p")) parseProperty(prop); - else skip(key); - } -} - - -template -bool LottieParser::parseTangent(const char *key, LottieVectorFrame& value) -{ - if (KEY_AS("ti") && getValue(value.inTangent)) ; - else if (KEY_AS("to") && getValue(value.outTangent)) ; - else return false; - - value.hasTangent = true; - return true; -} - - -template -bool LottieParser::parseTangent(const char *key, LottieScalarFrame& value) -{ - return false; -} - - -LottieInterpolator* LottieParser::getInterpolator(const char* key, Point& in, Point& out) -{ - char buf[20]; - - if (!key) { - snprintf(buf, sizeof(buf), "%.2f_%.2f_%.2f_%.2f", in.x, in.y, out.x, out.y); - key = buf; - } - - LottieInterpolator* interpolator = nullptr; - - //get a cached interpolator if it has any. - for (auto i = comp->interpolators.begin(); i < comp->interpolators.end(); ++i) { - if (!strncmp((*i)->key, key, sizeof(buf))) interpolator = *i; - } - - //new interpolator - if (!interpolator) { - interpolator = static_cast(malloc(sizeof(LottieInterpolator))); - interpolator->set(key, in, out); - comp->interpolators.push(interpolator); - } - - return interpolator; -} - - -template -void LottieParser::parseKeyFrame(T& prop) -{ - Point inTangent, outTangent; - const char* interpolatorKey = nullptr; - auto& frame = prop.newFrame(); - auto interpolator = false; - - enterObject(); - - while (auto key = nextObjectKey()) { - if (KEY_AS("i")) { - interpolator = true; - getInterpolatorPoint(inTangent); - } else if (KEY_AS("o")) { - getInterpolatorPoint(outTangent); - } else if (KEY_AS("n")) { - if (peekType() == kStringType) { - interpolatorKey = getString(); - } else { - enterArray(); - while (nextArrayValue()) { - if (!interpolatorKey) interpolatorKey = getString(); - else skip(nullptr); - } - } - } else if (KEY_AS("t")) { - frame.no = getFloat(); - } else if (KEY_AS("s")) { - getValue(frame.value); - } else if (KEY_AS("e")) { - //current end frame and the next start frame is duplicated, - //We propagate the end value to the next frame to avoid having duplicated values. - auto& frame2 = prop.nextFrame(); - getValue(frame2.value); - } else if (parseTangent(key, frame)) { - continue; - } else if (KEY_AS("h")) { - frame.hold = getInt(); - } else skip(key); - } - - if (interpolator) { - frame.interpolator = getInterpolator(interpolatorKey, inTangent, outTangent); - } -} - -template -void LottieParser::parsePropertyInternal(T& prop) -{ - //single value property - if (peekType() == kNumberType) { - getValue(prop.value); - //multi value property - } else { - //TODO: Here might be a single frame. - //Can we figure out the frame number in advance? - enterArray(); - while (nextArrayValue()) { - //keyframes value - if (peekType() == kObjectType) { - parseKeyFrame(prop); - //multi value property with no keyframes - } else { - getValue(prop.value); - break; - } - } - prop.prepare(); - } -} - - -template -void LottieParser::parseProperty(T& prop, LottieObject* obj) -{ - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("k")) parsePropertyInternal(prop); - else if (obj && KEY_AS("sid")) { - auto sid = getStringCopy(); - //append object if the slot already exists. - for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) { - if (strcmp((*slot)->sid, sid)) continue; - (*slot)->pairs.push({obj}); - break; - } - comp->slots.push(new LottieSlot(sid, obj, type)); - } else if (KEY_AS("x")) { - prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop); - } else if (KEY_AS("ix")) { - prop.ix = getInt(); - } else skip(key); - } - prop.type = type; -} - - -bool LottieParser::parseCommon(LottieObject* obj, const char* key) -{ - if (KEY_AS("nm")) { - obj->id = djb2Encode(getString()); - return true; - } else if (KEY_AS("hd")) { - obj->hidden = getBool(); - return true; - } else return false; -} - - -bool LottieParser::parseDirection(LottieShape* shape, const char* key) -{ - if (KEY_AS("d")) { - if (getInt() == 3) { - shape->clockwise = false; //default is true - } - return true; - } - return false; -} - - -LottieRect* LottieParser::parseRect() -{ - auto rect = new LottieRect; - - context.parent = rect; - - while (auto key = nextObjectKey()) { - if (parseCommon(rect, key)) continue; - else if (KEY_AS("s")) parseProperty(rect->size); - else if (KEY_AS("p")) parseProperty(rect->position); - else if (KEY_AS("r")) parseProperty(rect->radius); - else if (parseDirection(rect, key)) continue; - else skip(key); - } - rect->prepare(); - return rect; -} - - -LottieEllipse* LottieParser::parseEllipse() -{ - auto ellipse = new LottieEllipse; - - context.parent = ellipse; - - while (auto key = nextObjectKey()) { - if (parseCommon(ellipse, key)) continue; - else if (KEY_AS("p")) parseProperty(ellipse->position); - else if (KEY_AS("s")) parseProperty(ellipse->size); - else if (parseDirection(ellipse, key)) continue; - else skip(key); - } - ellipse->prepare(); - return ellipse; -} - - -LottieTransform* LottieParser::parseTransform(bool ddd) -{ - auto transform = new LottieTransform; - - context.parent = transform; - - if (ddd) { - transform->rotationEx = new LottieTransform::RotationEx; - TVGLOG("LOTTIE", "3D transform(ddd) is not totally compatible."); - } - - while (auto key = nextObjectKey()) { - if (parseCommon(transform, key)) continue; - else if (KEY_AS("p")) - { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("k")) parsePropertyInternal(transform->position); - else if (KEY_AS("s") && getBool()) transform->coords = new LottieTransform::SeparateCoord; - //check separateCoord to figure out whether "x(expression)" / "x(coord)" - else if (transform->coords && KEY_AS("x")) parseProperty(transform->coords->x); - else if (transform->coords && KEY_AS("y")) parseProperty(transform->coords->y); - else if (KEY_AS("x")) transform->position.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &transform->position); - else skip(key); - } - transform->position.type = LottieProperty::Type::Position; - } - else if (KEY_AS("a")) parseProperty(transform->anchor); - else if (KEY_AS("s")) parseProperty(transform->scale); - else if (KEY_AS("r")) parseProperty(transform->rotation); - else if (KEY_AS("o")) parseProperty(transform->opacity); - else if (transform->rotationEx && KEY_AS("rx")) parseProperty(transform->rotationEx->x); - else if (transform->rotationEx && KEY_AS("ry")) parseProperty(transform->rotationEx->y); - else if (transform->rotationEx && KEY_AS("rz")) parseProperty(transform->rotation); - else if (KEY_AS("sk")) parseProperty(transform->skewAngle); - else if (KEY_AS("sa")) parseProperty(transform->skewAxis); - else skip(key); - } - transform->prepare(); - return transform; -} - - -LottieSolidFill* LottieParser::parseSolidFill() -{ - auto fill = new LottieSolidFill; - - context.parent = fill; - - while (auto key = nextObjectKey()) { - if (parseCommon(fill, key)) continue; - else if (KEY_AS("c")) parseProperty(fill->color, fill); - else if (KEY_AS("o")) parseProperty(fill->opacity, fill); - else if (KEY_AS("fillEnabled")) fill->hidden |= !getBool(); - else if (KEY_AS("r")) fill->rule = getFillRule(); - else skip(key); - } - fill->prepare(); - return fill; -} - - -void LottieParser::parseStrokeDash(LottieStroke* stroke) -{ - enterArray(); - while (nextArrayValue()) { - enterObject(); - int idx = 0; - while (auto key = nextObjectKey()) { - if (KEY_AS("n")) { - auto style = getString(); - if (!strcmp("o", style)) idx = 0; //offset - else if (!strcmp("d", style)) idx = 1; //dash - else if (!strcmp("g", style)) idx = 2; //gap - } else if (KEY_AS("v")) { - parseProperty(stroke->dash(idx)); - } else skip(key); - } - } -} - - -LottieSolidStroke* LottieParser::parseSolidStroke() -{ - auto stroke = new LottieSolidStroke; - - context.parent = stroke; - - while (auto key = nextObjectKey()) { - if (parseCommon(stroke, key)) continue; - else if (KEY_AS("c")) parseProperty(stroke->color, stroke); - else if (KEY_AS("o")) parseProperty(stroke->opacity, stroke); - else if (KEY_AS("w")) parseProperty(stroke->width, stroke); - else if (KEY_AS("lc")) stroke->cap = getStrokeCap(); - else if (KEY_AS("lj")) stroke->join = getStrokeJoin(); - else if (KEY_AS("ml")) stroke->miterLimit = getFloat(); - else if (KEY_AS("fillEnabled")) stroke->hidden |= !getBool(); - else if (KEY_AS("d")) parseStrokeDash(stroke); - else skip(key); - } - stroke->prepare(); - return stroke; -} - - -void LottieParser::getPathSet(LottiePathSet& path) -{ - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("k")) { - if (peekType() == kArrayType) { - enterArray(); - while (nextArrayValue()) parseKeyFrame(path); - } else { - getValue(path.value); - } - } else if (KEY_AS("x")) { - path.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &path); - } else skip(key); - } - path.type = LottieProperty::Type::PathSet; -} - - -LottiePath* LottieParser::parsePath() -{ - auto path = new LottiePath; - - while (auto key = nextObjectKey()) { - if (parseCommon(path, key)) continue; - else if (KEY_AS("ks")) getPathSet(path->pathset); - else if (parseDirection(path, key)) continue; - else skip(key); - } - path->prepare(); - return path; -} - - -LottiePolyStar* LottieParser::parsePolyStar() -{ - auto star = new LottiePolyStar; - - context.parent = star; - - while (auto key = nextObjectKey()) { - if (parseCommon(star, key)) continue; - else if (KEY_AS("p")) parseProperty(star->position); - else if (KEY_AS("pt")) parseProperty(star->ptsCnt); - else if (KEY_AS("ir")) parseProperty(star->innerRadius); - else if (KEY_AS("is")) parseProperty(star->innerRoundness); - else if (KEY_AS("or")) parseProperty(star->outerRadius); - else if (KEY_AS("os")) parseProperty(star->outerRoundness); - else if (KEY_AS("r")) parseProperty(star->rotation); - else if (KEY_AS("sy")) star->type = (LottiePolyStar::Type) getInt(); - else if (parseDirection(star, key)) continue; - else skip(key); - } - star->prepare(); - return star; -} - - -LottieRoundedCorner* LottieParser::parseRoundedCorner() -{ - auto corner = new LottieRoundedCorner; - - context.parent = corner; - - while (auto key = nextObjectKey()) { - if (parseCommon(corner, key)) continue; - else if (KEY_AS("r")) parseProperty(corner->radius); - else skip(key); - } - corner->prepare(); - return corner; -} - - -void LottieParser::parseGradient(LottieGradient* gradient, const char* key) -{ - if (KEY_AS("t")) gradient->id = getInt(); - else if (KEY_AS("o")) parseProperty(gradient->opacity, gradient); - else if (KEY_AS("g")) - { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("p")) gradient->colorStops.count = getInt(); - else if (KEY_AS("k")) parseProperty(gradient->colorStops, gradient); - else skip(key); - } - } - else if (KEY_AS("s")) parseProperty(gradient->start, gradient); - else if (KEY_AS("e")) parseProperty(gradient->end, gradient); - else if (KEY_AS("h")) parseProperty(gradient->height, gradient); - else if (KEY_AS("a")) parseProperty(gradient->angle, gradient); - else skip(key); -} - - -LottieGradientFill* LottieParser::parseGradientFill() -{ - auto fill = new LottieGradientFill; - - context.parent = fill; - - while (auto key = nextObjectKey()) { - if (parseCommon(fill, key)) continue; - else if (KEY_AS("r")) fill->rule = getFillRule(); - else parseGradient(fill, key); - } - - fill->prepare(); - - return fill; -} - - -LottieGradientStroke* LottieParser::parseGradientStroke() -{ - auto stroke = new LottieGradientStroke; - - context.parent = stroke; - - while (auto key = nextObjectKey()) { - if (parseCommon(stroke, key)) continue; - else if (KEY_AS("lc")) stroke->cap = getStrokeCap(); - else if (KEY_AS("lj")) stroke->join = getStrokeJoin(); - else if (KEY_AS("ml")) stroke->miterLimit = getFloat(); - else if (KEY_AS("w")) parseProperty(stroke->width); - else if (KEY_AS("d")) parseStrokeDash(stroke); - else parseGradient(stroke, key); - } - stroke->prepare(); - - return stroke; -} - - -LottieTrimpath* LottieParser::parseTrimpath() -{ - auto trim = new LottieTrimpath; - - context.parent = trim; - - while (auto key = nextObjectKey()) { - if (parseCommon(trim, key)) continue; - else if (KEY_AS("s")) parseProperty(trim->start); - else if (KEY_AS("e")) parseProperty(trim->end); - else if (KEY_AS("o")) parseProperty(trim->offset); - else if (KEY_AS("m")) trim->type = static_cast(getInt()); - else skip(key); - } - trim->prepare(); - - return trim; -} - - -LottieRepeater* LottieParser::parseRepeater() -{ - auto repeater = new LottieRepeater; - - context.parent = repeater; - - while (auto key = nextObjectKey()) { - if (parseCommon(repeater, key)) continue; - else if (KEY_AS("c")) parseProperty(repeater->copies); - else if (KEY_AS("o")) parseProperty(repeater->offset); - else if (KEY_AS("m")) repeater->inorder = getInt() == 2; - else if (KEY_AS("tr")) - { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("a")) parseProperty(repeater->anchor); - else if (KEY_AS("p")) parseProperty(repeater->position); - else if (KEY_AS("r")) parseProperty(repeater->rotation); - else if (KEY_AS("s")) parseProperty(repeater->scale); - else if (KEY_AS("so")) parseProperty(repeater->startOpacity); - else if (KEY_AS("eo")) parseProperty(repeater->endOpacity); - else skip(key); - } - } - else skip(key); - } - repeater->prepare(); - - return repeater; -} - - -LottieOffsetPath* LottieParser::parseOffsetPath() -{ - auto offsetPath = new LottieOffsetPath; - - context.parent = offsetPath; - - while (auto key = nextObjectKey()) { - if (parseCommon(offsetPath, key)) continue; - else if (KEY_AS("a")) parseProperty(offsetPath->offset); - else if (KEY_AS("lj")) offsetPath->join = getStrokeJoin(); - else if (KEY_AS("ml")) parseProperty(offsetPath->miterLimit); - else skip(key); - } - offsetPath->prepare(); - - return offsetPath; -} - - -LottieObject* LottieParser::parseObject() -{ - auto type = getString(); - if (!type) return nullptr; - - if (!strcmp(type, "gr")) return parseGroup(); - else if (!strcmp(type, "rc")) return parseRect(); - else if (!strcmp(type, "el")) return parseEllipse(); - else if (!strcmp(type, "tr")) return parseTransform(); - else if (!strcmp(type, "fl")) return parseSolidFill(); - else if (!strcmp(type, "st")) return parseSolidStroke(); - else if (!strcmp(type, "sh")) return parsePath(); - else if (!strcmp(type, "sr")) return parsePolyStar(); - else if (!strcmp(type, "rd")) return parseRoundedCorner(); - else if (!strcmp(type, "gf")) return parseGradientFill(); - else if (!strcmp(type, "gs")) return parseGradientStroke(); - else if (!strcmp(type, "tm")) return parseTrimpath(); - else if (!strcmp(type, "rp")) return parseRepeater(); - else if (!strcmp(type, "mm")) TVGLOG("LOTTIE", "MergePath(mm) is not supported yet"); - else if (!strcmp(type, "pb")) TVGLOG("LOTTIE", "Puker/Bloat(pb) is not supported yet"); - else if (!strcmp(type, "tw")) TVGLOG("LOTTIE", "Twist(tw) is not supported yet"); - else if (!strcmp(type, "op")) return parseOffsetPath(); - else if (!strcmp(type, "zz")) TVGLOG("LOTTIE", "ZigZag(zz) is not supported yet"); - return nullptr; -} - - -void LottieParser::parseObject(Array& parent) -{ - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("ty")) { - if (auto child = parseObject()) { - if (child->hidden) delete(child); - else parent.push(child); - } - } else skip(key); - } -} - - -LottieImage* LottieParser::parseImage(const char* data, const char* subPath, bool embedded, float width, float height) -{ - //Used for Image Asset - auto image = new LottieImage; - - //embedded image resource. should start with "data:" - //header look like "data:image/png;base64," so need to skip till ','. - if (embedded && !strncmp(data, "data:", 5)) { - //figure out the mimetype - auto mimeType = data + 11; - auto needle = strstr(mimeType, ";"); - image->mimeType = strDuplicate(mimeType, needle - mimeType); - //b64 data - auto b64Data = strstr(data, ",") + 1; - size_t length = strlen(data) - (b64Data - data); - image->size = b64Decode(b64Data, length, &image->b64Data); - //external image resource - } else { - auto len = strlen(dirName) + strlen(subPath) + strlen(data) + 1; - image->path = static_cast(malloc(len)); - snprintf(image->path, len, "%s%s%s", dirName, subPath, data); - } - - image->width = width; - image->height = height; - image->prepare(); - - return image; -} - - -LottieObject* LottieParser::parseAsset() -{ - enterObject(); - - LottieObject* obj = nullptr; - unsigned long id = 0; - - //Used for Image Asset - const char* data = nullptr; - const char* subPath = nullptr; - float width = 0.0f; - float height = 0.0f; - auto embedded = false; - - while (auto key = nextObjectKey()) { - if (KEY_AS("id")) - { - if (peekType() == kStringType) { - id = djb2Encode(getString()); - } else { - id = _int2str(getInt()); - } - } - else if (KEY_AS("layers")) obj = parseLayers(comp->root); - else if (KEY_AS("u")) subPath = getString(); - else if (KEY_AS("p")) data = getString(); - else if (KEY_AS("w")) width = getFloat(); - else if (KEY_AS("h")) height = getFloat(); - else if (KEY_AS("e")) embedded = getInt(); - else skip(key); - } - if (data) obj = parseImage(data, subPath, embedded, width, height); - if (obj) obj->id = id; - return obj; -} - - -LottieFont* LottieParser::parseFont() -{ - enterObject(); - - auto font = new LottieFont; - - while (auto key = nextObjectKey()) { - if (KEY_AS("fName")) font->name = getStringCopy(); - else if (KEY_AS("fFamily")) font->family = getStringCopy(); - else if (KEY_AS("fStyle")) font->style = getStringCopy(); - else if (KEY_AS("ascent")) font->ascent = getFloat(); - else if (KEY_AS("origin")) font->origin = (LottieFont::Origin) getInt(); - else skip(key); - } - return font; -} - - -void LottieParser::parseAssets() -{ - enterArray(); - while (nextArrayValue()) { - auto asset = parseAsset(); - if (asset) comp->assets.push(asset); - else TVGERR("LOTTIE", "Invalid Asset!"); - } -} - -LottieMarker* LottieParser::parseMarker() -{ - enterObject(); - - auto marker = new LottieMarker; - - while (auto key = nextObjectKey()) { - if (KEY_AS("cm")) marker->name = getStringCopy(); - else if (KEY_AS("tm")) marker->time = getFloat(); - else if (KEY_AS("dr")) marker->duration = getFloat(); - else skip(key); - } - - return marker; -} - -void LottieParser::parseMarkers() -{ - enterArray(); - while (nextArrayValue()) { - comp->markers.push(parseMarker()); - } -} - -void LottieParser::parseChars(Array& glyphs) -{ - enterArray(); - while (nextArrayValue()) { - enterObject(); - //a new glyph - auto glyph = new LottieGlyph; - while (auto key = nextObjectKey()) { - if (KEY_AS("ch")) glyph->code = getStringCopy(); - else if (KEY_AS("size")) glyph->size = static_cast(getFloat()); - else if (KEY_AS("style")) glyph->style = getStringCopy(); - else if (KEY_AS("w")) glyph->width = getFloat(); - else if (KEY_AS("fFamily")) glyph->family = getStringCopy(); - else if (KEY_AS("data")) - { //glyph shapes - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("shapes")) parseShapes(glyph->children); - } - } else skip(key); - } - glyph->prepare(); - glyphs.push(glyph); - } -} - -void LottieParser::parseFonts() -{ - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("list")) { - enterArray(); - while (nextArrayValue()) { - comp->fonts.push(parseFont()); - } - } else skip(key); - } -} - - -LottieObject* LottieParser::parseGroup() -{ - auto group = new LottieGroup; - - while (auto key = nextObjectKey()) { - if (parseCommon(group, key)) continue; - else if (KEY_AS("it")) { - enterArray(); - while (nextArrayValue()) parseObject(group->children); - } else skip(key); - } - if (group->children.empty()) { - delete(group); - return nullptr; - } - group->prepare(); - - return group; -} - - -void LottieParser::parseTimeRemap(LottieLayer* layer) -{ - parseProperty(layer->timeRemap); -} - - -void LottieParser::parseShapes(Array& parent) -{ - enterArray(); - while (nextArrayValue()) { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("it")) { - enterArray(); - while (nextArrayValue()) parseObject(parent); - } else if (KEY_AS("ty")) { - if (auto child = parseObject()) { - if (child->hidden) delete(child); - else parent.push(child); - } - } else skip(key); - } - } -} - - -void LottieParser::parseTextRange(LottieText* text) -{ - enterArray(); - while (nextArrayValue()) { - enterObject(); - - auto selector = new LottieTextRange; - - while (auto key = nextObjectKey()) { - if (KEY_AS("s")) { // text range selector - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("t")) selector->expressible = (bool) getInt(); - else if (KEY_AS("xe")) parseProperty(selector->maxEase); - else if (KEY_AS("ne")) parseProperty(selector->minEase); - else if (KEY_AS("a")) parseProperty(selector->maxAmount); - else if (KEY_AS("b")) selector->based = (LottieTextRange::Based) getInt(); - else if (KEY_AS("rn")) selector->random = getInt() ? rand() : 0; - else if (KEY_AS("sh")) selector->shape = (LottieTextRange::Shape) getInt(); - else if (KEY_AS("o")) parseProperty(selector->offset); - else if (KEY_AS("r")) selector->rangeUnit = (LottieTextRange::Unit) getInt(); - else if (KEY_AS("sm")) parseProperty(selector->smoothness); - else if (KEY_AS("s")) parseProperty(selector->start); - else if (KEY_AS("e")) parseProperty(selector->end); - else skip(key); - } - } else if (KEY_AS("a")) { // text style - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("t")) parseProperty(selector->style.letterSpacing); - else if (KEY_AS("ls")) parseProperty(selector->style.lineSpacing); - else if (KEY_AS("fc")) parseProperty(selector->style.fillColor); - else if (KEY_AS("fo")) parseProperty(selector->style.fillOpacity); - else if (KEY_AS("sw")) parseProperty(selector->style.strokeWidth); - else if (KEY_AS("sc")) parseProperty(selector->style.strokeColor); - else if (KEY_AS("so")) parseProperty(selector->style.strokeOpacity); - else if (KEY_AS("o")) parseProperty(selector->style.opacity); - else if (KEY_AS("p")) parseProperty(selector->style.position); - else if (KEY_AS("s")) parseProperty(selector->style.scale); - else if (KEY_AS("r")) parseProperty(selector->style.rotation); - else skip(key); - } - } else skip(key); - } - - text->ranges.push(selector); - } -} - - -void LottieParser::parseText(Array& parent) -{ - enterObject(); - - auto text = new LottieText; - - while (auto key = nextObjectKey()) { - if (KEY_AS("d")) parseProperty(text->doc, text); - else if (KEY_AS("a")) parseTextRange(text); - else if (KEY_AS("p")) - { - TVGLOG("LOTTIE", "Text Follow Path (p) is not supported"); - skip(key); - } - else if (KEY_AS("m")) - { - TVGLOG("LOTTIE", "Text Alignment Option (m) is not supported"); - skip(key); - } - else skip(key); - } - - text->prepare(); - parent.push(text); -} - - -void LottieParser::getLayerSize(float& val) -{ - if (val == 0.0f) { - val = getFloat(); - } else { - //layer might have both w(width) & sw(solid color width) - //override one if the a new size is smaller. - auto w = getFloat(); - if (w < val) val = w; - } -} - -LottieMask* LottieParser::parseMask() -{ - auto mask = new LottieMask; - auto valid = true; //skip if the mask mode is none. - - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("inv")) mask->inverse = getBool(); - else if (KEY_AS("mode")) - { - mask->method = getMaskMethod(mask->inverse); - if (mask->method == CompositeMethod::None) valid = false; - } - else if (valid && KEY_AS("pt")) getPathSet(mask->pathset); - else if (valid && KEY_AS("o")) parseProperty(mask->opacity); - else if (valid && KEY_AS("x")) parseProperty(mask->expand); - else skip(key); - } - - if (!valid) { - delete(mask); - return nullptr; - } - - return mask; -} - - -void LottieParser::parseMasks(LottieLayer* layer) -{ - enterArray(); - while (nextArrayValue()) { - if (auto mask = parseMask()) { - layer->masks.push(mask); - } - } -} - - -void LottieParser::parseGaussianBlur(LottieGaussianBlur* effect) -{ - int idx = 0; //blurness -> direction -> wrap - enterArray(); - while (nextArrayValue()) { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("v")) { - enterObject(); - while (auto key = nextObjectKey()) { - if (KEY_AS("k")) { - if (idx == 0) parsePropertyInternal(effect->blurness); - else if (idx == 1) parsePropertyInternal(effect->direction); - else if (idx == 2) parsePropertyInternal(effect->wrap); - else skip(key); - ++idx; - } else skip(key); - } - } else skip(key); - } - } -} - - -void LottieParser::parseEffect(LottieEffect* effect) -{ - switch (effect->type) { - case LottieEffect::GaussianBlur: { - parseGaussianBlur(static_cast(effect)); - break; - } - default: break; - } -} - - -void LottieParser::parseEffects(LottieLayer* layer) -{ - auto invalid = true; - - enterArray(); - while (nextArrayValue()) { - LottieEffect* effect = nullptr; - enterObject(); - while (auto key = nextObjectKey()) { - //type must be priortized. - if (KEY_AS("ty")) - { - effect = getEffect(getInt()); - if (!effect) break; - else invalid = false; - } - else if (effect && KEY_AS("en")) effect->enable = getInt(); - else if (effect && KEY_AS("ef")) parseEffect(effect); - else skip(key); - } - //TODO: remove when all effects were guaranteed. - if (invalid) { - TVGLOG("LOTTIE", "Not supported Layer Effect = %d", effect ? (int)effect->type : -1); - while (auto key = nextObjectKey()) skip(key); - } else layer->effects.push(effect); - } -} - - -LottieLayer* LottieParser::parseLayer(LottieLayer* precomp) -{ - auto layer = new LottieLayer; - - layer->comp = precomp; - context.layer = layer; - - auto ddd = false; - RGB24 color; - - enterObject(); - - while (auto key = nextObjectKey()) { - if (KEY_AS("nm")) - { - layer->name = getStringCopy(); - layer->id = djb2Encode(layer->name); - } - else if (KEY_AS("ddd")) ddd = getInt(); //3d layer - else if (KEY_AS("ind")) layer->idx = getInt(); - else if (KEY_AS("ty")) layer->type = (LottieLayer::Type) getInt(); - else if (KEY_AS("sr")) layer->timeStretch = getFloat(); - else if (KEY_AS("ks")) - { - enterObject(); - layer->transform = parseTransform(ddd); - } - else if (KEY_AS("ao")) layer->autoOrient = getInt(); - else if (KEY_AS("shapes")) parseShapes(layer->children); - else if (KEY_AS("ip")) layer->inFrame = getFloat(); - else if (KEY_AS("op")) layer->outFrame = getFloat(); - else if (KEY_AS("st")) layer->startFrame = getFloat(); - else if (KEY_AS("bm")) layer->blendMethod = (BlendMethod) getInt(); - else if (KEY_AS("parent")) layer->pidx = getInt(); - else if (KEY_AS("tm")) parseTimeRemap(layer); - else if (KEY_AS("w") || KEY_AS("sw")) getLayerSize(layer->w); - else if (KEY_AS("h") || KEY_AS("sh")) getLayerSize(layer->h); - else if (KEY_AS("sc")) color = getColor(getString()); - else if (KEY_AS("tt")) layer->matteType = getMatteType(); - else if (KEY_AS("tp")) layer->mid = getInt(); - else if (KEY_AS("masksProperties")) parseMasks(layer); - else if (KEY_AS("hd")) layer->hidden = getBool(); - else if (KEY_AS("refId")) layer->rid = djb2Encode(getString()); - else if (KEY_AS("td")) layer->matteSrc = getInt(); //used for matte layer - else if (KEY_AS("t")) parseText(layer->children); - else if (KEY_AS("ef")) parseEffects(layer); - else skip(key); - } - - layer->prepare(&color); - - return layer; -} - - -LottieLayer* LottieParser::parseLayers(LottieLayer* root) -{ - auto precomp = new LottieLayer; - - precomp->type = LottieLayer::Precomp; - precomp->comp = root; - - enterArray(); - while (nextArrayValue()) { - precomp->children.push(parseLayer(precomp)); - } - - precomp->prepare(); - return precomp; -} - - -void LottieParser::postProcess(Array& glyphs) -{ - //aggregate font characters - for (uint32_t g = 0; g < glyphs.count; ++g) { - auto glyph = glyphs[g]; - for (uint32_t i = 0; i < comp->fonts.count; ++i) { - auto& font = comp->fonts[i]; - if (!strcmp(font->family, glyph->family) && !strcmp(font->style, glyph->style)) { - font->chars.push(glyph); - free(glyph->family); - free(glyph->style); - break; - } - } - } -} - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -const char* LottieParser::sid(bool first) -{ - if (first) { - //verify json - if (!parseNext()) return nullptr; - enterObject(); - } - return nextObjectKey(); -} - - -bool LottieParser::apply(LottieSlot* slot) -{ - enterObject(); - - //OPTIMIZE: we can create the property directly, without object - LottieObject* obj = nullptr; //slot object - - switch (slot->type) { - case LottieProperty::Type::ColorStop: { - obj = new LottieGradient; - context.parent = obj; - parseSlotProperty(static_cast(obj)->colorStops); - break; - } - case LottieProperty::Type::Color: { - obj = new LottieSolid; - context.parent = obj; - parseSlotProperty(static_cast(obj)->color); - break; - } - case LottieProperty::Type::TextDoc: { - obj = new LottieText; - context.parent = obj; - parseSlotProperty(static_cast(obj)->doc); - break; - } - default: break; - } - - if (!obj || Invalid()) return false; - - slot->assign(obj); - - delete(obj); - - return true; -} - - -bool LottieParser::parse() -{ - //verify json. - if (!parseNext()) return false; - - enterObject(); - - if (comp) delete(comp); - comp = new LottieComposition; - - Array glyphs; - - auto startFrame = 0.0f; - auto endFrame = 0.0f; - - while (auto key = nextObjectKey()) { - if (KEY_AS("v")) comp->version = getStringCopy(); - else if (KEY_AS("fr")) comp->frameRate = getFloat(); - else if (KEY_AS("ip")) startFrame = getFloat(); - else if (KEY_AS("op")) endFrame = getFloat(); - else if (KEY_AS("w")) comp->w = getFloat(); - else if (KEY_AS("h")) comp->h = getFloat(); - else if (KEY_AS("nm")) comp->name = getStringCopy(); - else if (KEY_AS("assets")) parseAssets(); - else if (KEY_AS("layers")) comp->root = parseLayers(comp->root); - else if (KEY_AS("fonts")) parseFonts(); - else if (KEY_AS("chars")) parseChars(glyphs); - else if (KEY_AS("markers")) parseMarkers(); - else skip(key); - } - - if (Invalid() || !comp->root) { - delete(comp); - return false; - } - - comp->root->inFrame = startFrame; - comp->root->outFrame = endFrame; - - postProcess(glyphs); - - return true; -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.h deleted file mode 100644 index 0a3996ef..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParser.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_PARSER_H_ -#define _TVG_LOTTIE_PARSER_H_ - -#include "tvgCommon.h" -#include "tvgLottieParserHandler.h" -#include "tvgLottieProperty.h" - -struct LottieParser : LookaheadParserHandler -{ -public: - LottieParser(const char *str, const char* dirName) : LookaheadParserHandler(str) - { - this->dirName = dirName; - } - - bool parse(); - bool apply(LottieSlot* slot); - const char* sid(bool first = false); - - LottieComposition* comp = nullptr; - const char* dirName = nullptr; //base resource directory - -private: - RGB24 getColor(const char *str); - CompositeMethod getMatteType(); - FillRule getFillRule(); - StrokeCap getStrokeCap(); - StrokeJoin getStrokeJoin(); - CompositeMethod getMaskMethod(bool inversed); - LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out); - LottieEffect* getEffect(int type); - - void getInterpolatorPoint(Point& pt); - void getPathSet(LottiePathSet& path); - void getLayerSize(float& val); - void getValue(TextDocument& doc); - void getValue(PathSet& path); - void getValue(Array& pts); - void getValue(ColorStop& color); - void getValue(float& val); - void getValue(uint8_t& val); - void getValue(int8_t& val); - void getValue(RGB24& color); - bool getValue(Point& pt); - - template bool parseTangent(const char *key, LottieVectorFrame& value); - template bool parseTangent(const char *key, LottieScalarFrame& value); - template void parseKeyFrame(T& prop); - template void parsePropertyInternal(T& prop); - template void parseProperty(T& prop, LottieObject* obj = nullptr); - template void parseSlotProperty(T& prop); - - LottieObject* parseObject(); - LottieObject* parseAsset(); - LottieImage* parseImage(const char* data, const char* subPath, bool embedded, float width, float height); - LottieLayer* parseLayer(LottieLayer* precomp); - LottieObject* parseGroup(); - LottieRect* parseRect(); - LottieEllipse* parseEllipse(); - LottieSolidFill* parseSolidFill(); - LottieTransform* parseTransform(bool ddd = false); - LottieSolidStroke* parseSolidStroke(); - LottieGradientStroke* parseGradientStroke(); - LottiePath* parsePath(); - LottiePolyStar* parsePolyStar(); - LottieRoundedCorner* parseRoundedCorner(); - LottieGradientFill* parseGradientFill(); - LottieLayer* parseLayers(LottieLayer* root); - LottieMask* parseMask(); - LottieTrimpath* parseTrimpath(); - LottieRepeater* parseRepeater(); - LottieOffsetPath* parseOffsetPath(); - LottieFont* parseFont(); - LottieMarker* parseMarker(); - - void parseGaussianBlur(LottieGaussianBlur* effect); - - bool parseDirection(LottieShape* shape, const char* key); - bool parseCommon(LottieObject* obj, const char* key); - void parseObject(Array& parent); - void parseShapes(Array& parent); - void parseText(Array& parent); - void parseMasks(LottieLayer* layer); - void parseEffects(LottieLayer* layer); - void parseTimeRemap(LottieLayer* layer); - void parseStrokeDash(LottieStroke* stroke); - void parseGradient(LottieGradient* gradient, const char* key); - void parseTextRange(LottieText* text); - void parseAssets(); - void parseFonts(); - void parseChars(Array& glyphs); - void parseMarkers(); - void parseEffect(LottieEffect* effect); - void postProcess(Array& glyphs); - - //Current parsing context - struct Context { - LottieLayer* layer = nullptr; - LottieObject* parent = nullptr; - } context; -}; - -#endif //_TVG_LOTTIE_PARSER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.cpp b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.cpp deleted file mode 100644 index dbc73280..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "tvgLottieParserHandler.h" - - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -static const int PARSE_FLAGS = kParseDefaultFlags | kParseInsituFlag; - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - - -bool LookaheadParserHandler::enterArray() -{ - if (state != kEnteringArray) { - Error(); - return false; - } - parseNext(); - return true; -} - - -bool LookaheadParserHandler::nextArrayValue() -{ - if (state == kExitingArray) { - parseNext(); - return false; - } - //SPECIAL CASE: same as nextObjectKey() - if (state == kExitingObject) return false; - if (state == kError || state == kHasKey) { - Error(); - return false; - } - return true; -} - - -int LookaheadParserHandler::getInt() -{ - if (state != kHasNumber) { - Error(); - return 0; - } - auto result = val.GetInt(); - parseNext(); - return result; -} - - -float LookaheadParserHandler::getFloat() -{ - if (state != kHasNumber) { - Error(); - return 0; - } - auto result = val.GetFloat(); - parseNext(); - return result; -} - - -const char* LookaheadParserHandler::getString() -{ - if (state != kHasString) { - Error(); - return nullptr; - } - auto result = val.GetString(); - parseNext(); - return result; -} - - -char* LookaheadParserHandler::getStringCopy() -{ - auto str = getString(); - if (str) return strdup(str); - return nullptr; -} - - -bool LookaheadParserHandler::getBool() -{ - if (state != kHasBool) { - Error(); - return false; - } - auto result = val.GetBool(); - parseNext(); - return result; -} - - -void LookaheadParserHandler::getNull() -{ - if (state != kHasNull) { - Error(); - return; - } - parseNext(); -} - - -bool LookaheadParserHandler::parseNext() -{ - if (reader.HasParseError()) { - Error(); - return false; - } - if (!reader.IterativeParseNext(iss, *this)) { - Error(); - return false; - } - return true; -} - - -bool LookaheadParserHandler::enterObject() -{ - if (state != kEnteringObject) { - Error(); - return false; - } - parseNext(); - return true; -} - - -int LookaheadParserHandler::peekType() -{ - if (state >= kHasNull && state <= kHasKey) return val.GetType(); - if (state == kEnteringArray) return kArrayType; - if (state == kEnteringObject) return kObjectType; - return -1; -} - - -void LookaheadParserHandler::skipOut(int depth) -{ - do { - if (state == kEnteringArray || state == kEnteringObject) ++depth; - else if (state == kExitingArray || state == kExitingObject) --depth; - else if (state == kError) return; - parseNext(); - } while (depth > 0); -} - - -const char* LookaheadParserHandler::nextObjectKey() -{ - if (state == kHasKey) { - auto result = val.GetString(); - parseNext(); - return result; - } - - /* SPECIAL CASE: The parser works with a predefined rule that it will be only - while (nextObjectKey()) for each object but in case of our nested group - object we can call multiple time nextObjectKey() while exiting the object - so ignore those and don't put parser in the error state. */ - if (state == kExitingArray || state == kEnteringObject) return nullptr; - - if (state != kExitingObject) { - Error(); - return nullptr; - } - - parseNext(); - return nullptr; -} - - -void LookaheadParserHandler::skip(const char* key) -{ - //if (key) TVGLOG("LOTTIE", "Skipped parsing value = %s", key); - - if (peekType() == kArrayType) { - enterArray(); - skipOut(1); - } else if (peekType() == kObjectType) { - enterObject(); - skipOut(1); - } else { - skipOut(0); - } -} diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.h deleted file mode 100644 index 211268b5..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieParserHandler.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_PARSER_HANDLER_H_ -#define _TVG_LOTTIE_PARSER_HANDLER_H_ - -#include "rapidjson/document.h" -#include "tvgCommon.h" - - -using namespace rapidjson; - - -struct LookaheadParserHandler -{ - enum LookaheadParsingState { - kInit = 0, - kError, - kHasNull, - kHasBool, - kHasNumber, - kHasString, - kHasKey, - kEnteringObject, - kExitingObject, - kEnteringArray, - kExitingArray - }; - - Value val; - LookaheadParsingState state = kInit; - Reader reader; - InsituStringStream iss; - - LookaheadParserHandler(const char *str) : iss((char*)str) - { - reader.IterativeParseInit(); - } - - bool Null() - { - state = kHasNull; - val.SetNull(); - return true; - } - - bool Bool(bool b) - { - state = kHasBool; - val.SetBool(b); - return true; - } - - bool Int(int i) - { - state = kHasNumber; - val.SetInt(i); - return true; - } - - bool Uint(unsigned u) - { - state = kHasNumber; - val.SetUint(u); - return true; - } - - bool Int64(int64_t i) - { - state = kHasNumber; - val.SetInt64(i); - return true; - } - - bool Uint64(int64_t u) - { - state = kHasNumber; - val.SetUint64(u); - return true; - } - - bool Double(double d) - { - state = kHasNumber; - val.SetDouble(d); - return true; - } - - bool RawNumber(const char *, SizeType, TVG_UNUSED bool) - { - return false; - } - - bool String(const char *str, SizeType length, TVG_UNUSED bool) - { - state = kHasString; - val.SetString(str, length); - return true; - } - - bool StartObject() - { - state = kEnteringObject; - return true; - } - - bool Key(const char *str, SizeType length, TVG_UNUSED bool) - { - state = kHasKey; - val.SetString(str, length); - return true; - } - - bool EndObject(SizeType) - { - state = kExitingObject; - return true; - } - - bool StartArray() - { - state = kEnteringArray; - return true; - } - - bool EndArray(SizeType) - { - state = kExitingArray; - return true; - } - - void Error() - { - TVGERR("LOTTIE", "Parsing Error!"); - state = kError; - } - - bool Invalid() - { - return state == kError; - } - - bool enterObject(); - bool enterArray(); - bool nextArrayValue(); - int getInt(); - float getFloat(); - const char* getString(); - char* getStringCopy(); - bool getBool(); - void getNull(); - bool parseNext(); - const char* nextObjectKey(); - void skip(const char* key); - void skipOut(int depth); - int peekType(); -}; - -#endif //_TVG_LOTTIE_PARSER_HANDLER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieProperty.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieProperty.h deleted file mode 100644 index 8190326b..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieProperty.h +++ /dev/null @@ -1,838 +0,0 @@ -/* - * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_PROPERTY_H_ -#define _TVG_LOTTIE_PROPERTY_H_ - -#include -#include "tvgMath.h" -#include "tvgLottieCommon.h" -#include "tvgLottieInterpolator.h" -#include "tvgLottieExpressions.h" -#include "tvgLottieModifier.h" - - -struct LottieFont; -struct LottieLayer; -struct LottieObject; - - -template -struct LottieScalarFrame -{ - T value; //keyframe value - float no; //frame number - LottieInterpolator* interpolator; - bool hold = false; //do not interpolate. - - T interpolate(LottieScalarFrame* next, float frameNo) - { - auto t = (frameNo - no) / (next->no - no); - if (interpolator) t = interpolator->progress(t); - - if (hold) { - if (t < 1.0f) return value; - else return next->value; - } - return lerp(value, next->value, t); - } -}; - - -template -struct LottieVectorFrame -{ - T value; //keyframe value - float no; //frame number - LottieInterpolator* interpolator; - T outTangent, inTangent; - float length; - bool hasTangent = false; - bool hold = false; - - T interpolate(LottieVectorFrame* next, float frameNo) - { - auto t = (frameNo - no) / (next->no - no); - if (interpolator) t = interpolator->progress(t); - - if (hold) { - if (t < 1.0f) return value; - else return next->value; - } - - if (hasTangent) { - Bezier bz = {value, value + outTangent, next->value + inTangent, next->value}; - return bz.at(bz.atApprox(t * length, length)); - } else { - return lerp(value, next->value, t); - } - } - - float angle(LottieVectorFrame* next, float frameNo) - { - if (!hasTangent) { - Point dp = next->value - value; - return rad2deg(tvg::atan2(dp.y, dp.x)); - } - - auto t = (frameNo - no) / (next->no - no); - if (interpolator) t = interpolator->progress(t); - Bezier bz = {value, value + outTangent, next->value + inTangent, next->value}; - t = bz.atApprox(t * length, length); - return bz.angle(t >= 1.0f ? 0.99f : (t <= 0.0f ? 0.01f : t)); - } - - void prepare(LottieVectorFrame* next) - { - Bezier bz = {value, value + outTangent, next->value + inTangent, next->value}; - length = bz.lengthApprox(); - } -}; - - -//Property would have an either keyframes or single value. -struct LottieProperty -{ - enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Invalid }; - - LottieExpression* exp = nullptr; - Type type; - uint8_t ix; //property index - - //TODO: Apply common bodies? - virtual ~LottieProperty() {} - virtual uint32_t frameCnt() = 0; - virtual uint32_t nearest(float time) = 0; - virtual float frameNo(int32_t key) = 0; -}; - - -struct LottieExpression -{ - enum LoopMode : uint8_t { None = 0, InCycle = 1, InPingPong, InOffset, InContinue, OutCycle, OutPingPong, OutOffset, OutContinue }; - - char* code; - LottieComposition* comp; - LottieLayer* layer; - LottieObject* object; - LottieProperty* property; - bool disabled = false; - - struct { - uint32_t key = 0; //the keyframe number repeating to - float in = FLT_MAX; //looping duration in frame number - LoopMode mode = None; - } loop; - - ~LottieExpression() - { - free(code); - } -}; - - -static void _copy(PathSet* pathset, Array& outPts, Matrix* transform) -{ - Array inPts; - - if (transform) { - for (int i = 0; i < pathset->ptsCnt; ++i) { - Point pt = pathset->pts[i]; - pt *= *transform; - outPts.push(pt); - } - } else { - inPts.data = pathset->pts; - inPts.count = pathset->ptsCnt; - outPts.push(inPts); - inPts.data = nullptr; - } -} - - -static void _copy(PathSet* pathset, Array& outCmds) -{ - Array inCmds; - inCmds.data = pathset->cmds; - inCmds.count = pathset->cmdsCnt; - outCmds.push(inCmds); - inCmds.data = nullptr; -} - - -template -uint32_t _bsearch(T* frames, float frameNo) -{ - int32_t low = 0; - int32_t high = int32_t(frames->count) - 1; - - while (low <= high) { - auto mid = low + (high - low) / 2; - auto frame = frames->data + mid; - if (frameNo < frame->no) high = mid - 1; - else low = mid + 1; - } - if (high < low) low = high; - if (low < 0) low = 0; - return low; -} - - -template -uint32_t _nearest(T* frames, float frameNo) -{ - if (frames) { - auto key = _bsearch(frames, frameNo); - if (key == frames->count - 1) return key; - return (fabsf(frames->data[key].no - frameNo) < fabsf(frames->data[key + 1].no - frameNo)) ? key : (key + 1); - } - return 0; -} - - -template -float _frameNo(T* frames, int32_t key) -{ - if (!frames) return 0.0f; - if (key < 0) key = 0; - if (key >= (int32_t) frames->count) key = (int32_t)(frames->count - 1); - return (*frames)[key].no; -} - - -template -float _loop(T* frames, float frameNo, LottieExpression* exp) -{ - if (frameNo >= exp->loop.in || frameNo < frames->first().no || frameNo < frames->last().no) return frameNo; - - frameNo -= frames->first().no; - - switch (exp->loop.mode) { - case LottieExpression::LoopMode::InCycle: { - return fmodf(frameNo, frames->last().no - frames->first().no) + (*frames)[exp->loop.key].no; - } - case LottieExpression::LoopMode::InPingPong: { - auto range = frames->last().no - (*frames)[exp->loop.key].no; - auto forward = (static_cast(frameNo / range) % 2) == 0 ? true : false; - frameNo = fmodf(frameNo, range); - return (forward ? frameNo : (range - frameNo)) + (*frames)[exp->loop.key].no; - } - case LottieExpression::LoopMode::OutCycle: { - return fmodf(frameNo, (*frames)[frames->count - 1 - exp->loop.key].no - frames->first().no) + frames->first().no; - } - case LottieExpression::LoopMode::OutPingPong: { - auto range = (*frames)[frames->count - 1 - exp->loop.key].no - frames->first().no; - auto forward = (static_cast(frameNo / range) % 2) == 0 ? true : false; - frameNo = fmodf(frameNo, range); - return (forward ? frameNo : (range - frameNo)) + frames->first().no; - } - default: break; - } - return frameNo; -} - - -template -struct LottieGenericProperty : LottieProperty -{ - //Property has an either keyframes or single value. - Array>* frames = nullptr; - T value; - - LottieGenericProperty(T v) : value(v) {} - LottieGenericProperty() {} - - ~LottieGenericProperty() - { - release(); - } - - void release() - { - delete(frames); - frames = nullptr; - if (exp) { - delete(exp); - exp = nullptr; - } - } - - uint32_t nearest(float frameNo) override - { - return _nearest(frames, frameNo); - } - - uint32_t frameCnt() override - { - return frames ? frames->count : 1; - } - - float frameNo(int32_t key) override - { - return _frameNo(frames, key); - } - - LottieScalarFrame& newFrame() - { - if (!frames) frames = new Array>; - if (frames->count + 1 >= frames->reserved) { - auto old = frames->reserved; - frames->grow(frames->count + 2); - memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame) * (frames->reserved - old)); - } - ++frames->count; - return frames->last(); - } - - LottieScalarFrame& nextFrame() - { - return (*frames)[frames->count]; - } - - T operator()(float frameNo) - { - if (!frames) return value; - if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value; - if (frameNo >= frames->last().no) return frames->last().value; - - auto frame = frames->data + _bsearch(frames, frameNo); - if (tvg::equal(frame->no, frameNo)) return frame->value; - return frame->interpolate(frame + 1, frameNo); - } - - T operator()(float frameNo, LottieExpressions* exps) - { - if (exps && exp) { - T out{}; - if (exp->loop.mode != LottieExpression::LoopMode::None) frameNo = _loop(frames, frameNo, exp); - if (exps->result>(frameNo, out, exp)) return out; - } - return operator()(frameNo); - } - - LottieGenericProperty& operator=(const LottieGenericProperty& other) - { - //shallow copy, used for slot overriding - if (other.frames) { - frames = other.frames; - const_cast&>(other).frames = nullptr; - } else value = other.value; - return *this; - } - - float angle(float frameNo) { return 0; } - void prepare() {} -}; - - -struct LottiePathSet : LottieProperty -{ - Array>* frames = nullptr; - PathSet value; - - ~LottiePathSet() - { - release(); - } - - void release() - { - if (exp) { - delete(exp); - exp = nullptr; - } - - free(value.cmds); - free(value.pts); - - if (!frames) return; - - for (auto p = frames->begin(); p < frames->end(); ++p) { - free((*p).value.cmds); - free((*p).value.pts); - } - free(frames->data); - free(frames); - } - - uint32_t nearest(float frameNo) override - { - return _nearest(frames, frameNo); - } - - uint32_t frameCnt() override - { - return frames ? frames->count : 1; - } - - float frameNo(int32_t key) override - { - return _frameNo(frames, key); - } - - LottieScalarFrame& newFrame() - { - if (!frames) { - frames = static_cast>*>(calloc(1, sizeof(Array>))); - } - if (frames->count + 1 >= frames->reserved) { - auto old = frames->reserved; - frames->grow(frames->count + 2); - memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame) * (frames->reserved - old)); - } - ++frames->count; - return frames->last(); - } - - LottieScalarFrame& nextFrame() - { - return (*frames)[frames->count]; - } - - bool operator()(float frameNo, Array& cmds, Array& pts, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offsetPath) - { - PathSet* path = nullptr; - LottieScalarFrame* frame = nullptr; - float t; - bool interpolate = false; - - if (!frames) path = &value; - else if (frames->count == 1 || frameNo <= frames->first().no) path = &frames->first().value; - else if (frameNo >= frames->last().no) path = &frames->last().value; - else { - frame = frames->data + _bsearch(frames, frameNo); - if (tvg::equal(frame->no, frameNo)) path = &frame->value; - else if (frame->value.ptsCnt != (frame + 1)->value.ptsCnt) { - path = &frame->value; - TVGLOG("LOTTIE", "Different numbers of points in consecutive frames - interpolation omitted."); - } else { - t = (frameNo - frame->no) / ((frame + 1)->no - frame->no); - if (frame->interpolator) t = frame->interpolator->progress(t); - if (frame->hold) path = &(frame + ((t < 1.0f) ? 0 : 1))->value; - else interpolate = true; - } - } - - if (!interpolate) { - if (roundness) { - if (offsetPath) { - Array cmds1(path->cmdsCnt); - Array pts1(path->ptsCnt); - roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds1, pts1, transform); - return offsetPath->modifyPath(cmds1.data, cmds1.count, pts1.data, pts1.count, cmds, pts); - } - return roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds, pts, transform); - } - if (offsetPath) return offsetPath->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds, pts); - - _copy(path, cmds); - _copy(path, pts, transform); - return true; - } - - auto s = frame->value.pts; - auto e = (frame + 1)->value.pts; - - if (!roundness && !offsetPath) { - for (auto i = 0; i < frame->value.ptsCnt; ++i, ++s, ++e) { - auto pt = lerp(*s, *e, t); - if (transform) pt *= *transform; - pts.push(pt); - } - _copy(&frame->value, cmds); - return true; - } - - auto interpPts = (Point*)malloc(frame->value.ptsCnt * sizeof(Point)); - auto p = interpPts; - for (auto i = 0; i < frame->value.ptsCnt; ++i, ++s, ++e, ++p) { - *p = lerp(*s, *e, t); - if (transform) *p *= *transform; - } - - if (roundness) { - if (offsetPath) { - Array cmds1; - Array pts1; - roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds1, pts1, nullptr); - offsetPath->modifyPath(cmds1.data, cmds1.count, pts1.data, pts1.count, cmds, pts); - } else roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds, pts, nullptr); - } else if (offsetPath) offsetPath->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds, pts); - - free(interpPts); - - return true; - } - - - bool operator()(float frameNo, Array& cmds, Array& pts, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offsetPath, LottieExpressions* exps) - { - if (exps && exp) { - if (exp->loop.mode != LottieExpression::LoopMode::None) frameNo = _loop(frames, frameNo, exp); - if (exps->result(frameNo, cmds, pts, transform, roundness, offsetPath, exp)) return true; - } - return operator()(frameNo, cmds, pts, transform, roundness, offsetPath); - } - - void prepare() {} -}; - - -struct LottieColorStop : LottieProperty -{ - Array>* frames = nullptr; - ColorStop value; - uint16_t count = 0; //colorstop count - bool populated = false; - - ~LottieColorStop() - { - release(); - } - - void release() - { - if (exp) { - delete(exp); - exp = nullptr; - } - - if (value.data) { - free(value.data); - value.data = nullptr; - } - - if (!frames) return; - - for (auto p = frames->begin(); p < frames->end(); ++p) { - free((*p).value.data); - } - free(frames->data); - free(frames); - frames = nullptr; - } - - uint32_t nearest(float frameNo) override - { - return _nearest(frames, frameNo); - } - - uint32_t frameCnt() override - { - return frames ? frames->count : 1; - } - - float frameNo(int32_t key) override - { - return _frameNo(frames, key); - } - - LottieScalarFrame& newFrame() - { - if (!frames) { - frames = static_cast>*>(calloc(1, sizeof(Array>))); - } - if (frames->count + 1 >= frames->reserved) { - auto old = frames->reserved; - frames->grow(frames->count + 2); - memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame) * (frames->reserved - old)); - } - ++frames->count; - return frames->last(); - } - - LottieScalarFrame& nextFrame() - { - return (*frames)[frames->count]; - } - - Result operator()(float frameNo, Fill* fill, LottieExpressions* exps) - { - if (exps && exp) { - if (exp->loop.mode != LottieExpression::LoopMode::None) frameNo = _loop(frames, frameNo, exp); - if (exps->result(frameNo, fill, exp)) return Result::Success; - } - - if (!frames) return fill->colorStops(value.data, count); - - if (frames->count == 1 || frameNo <= frames->first().no) { - return fill->colorStops(frames->first().value.data, count); - } - - if (frameNo >= frames->last().no) { - return fill->colorStops(frames->last().value.data, count); - } - - auto frame = frames->data + _bsearch(frames, frameNo); - if (tvg::equal(frame->no, frameNo)) return fill->colorStops(frame->value.data, count); - - //interpolate - auto t = (frameNo - frame->no) / ((frame + 1)->no - frame->no); - if (frame->interpolator) t = frame->interpolator->progress(t); - - if (frame->hold) { - if (t < 1.0f) fill->colorStops(frame->value.data, count); - else fill->colorStops((frame + 1)->value.data, count); - } - - auto s = frame->value.data; - auto e = (frame + 1)->value.data; - - Array result; - - for (auto i = 0; i < count; ++i, ++s, ++e) { - auto offset = lerp(s->offset, e->offset, t); - auto r = lerp(s->r, e->r, t); - auto g = lerp(s->g, e->g, t); - auto b = lerp(s->b, e->b, t); - auto a = lerp(s->a, e->a, t); - result.push({offset, r, g, b, a}); - } - return fill->colorStops(result.data, count); - } - - LottieColorStop& operator=(const LottieColorStop& other) - { - //shallow copy, used for slot overriding - if (other.frames) { - frames = other.frames; - const_cast(other).frames = nullptr; - } else { - value = other.value; - const_cast(other).value = {nullptr, nullptr}; - } - populated = other.populated; - count = other.count; - - return *this; - } - - void prepare() {} -}; - - -struct LottiePosition : LottieProperty -{ - Array>* frames = nullptr; - Point value; - - LottiePosition(Point v) : value(v) - { - } - - ~LottiePosition() - { - release(); - } - - void release() - { - delete(frames); - frames = nullptr; - - if (exp) { - delete(exp); - exp = nullptr; - } - } - - uint32_t nearest(float frameNo) override - { - return _nearest(frames, frameNo); - } - - uint32_t frameCnt() override - { - return frames ? frames->count : 1; - } - - float frameNo(int32_t key) override - { - return _frameNo(frames, key); - } - - LottieVectorFrame& newFrame() - { - if (!frames) frames = new Array>; - if (frames->count + 1 >= frames->reserved) { - auto old = frames->reserved; - frames->grow(frames->count + 2); - memset((void*)(frames->data + old), 0x00, sizeof(LottieVectorFrame) * (frames->reserved - old)); - } - ++frames->count; - return frames->last(); - } - - LottieVectorFrame& nextFrame() - { - return (*frames)[frames->count]; - } - - Point operator()(float frameNo) - { - if (!frames) return value; - if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value; - if (frameNo >= frames->last().no) return frames->last().value; - - auto frame = frames->data + _bsearch(frames, frameNo); - if (tvg::equal(frame->no, frameNo)) return frame->value; - return frame->interpolate(frame + 1, frameNo); - } - - Point operator()(float frameNo, LottieExpressions* exps) - { - Point out{}; - if (exps && exp) { - if (exp->loop.mode != LottieExpression::LoopMode::None) frameNo = _loop(frames, frameNo, exp); - if (exps->result(frameNo, out, exp)) return out; - } - return operator()(frameNo); - } - - float angle(float frameNo) - { - if (!frames || frames->count == 1) return 0; - - if (frameNo <= frames->first().no) return frames->first().angle(frames->data + 1, frames->first().no); - if (frameNo >= frames->last().no) { - auto frame = frames->data + frames->count - 2; - return frame->angle(frame + 1, frames->last().no); - } - - auto frame = frames->data + _bsearch(frames, frameNo); - return frame->angle(frame + 1, frameNo); - } - - void prepare() - { - if (!frames || frames->count < 2) return; - for (auto frame = frames->begin() + 1; frame < frames->end(); ++frame) { - (frame - 1)->prepare(frame); - } - } -}; - - -struct LottieTextDoc : LottieProperty -{ - Array>* frames = nullptr; - TextDocument value; - - ~LottieTextDoc() - { - release(); - } - - void release() - { - if (exp) { - delete(exp); - exp = nullptr; - } - - if (value.text) { - free(value.text); - value.text = nullptr; - } - if (value.name) { - free(value.name); - value.name = nullptr; - } - - if (!frames) return; - - for (auto p = frames->begin(); p < frames->end(); ++p) { - free((*p).value.text); - free((*p).value.name); - } - delete(frames); - frames = nullptr; - } - - uint32_t nearest(float frameNo) override - { - return _nearest(frames, frameNo); - } - - uint32_t frameCnt() override - { - return frames ? frames->count : 1; - } - - float frameNo(int32_t key) override - { - return _frameNo(frames, key); - } - - LottieScalarFrame& newFrame() - { - if (!frames) frames = new Array>; - if (frames->count + 1 >= frames->reserved) { - auto old = frames->reserved; - frames->grow(frames->count + 2); - memset((void*)(frames->data + old), 0x00, sizeof(LottieScalarFrame) * (frames->reserved - old)); - } - ++frames->count; - return frames->last(); - } - - LottieScalarFrame& nextFrame() - { - return (*frames)[frames->count]; - } - - TextDocument& operator()(float frameNo) - { - if (!frames) return value; - if (frames->count == 1 || frameNo <= frames->first().no) return frames->first().value; - if (frameNo >= frames->last().no) return frames->last().value; - - auto frame = frames->data + _bsearch(frames, frameNo); - return frame->value; - } - - LottieTextDoc& operator=(const LottieTextDoc& other) - { - //shallow copy, used for slot overriding - if (other.frames) { - frames = other.frames; - const_cast(other).frames = nullptr; - } else { - value = other.value; - const_cast(other).value.text = nullptr; - const_cast(other).value.name = nullptr; - } - return *this; - } - - void prepare() {} -}; - - -using LottiePoint = LottieGenericProperty; -using LottieFloat = LottieGenericProperty; -using LottieOpacity = LottieGenericProperty; -using LottieColor = LottieGenericProperty; -using LottieSlider = LottieFloat; -using LottieCheckbox = LottieGenericProperty; - -#endif //_TVG_LOTTIE_PROPERTY_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieRenderPooler.h b/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieRenderPooler.h deleted file mode 100644 index b26eeac4..00000000 --- a/godot/thirdparty/thorvg/src/loaders/lottie/tvgLottieRenderPooler.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2024 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LOTTIE_RENDER_POOLER_H_ -#define _TVG_LOTTIE_RENDER_POOLER_H_ - -#include "tvgCommon.h" -#include "tvgArray.h" -#include "tvgPaint.h" - - -template -struct LottieRenderPooler -{ - Array pooler; - - ~LottieRenderPooler() - { - for (auto p = pooler.begin(); p < pooler.end(); ++p) { - if (PP(*p)->unref() == 0) delete(*p); - } - } - - T* pooling(bool copy = false) - { - //return available one. - for (auto p = pooler.begin(); p < pooler.end(); ++p) { - if (PP(*p)->refCnt == 1) return *p; - } - - //no empty, generate a new one. - auto p = copy ? static_cast(pooler[0]->duplicate()) : T::gen().release(); - PP(p)->ref(); - pooler.push(p); - return p; - } -}; - -#endif //_TVG_LOTTIE_RENDER_POOLER_H_ diff --git a/godot/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/godot/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index baae588e..1ab3043c 100644 --- a/godot/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/godot/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -2555,6 +2555,18 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char } +static SvgColor* _findLatestColor(const SvgLoaderData* loader) +{ + auto parent = loader->stack.count > 0 ? loader->stack.last() : loader->doc; + + while (parent != nullptr) { + if (parent->style->curColorSet) return &parent->style->color; + parent = parent->parent; + } + return nullptr; +} + + static bool _attrParseStopsStyle(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; @@ -2564,7 +2576,13 @@ static bool _attrParseStopsStyle(void* data, const char* key, const char* value) stop->a = _toOpacity(value); loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopOpacity); } else if (!strcmp(key, "stop-color")) { - if (_toColor(value, &stop->r, &stop->g, &stop->b, nullptr)) { + if (!strcmp(value, "currentColor")) { + if (auto latestColor = _findLatestColor(loader)) { + stop->r = latestColor->r; + stop->g = latestColor->g; + stop->b = latestColor->b; + } + } else if (_toColor(value, &stop->r, &stop->g, &stop->b, nullptr)) { loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopColor); } } else { @@ -2587,7 +2605,13 @@ static bool _attrParseStops(void* data, const char* key, const char* value) stop->a = _toOpacity(value); } } else if (!strcmp(key, "stop-color")) { - if (!(loader->svgParse->flags & SvgStopStyleFlags::StopColor)) { + if (!strcmp(value, "currentColor")) { + if (auto latestColor = _findLatestColor(loader)) { + stop->r = latestColor->r; + stop->g = latestColor->g; + stop->b = latestColor->b; + } + } else if (!(loader->svgParse->flags & SvgStopStyleFlags::StopColor)) { _toColor(value, &stop->r, &stop->g, &stop->b, nullptr); } } else if (!strcmp(key, "style")) { diff --git a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index 74b38330..9371ae6c 100644 --- a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -568,13 +568,17 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity); bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h, pixel_t val = 0); void rasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len); +void rasterTranslucentPixel32(uint32_t* dst, uint32_t* src, uint32_t len, uint8_t opacity); +void rasterPixel32(uint32_t* dst, uint32_t* src, uint32_t len, uint8_t opacity); void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len); void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32_t h, const SwBBox& bbox, bool flipped); void rasterUnpremultiply(RenderSurface* surface); void rasterPremultiply(RenderSurface* surface); bool rasterConvertCS(RenderSurface* surface, ColorSpace to); -bool effectGaussianBlur(SwImage& image, SwImage& buffer, const SwBBox& bbox, const RenderEffectGaussian* params); -bool effectGaussianPrepare(RenderEffectGaussian* effect); +bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params); +bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* effect); +bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, uint8_t opacity, bool direct); +bool effectDropShadowPrepare(RenderEffectDropShadow* effect); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp index d2d16ff2..fd8e532e 100644 --- a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp +++ b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwPostEffect.cpp @@ -20,10 +20,11 @@ * SOFTWARE. */ +#include "tvgMath.h" #include "tvgSwCommon.h" /************************************************************************/ -/* Gaussian Filter Implementation */ +/* Gaussian Blur Implementation */ /************************************************************************/ struct SwGaussianBlur @@ -48,49 +49,59 @@ static void _gaussianExtendRegion(RenderRegion& region, int extra, int8_t direct } -static int _gaussianRemap(int end, int idx, int border) +static int _gaussianEdgeWrap(int end, int idx) { - //wrap - if (border == 1) return idx % end; + auto r = idx % end; + return (r < 0) ? end + r : r; +} - //duplicate + +static int _gaussianEdgeExtend(int end, int idx) +{ if (idx < 0) return 0; else if (idx >= end) return end - 1; return idx; } +static int _gaussianRemap(int end, int idx, int border) +{ + if (border == 1) return _gaussianEdgeWrap(end, idx); + return _gaussianEdgeExtend(end, idx); +} + + //TODO: SIMD OPTIMIZATION? -static void _gaussianBlur(uint8_t* src, uint8_t* dst, int32_t stride, int32_t w, int32_t h, const SwBBox& bbox, int32_t dimension, int border, bool flipped) +static void _gaussianFilter(uint8_t* dst, uint8_t* src, int32_t stride, int32_t w, int32_t h, const SwBBox& bbox, int32_t dimension, int border, bool flipped) { if (flipped) { - src += ((bbox.min.x * stride) + bbox.min.y) << 2; - dst += ((bbox.min.x * stride) + bbox.min.y) << 2; + src += (bbox.min.x * stride + bbox.min.y) << 2; + dst += (bbox.min.x * stride + bbox.min.y) << 2; } else { - src += ((bbox.min.y * stride) + bbox.min.x) << 2; - dst += ((bbox.min.y * stride) + bbox.min.x) << 2; + src += (bbox.min.y * stride + bbox.min.x) << 2; + dst += (bbox.min.y * stride + bbox.min.x) << 2; } auto iarr = 1.0f / (dimension + dimension + 1); #pragma omp parallel for - for (int x = 0; x < h; x++) { - auto p = x * stride; + for (int y = 0; y < h; ++y) { + auto p = y * stride; auto i = p * 4; //current index auto l = -(dimension + 1); //left index auto r = dimension; //right index int acc[4] = {0, 0, 0, 0}; //sliding accumulator - //initial acucmulation - for (int x2 = l; x2 < r; ++x2) { - auto id = (_gaussianRemap(w, x2, border) + p) * 4; + //initial accumulation + for (int x = l; x < r; ++x) { + auto id = (_gaussianRemap(w, x, border) + p) * 4; acc[0] += src[id++]; acc[1] += src[id++]; acc[2] += src[id++]; acc[3] += src[id]; } //perform filtering - for (int x2 = 0; x2 < w; ++x2, ++r, ++l) { + for (int x = 0; x < w; ++x, ++r, ++l) { auto rid = (_gaussianRemap(w, r, border) + p) * 4; auto lid = (_gaussianRemap(w, l, border) + p) * 4; acc[0] += src[rid++] - src[lid++]; @@ -106,11 +117,15 @@ static void _gaussianBlur(uint8_t* src, uint8_t* dst, int32_t stride, int32_t w, } -static int _gaussianInit(int* kernel, float sigma, int level) +static int _gaussianInit(SwGaussianBlur* data, float sigma, int quality) { const auto MAX_LEVEL = SwGaussianBlur::MAX_LEVEL; - //compute the kernel + if (tvg::zero(sigma)) return 0; + + data->level = int(SwGaussianBlur::MAX_LEVEL * ((quality - 1) * 0.01f)) + 1; + + //compute box kernel sizes auto wl = (int) sqrt((12 * sigma / MAX_LEVEL) + 1); if (wl % 2 == 0) --wl; auto wu = wl + 2; @@ -118,92 +133,278 @@ static int _gaussianInit(int* kernel, float sigma, int level) auto m = int(mi + 0.5f); auto extends = 0; - for (int i = 0; i < level; i++) { - kernel[i] = ((i < m ? wl : wu) - 1) / 2; - extends += kernel[i]; + for (int i = 0; i < data->level; i++) { + data->kernel[i] = ((i < m ? wl : wu) - 1) / 2; + extends += data->kernel[i]; } return extends; } -bool effectGaussianPrepare(RenderEffectGaussian* params) +bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params) { - auto data = (SwGaussianBlur*)malloc(sizeof(SwGaussianBlur)); + auto rd = (SwGaussianBlur*)malloc(sizeof(SwGaussianBlur)); - //compute box kernel sizes - data->level = int(SwGaussianBlur::MAX_LEVEL * ((params->quality - 1) * 0.01f)) + 1; - auto extends = _gaussianInit(data->kernel, params->sigma * params->sigma, data->level); + auto extends = _gaussianInit(rd, params->sigma * params->sigma, params->quality); - //skip, if the parameters are invalid. + //invalid if (extends == 0) { params->invalid = true; - free(data); + free(rd); return false; } _gaussianExtendRegion(params->extend, extends, params->direction); - params->rd = data; + params->rd = rd; return true; } -/* It is best to take advantage of the Gaussian blur’s separable property - by dividing the process into two passes. horizontal and vertical. - We can expect fewer calculations. */ -bool effectGaussianBlur(SwImage& image, SwImage& buffer, const SwBBox& bbox, const RenderEffectGaussian* params) +bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params) { - if (params->invalid) return false; - - if (image.channelSize != sizeof(uint32_t)) { + if (cmp->image.channelSize != sizeof(uint32_t)) { TVGERR("SW_ENGINE", "Not supported grayscale Gaussian Blur!"); return false; } + auto& buffer = surface->compositor->image; auto data = static_cast(params->rd); + auto& bbox = cmp->bbox; auto w = (bbox.max.x - bbox.min.x); auto h = (bbox.max.y - bbox.min.y); - auto stride = image.stride; - auto front = image.buf8; - auto back = buffer.buf8; + auto stride = cmp->image.stride; + auto front = cmp->image.buf32; + auto back = buffer.buf32; auto swapped = false; - //fine-tuning for low-quality (experimental) - auto threshold = (std::min(w, h) < 300) ? 2 : 1; - TVGLOG("SW_ENGINE", "GaussianFilter region(%ld, %ld, %ld, %ld) params(%f %d %d), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->sigma, params->direction, params->border, data->level); + /* It is best to take advantage of the Gaussian blur’s separable property + by dividing the process into two passes. horizontal and vertical. + We can expect fewer calculations. */ + //horizontal - if (params->direction == 0 || params->direction == 1) { + if (params->direction != 2) { for (int i = 0; i < data->level; ++i) { - auto k = data->kernel[i] / threshold; - if (k == 0) continue; - _gaussianBlur(front, back, stride, w, h, bbox, k, params->border, false); + _gaussianFilter(reinterpret_cast(back), reinterpret_cast(front), stride, w, h, bbox, data->kernel[i], params->border, false); std::swap(front, back); swapped = !swapped; } } //vertical. x/y flipping and horionztal access is pretty compatible with the memory architecture. - if (params->direction == 0 || params->direction == 2) { - rasterXYFlip(reinterpret_cast(front), reinterpret_cast(back), stride, w, h, bbox, false); + if (params->direction != 1) { + rasterXYFlip(front, back, stride, w, h, bbox, false); std::swap(front, back); for (int i = 0; i < data->level; ++i) { - auto k = data->kernel[i] / threshold; - if (k == 0) continue; - _gaussianBlur(front, back, stride, h, w, bbox, k, params->border, true); + _gaussianFilter(reinterpret_cast(back), reinterpret_cast(front), stride, h, w, bbox, data->kernel[i], params->border, true); std::swap(front, back); swapped = !swapped; } - rasterXYFlip(reinterpret_cast(front), reinterpret_cast(back), stride, h, w, bbox, true); + rasterXYFlip(front, back, stride, h, w, bbox, true); std::swap(front, back); } - if (swapped) std::swap(image.buf8, buffer.buf8); + if (swapped) std::swap(cmp->image.buf8, buffer.buf8); + + return true; +} + +/************************************************************************/ +/* Drop Shadow Implementation */ +/************************************************************************/ + +struct SwDropShadow : SwGaussianBlur +{ + SwPoint offset; +}; + + +//TODO: SIMD OPTIMIZATION? +static void _dropShadowFilter(uint32_t* dst, uint32_t* src, int stride, int w, int h, const SwBBox& bbox, int32_t dimension, uint32_t color, bool flipped) +{ + if (flipped) { + src += (bbox.min.x * stride + bbox.min.y); + dst += (bbox.min.x * stride + bbox.min.y); + } else { + src += (bbox.min.y * stride + bbox.min.x); + dst += (bbox.min.y * stride + bbox.min.x); + } + auto iarr = 1.0f / (dimension + dimension + 1); + + #pragma omp parallel for + for (int y = 0; y < h; ++y) { + auto p = y * stride; + auto i = p; //current index + auto l = -(dimension + 1); //left index + auto r = dimension; //right index + int acc = 0; //sliding accumulator + + //initial accumulation + for (int x = l; x < r; ++x) { + auto id = _gaussianEdgeExtend(w, x) + p; + acc += A(src[id]); + } + //perform filtering + for (int x = 0; x < w; ++x, ++r, ++l) { + auto rid = _gaussianEdgeExtend(w, r) + p; + auto lid = _gaussianEdgeExtend(w, l) + p; + acc += A(src[rid]) - A(src[lid]); + dst[i++] = ALPHA_BLEND(color, static_cast(acc * iarr + 0.5f)); + } + } +} + + +static void _dropShadowShift(uint32_t* dst, uint32_t* src, int stride, SwBBox& region, SwPoint& offset, uint8_t opacity, bool direct) +{ + src += (region.min.y * stride + region.min.x); + dst += (region.min.y * stride + region.min.x); + + auto w = region.max.x - region.min.x; + auto h = region.max.y - region.min.y; + auto translucent = (direct || opacity < 255); + + //shift offset + if (region.min.x + offset.x < 0) src -= offset.x; + else dst += offset.x; + + if (region.min.y + offset.y < 0) src -= (offset.y * stride); + else dst += (offset.y * stride); + + for (auto y = 0; y < h; ++y) { + if (translucent) rasterTranslucentPixel32(dst, src, w, opacity); + else rasterPixel32(dst, src, w, opacity); + src += stride; + dst += stride; + } +} + + +static void _dropShadowExtendRegion(RenderRegion& region, int extra, SwPoint& offset) +{ + //bbox region expansion for feathering + region.x = -extra; + region.w = extra * 2; + region.y = -extra; + region.h = extra * 2; + + region.x = std::min(region.x + (int32_t)offset.x, region.x); + region.y = std::min(region.y + (int32_t)offset.y, region.y); + region.w += abs(offset.x); + region.h += abs(offset.y); +} + + +bool effectDropShadowPrepare(RenderEffectDropShadow* params) +{ + auto rd = (SwDropShadow*)malloc(sizeof(SwDropShadow)); + + //compute box kernel sizes + auto extends = _gaussianInit(rd, params->sigma * params->sigma, params->quality); + + //invalid + if (extends == 0 || params->color[3] == 0) { + params->invalid = true; + free(rd); + return false; + } + + //offset + if (params->distance > 0.0f) { + auto radian = tvg::deg2rad(90.0f - params->angle); + rd->offset = {(SwCoord)(params->distance * cosf(radian)), (SwCoord)(-1.0f * params->distance * sinf(radian))}; + } else { + rd->offset = {0, 0}; + } + + //bbox region expansion for feathering + _dropShadowExtendRegion(params->extend, extends, rd->offset); + + params->rd = rd; + + return true; +} + + +//A quite same integration with effectGaussianBlur(). See it for detailed comments. +//surface[0]: the original image, to overlay it into the filtered image. +//surface[1]: temporary buffer for generating the filtered image. +bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params, uint8_t opacity, bool direct) +{ + if (cmp->image.channelSize != sizeof(uint32_t)) { + TVGERR("SW_ENGINE", "Not supported grayscale Drop Shadow!"); + return false; + } + + //FIXME: if the body is partially visible due to clipping, the shadow also becomes partially visible. + + auto data = static_cast(params->rd); + auto& bbox = cmp->bbox; + auto w = (bbox.max.x - bbox.min.x); + auto h = (bbox.max.y - bbox.min.y); + + //outside the screen + if (abs(data->offset.x) >= w || abs(data->offset.y) >= h) return true; + + SwImage* buffer[] = {&surface[0]->compositor->image, &surface[1]->compositor->image}; + auto color = cmp->recoverSfc->join(params->color[0], params->color[1], params->color[2], 255); + auto stride = cmp->image.stride; + auto front = cmp->image.buf32; + auto back = buffer[1]->buf32; + opacity = MULTIPLY(params->color[3], opacity); + + TVGLOG("SW_ENGINE", "DropShadow region(%ld, %ld, %ld, %ld) params(%f %f %f), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->angle, params->distance, params->sigma, data->level); + + //saving the original image in order to overlay it into the filtered image. + _dropShadowFilter(back, front, stride, w, h, bbox, data->kernel[0], color, false); + std::swap(front, buffer[0]->buf32); + std::swap(front, back); + + //horizontal + for (int i = 1; i < data->level; ++i) { + _dropShadowFilter(back, front, stride, w, h, bbox, data->kernel[i], color, false); + std::swap(front, back); + } + + //vertical + rasterXYFlip(front, back, stride, w, h, bbox, false); + std::swap(front, back); + + for (int i = 0; i < data->level; ++i) { + _dropShadowFilter(back, front, stride, h, w, bbox, data->kernel[i], color, true); + std::swap(front, back); + } + + rasterXYFlip(front, back, stride, h, w, bbox, true); + std::swap(cmp->image.buf32, back); + + //draw to the main surface directly + if (direct) { + _dropShadowShift(cmp->recoverSfc->buf32, cmp->image.buf32, stride, bbox, data->offset, opacity, direct); + std::swap(cmp->image.buf32, buffer[0]->buf32); + return true; + } + + //draw to the intermediate surface + rasterClear(surface[1], bbox.min.x, bbox.min.y, w, h); + _dropShadowShift(buffer[1]->buf32, cmp->image.buf32, stride, bbox, data->offset, opacity, direct); + std::swap(cmp->image.buf32, buffer[1]->buf32); + + //compositing shadow and body + auto s = buffer[0]->buf32 + (bbox.min.y * buffer[0]->stride + bbox.min.x); + auto d = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); + + for (auto y = 0; y < h; ++y) { + rasterTranslucentPixel32(d, s, w, 255); + s += buffer[0]->stride; + d += cmp->image.stride; + } return true; } diff --git a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index fd1238be..18ffc18e 100644 --- a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -869,16 +869,7 @@ static bool _rasterDirectRleImage(SwSurface* surface, const SwImage* image, uint auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox); auto alpha = MULTIPLY(span->coverage, opacity); - if (alpha == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { - *dst = *img + ALPHA_BLEND(*dst, IA(*img)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { - auto src = ALPHA_BLEND(*img, alpha); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } - } + rasterTranslucentPixel32(dst, img, span->len, alpha); } return true; } @@ -1144,27 +1135,14 @@ static bool _rasterDirectImage(SwSurface* surface, const SwImage* image, const S //32bits channels if (surface->channelSize == sizeof(uint32_t)) { auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x]; - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto src = sbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) { - *dst = *src + ALPHA_BLEND(*dst, IA(*src)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { - auto tmp = ALPHA_BLEND(*src, opacity); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); - } - } + rasterTranslucentPixel32(dbuffer, sbuffer, region.max.x - region.min.x, opacity); dbuffer += surface->stride; sbuffer += image->stride; } //8bits grayscale } else if (surface->channelSize == sizeof(uint8_t)) { auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x]; - for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride, sbuffer += image->stride) { auto dst = dbuffer; auto src = sbuffer; @@ -1598,6 +1576,19 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRle* rle, const /* External Class Implementation */ /************************************************************************/ +void rasterTranslucentPixel32(uint32_t* dst, uint32_t* src, uint32_t len, uint8_t opacity) +{ + //TODO: Support SIMD accelerations + cRasterTranslucentPixels(dst, src, len, opacity); +} + + +void rasterPixel32(uint32_t* dst, uint32_t* src, uint32_t len, uint8_t opacity) +{ + //TODO: Support SIMD accelerations + cRasterPixels(dst, src, len, opacity); +} + void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len) { diff --git a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h index 519e9b03..d79da0e4 100644 --- a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h +++ b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h @@ -20,6 +20,38 @@ * SOFTWARE. */ + +template +static void inline cRasterTranslucentPixels(PIXEL_T* dst, PIXEL_T* src, uint32_t len, uint32_t opacity) +{ + //TODO: 64bits faster? + if (opacity == 255) { + for (uint32_t x = 0; x < len; ++x, ++dst, ++src) { + *dst = *src + ALPHA_BLEND(*dst, IA(*src)); + } + } else { + for (uint32_t x = 0; x < len; ++x, ++dst, ++src) { + auto tmp = ALPHA_BLEND(*src, opacity); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + } + } +} + + +template +static void inline cRasterPixels(PIXEL_T* dst, PIXEL_T* src, uint32_t len, uint32_t opacity) +{ + //TODO: 64bits faster? + if (opacity == 255) { + for (uint32_t x = 0; x < len; ++x, ++dst, ++src) { + *dst = *src; + } + } else { + cRasterTranslucentPixels(dst, src, len, opacity); + } +} + + template static void inline cRasterPixels(PIXEL_T* dst, PIXEL_T val, uint32_t offset, int32_t len) { diff --git a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 27cf5f4e..180f3cc3 100644 --- a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -603,6 +603,8 @@ RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) if (x + w > sw) w = (sw - x); if (y + h > sh) h = (sh - y); + if (w == 0 || h == 0) return nullptr; + cmp->compositor->recoverSfc = surface; cmp->compositor->recoverCmp = surface->compositor; cmp->compositor->valid = false; @@ -647,19 +649,32 @@ bool SwRenderer::endComposite(RenderCompositor* cmp) bool SwRenderer::prepare(RenderEffect* effect) { switch (effect->type) { - case SceneEffect::GaussianBlur: return effectGaussianPrepare(static_cast(effect)); + case SceneEffect::GaussianBlur: return effectGaussianBlurPrepare(static_cast(effect)); + case SceneEffect::DropShadow: return effectDropShadowPrepare(static_cast(effect)); default: return false; } } -bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect) +bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) { + if (effect->invalid) return false; + auto p = static_cast(cmp); - auto& buffer = request(surface->channelSize)->compositor->image; switch (effect->type) { - case SceneEffect::GaussianBlur: return effectGaussianBlur(p->image, buffer, p->bbox, static_cast(effect)); + case SceneEffect::GaussianBlur: { + return effectGaussianBlur(p, request(surface->channelSize), static_cast(effect)); + } + case SceneEffect::DropShadow: { + auto cmp1 = request(surface->channelSize); + cmp1->compositor->valid = false; + auto cmp2 = request(surface->channelSize); + SwSurface* surfaces[] = {cmp1, cmp2}; + auto ret = effectDropShadow(p, surfaces, static_cast(effect), opacity, direct); + cmp1->compositor->valid = true; + return ret; + } default: return false; } } diff --git a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h index a5d63028..bd6beb8d 100644 --- a/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h +++ b/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h @@ -61,7 +61,7 @@ class SwRenderer : public RenderMethod void clearCompositors(); bool prepare(RenderEffect* effect) override; - bool effect(RenderCompositor* cmp, const RenderEffect* effect) override; + bool effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) override; static SwRenderer* gen(); static bool init(uint32_t threads); diff --git a/godot/thirdparty/thorvg/src/renderer/tvgRender.h b/godot/thirdparty/thorvg/src/renderer/tvgRender.h index 030e7822..eae44a2e 100644 --- a/godot/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/godot/thirdparty/thorvg/src/renderer/tvgRender.h @@ -276,20 +276,17 @@ struct RenderEffect } }; -struct RenderEffectGaussian : RenderEffect +struct RenderEffectGaussianBlur : RenderEffect { float sigma; uint8_t direction; //0: both, 1: horizontal, 2: vertical uint8_t border; //0: duplicate, 1: wrap uint8_t quality; //0 ~ 100 (optional) - static RenderEffectGaussian* gen(va_list& args) + static RenderEffectGaussianBlur* gen(va_list& args) { - auto sigma = (float) va_arg(args, double); - if (sigma <= 0) return nullptr; - - auto inst = new RenderEffectGaussian; - inst->sigma = sigma; + auto inst = new RenderEffectGaussianBlur; + inst->sigma = std::max((float) va_arg(args, double), 0.0f); inst->direction = std::min(va_arg(args, int), 2); inst->border = std::min(va_arg(args, int), 1); inst->quality = std::min(va_arg(args, int), 100); @@ -298,6 +295,30 @@ struct RenderEffectGaussian : RenderEffect } }; +struct RenderEffectDropShadow : RenderEffect +{ + uint8_t color[4]; //rgba + float angle; + float distance; + float sigma; + uint8_t quality; //0 ~ 100 (optional) + + static RenderEffectDropShadow* gen(va_list& args) + { + auto inst = new RenderEffectDropShadow; + inst->color[0] = va_arg(args, int); + inst->color[1] = va_arg(args, int); + inst->color[2] = va_arg(args, int); + inst->color[3] = std::min(va_arg(args, int), 255); + inst->angle = (float) va_arg(args, double); + inst->distance = (float) va_arg(args, double); + inst->sigma = std::max((float) va_arg(args, double), 0.0f); + inst->quality = std::min(va_arg(args, int), 100); + inst->type = SceneEffect::DropShadow; + return inst; + } +}; + class RenderMethod { private: @@ -331,7 +352,7 @@ class RenderMethod virtual bool endComposite(RenderCompositor* cmp) = 0; virtual bool prepare(RenderEffect* effect) = 0; - virtual bool effect(RenderCompositor* cmp, const RenderEffect* effect) = 0; + virtual bool effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) = 0; }; static inline bool MASK_REGION_MERGING(CompositeMethod method) diff --git a/godot/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/godot/thirdparty/thorvg/src/renderer/tvgSaver.cpp index d9cff5bc..993fe6d8 100644 --- a/godot/thirdparty/thorvg/src/renderer/tvgSaver.cpp +++ b/godot/thirdparty/thorvg/src/renderer/tvgSaver.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ +#include #include "tvgCommon.h" #include "tvgSaveModule.h" #include "tvgPaint.h" diff --git a/godot/thirdparty/thorvg/src/renderer/tvgScene.cpp b/godot/thirdparty/thorvg/src/renderer/tvgScene.cpp index 0b165c71..ce169d33 100644 --- a/godot/thirdparty/thorvg/src/renderer/tvgScene.cpp +++ b/godot/thirdparty/thorvg/src/renderer/tvgScene.cpp @@ -77,7 +77,11 @@ Result Scene::push(unique_ptr paint) noexcept { auto p = paint.release(); if (!p) return Result::MemoryCorruption; - PP(p)->ref(); + P(p)->ref(); + + //Relocated the paint to the current scene space + P(p)->renderFlag |= RenderUpdateFlag::Transform; + pImpl->paints.push_back(p); return Result::Success; @@ -117,7 +121,11 @@ Result Scene::push(SceneEffect effect, ...) noexcept switch (effect) { case SceneEffect::GaussianBlur: { - re = RenderEffectGaussian::gen(args); + re = RenderEffectGaussianBlur::gen(args); + break; + } + case SceneEffect::DropShadow: { + re = RenderEffectDropShadow::gen(args); break; } default: break; diff --git a/godot/thirdparty/thorvg/src/renderer/tvgScene.h b/godot/thirdparty/thorvg/src/renderer/tvgScene.h index cb2ef7f6..7972ae33 100644 --- a/godot/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/godot/thirdparty/thorvg/src/renderer/tvgScene.h @@ -143,8 +143,9 @@ struct Scene::Impl if (cmp) { //Apply post effects if any. if (effects) { + auto direct = effects->count == 1 ? true : false; for (auto e = effects->begin(); e < effects->end(); ++e) { - renderer->effect(cmp, *e); + renderer->effect(cmp, *e, opacity, direct); } } renderer->endComposite(cmp); diff --git a/godot/thirdparty/thorvg/update-thorvg.sh b/godot/thirdparty/thorvg/update-thorvg.sh index 26292bc1..f9953f2f 100755 --- a/godot/thirdparty/thorvg/update-thorvg.sh +++ b/godot/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.15.3 +VERSION=0.15.5 # Uncomment and set a git hash to use specific commit instead of tag. #GIT_COMMIT= @@ -74,10 +74,6 @@ cp -rv src/loaders/external_webp ../src/loaders/ # Not using external jpg as it's turbojpeg, which we don't have. cp -rv src/loaders/jpg ../src/loaders/ -cp -rv src/loaders/lottie ../src/loaders/ -# Disabled: THORVG_LOTTIE_EXPRESSIONS_SUPPORT -rm -rfv ../src/loaders/lottie/jerryscript - popd rm -rf tmp popd diff --git a/godot/thirdparty/ufbx/ufbx.c b/godot/thirdparty/ufbx/ufbx.c index 2d13c78b..77bd3dea 100644 --- a/godot/thirdparty/ufbx/ufbx.c +++ b/godot/thirdparty/ufbx/ufbx.c @@ -20,6 +20,21 @@ // UFBX_TRACE Log calls of `ufbxi_check()` for tracing execution // UFBX_LITTLE_ENDIAN=0/1 Explicitly define little/big endian architecture // UFBX_PATH_SEPARATOR='' Specify default platform path separator +// UFBX_NO_SSE Do not try to include SSE + +// Dependencies: +// UFBX_NO_MALLOC Disable default malloc/realloc/free +// UFBX_NO_STDIO Disable stdio FILE API +// UFBX_EXTERNAL_MALLOC Link to external ufbx_malloc() interface +// UFBX_EXTERNAL_STDIO Link to external ufbx_stdio_() interface +// UFBX_EXTERNAL_MATH Link to external interface +// UFBX_EXTERNAL_STRING Link to external interface + +// Freestanding: +// UFBX_MATH_PREFIX='ufbx_' Prefix for external functions used +// UFBX_STRING_PREFIX='ufbx_' Prefix for external functions used +// UFBX_NO_LIBC Do not include libc (implies UFBX_EXTERNAL_MATH/STRING/MALLOC/STDIO by default) +// UFBX_NO_LIBC_TYPES Do not include any libc headers, you must define all types in // Mostly internal for debugging: // UFBX_STATIC_ANALYSIS Enable static analysis augmentation @@ -175,28 +190,71 @@ // -- Headers -#include -#include -#include -#include -#include -#include - -#if !defined(UFBX_NO_MATH_H) - #include - #define UFBX_INFINITY INFINITY - #define UFBX_NAN NAN +// Legacy mapping +#if !defined(UFBX_EXTERNAL_MATH) && defined(UFBX_NO_MATH_H) + #define UFBX_EXTERNAL_MATH #endif -#if !defined(UFBX_MATH_PREFIX) - #define UFBX_MATH_PREFIX +#if !defined(UFBX_NO_LIBC_TYPES) + #include #endif -#define ufbxi_math_cat2(a, b) a##b -#define ufbxi_math_cat(a, b) ufbxi_math_cat2(a, b) -#define ufbxi_math_fn(name) ufbxi_math_cat(UFBX_MATH_PREFIX, name) +#if !defined(UFBX_NO_LIBC) + #if !defined(UFBX_NO_FLOAT_H) + #include + #endif + #if !defined(UFBX_EXTERNAL_MATH) + #include + #endif + #if !defined(UFBX_EXTERNAL_STRING) + #include + #endif + #if !defined(UFBX_NO_STDIO) && !defined(UFBX_EXTERNAL_STDIO) + #include + #endif + #if !defined(UFBX_NO_MALLOC) && !defined(UFBX_EXTERNAL_MALLOC) + #include + #endif +#else + #if !defined(UFBX_EXTERNAL_MATH) && !defined(UFBX_NO_EXTERNAL_MATH) + #define UFBX_EXTERNAL_MATH + #endif + #if !defined(UFBX_EXTERNAL_STRING) && !defined(UFBX_NO_EXTERNAL_STRING) + #define UFBX_EXTERNAL_STRING + #endif + #if !defined(UFBX_EXTERNAL_MALLOC) && !defined(UFBX_NO_EXTERNAL_MALLOC) && !defined(UFBX_NO_MALLOC) + #define UFBX_EXTERNAL_MALLOC + #endif + #if !defined(UFBX_EXTERNAL_STDIO) && !defined(UFBX_NO_EXTERNAL_STDIO) && !defined(UFBX_NO_STDIO) + #define UFBX_EXTERNAL_STDIO + #endif +#endif + +#if defined(UFBX_EXTERNAL_STRING) && !defined(UFBX_STRING_PREFIX) + #define UFBX_STRING_PREFIX ufbx_ +#endif -#if !defined(UFBX_NO_MATH_DEFINES) +#if !defined(UFBX_EXTERNAL_MATH) + #if !defined(UFBX_MATH_PREFIX) + #define UFBX_MATH_PREFIX + #endif +#endif + +#define ufbxi_pre_cat2(a, b) a##b +#define ufbxi_pre_cat(a, b) ufbxi_pre_cat2(a, b) + +// -- External functions + +#ifndef ufbx_extern_abi + #if defined(UFBX_STATIC) + #define ufbx_extern_abi static + #else + #define ufbx_extern_abi + #endif +#endif + +#if defined(UFBX_MATH_PREFIX) + #define ufbxi_math_fn(name) ufbxi_pre_cat(UFBX_MATH_PREFIX, name) #define ufbx_sqrt ufbxi_math_fn(sqrt) #define ufbx_fabs ufbxi_math_fn(fabs) #define ufbx_pow ufbxi_math_fn(pow) @@ -216,31 +274,123 @@ #define ufbx_isnan ufbxi_math_fn(isnan) #endif -#if defined(UFBX_NO_MATH_H) && !defined(UFBX_NO_MATH_DECLARATIONS) - double ufbx_sqrt(double x); - double ufbx_sin(double x); - double ufbx_cos(double x); - double ufbx_tan(double x); - double ufbx_asin(double x); - double ufbx_acos(double x); - double ufbx_atan(double x); - double ufbx_atan2(double y, double x); - double ufbx_pow(double x, double y); - double ufbx_fmin(double a, double b); - double ufbx_fmax(double a, double b); - double ufbx_fabs(double x); - double ufbx_copysign(double x, double y); - double ufbx_nextafter(double x, double y); - double ufbx_rint(double x); - double ufbx_ceil(double x); - int ufbx_isnan(double x); +#if !defined(UFBX_NO_EXTERNAL_DEFINES) + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(UFBX_EXTERNAL_MATH) + ufbx_extern_abi double ufbx_sqrt(double x); + ufbx_extern_abi double ufbx_sin(double x); + ufbx_extern_abi double ufbx_cos(double x); + ufbx_extern_abi double ufbx_tan(double x); + ufbx_extern_abi double ufbx_asin(double x); + ufbx_extern_abi double ufbx_acos(double x); + ufbx_extern_abi double ufbx_atan(double x); + ufbx_extern_abi double ufbx_atan2(double y, double x); + ufbx_extern_abi double ufbx_pow(double x, double y); + ufbx_extern_abi double ufbx_fmin(double a, double b); + ufbx_extern_abi double ufbx_fmax(double a, double b); + ufbx_extern_abi double ufbx_fabs(double x); + ufbx_extern_abi double ufbx_copysign(double x, double y); + ufbx_extern_abi double ufbx_nextafter(double x, double y); + ufbx_extern_abi double ufbx_rint(double x); + ufbx_extern_abi double ufbx_ceil(double x); + ufbx_extern_abi int ufbx_isnan(double x); +#endif + +#if defined(UFBX_EXTERNAL_STRING) + ufbx_extern_abi size_t ufbx_strlen(const char *str); + ufbx_extern_abi void *ufbx_memcpy(void *dst, const void *src, size_t count); + ufbx_extern_abi void *ufbx_memmove(void *dst, const void *src, size_t count); + ufbx_extern_abi void *ufbx_memset(void *dst, int ch, size_t count); + ufbx_extern_abi const void *ufbx_memchr(const void *ptr, int value, size_t count); + ufbx_extern_abi int ufbx_memcmp(const void *a, const void *b, size_t count); + ufbx_extern_abi int ufbx_strcmp(const char *a, const char *b); + ufbx_extern_abi int ufbx_strncmp(const char *a, const char *b, size_t count); +#endif + +#if defined(UFBX_EXTERNAL_MALLOC) + ufbx_extern_abi void *ufbx_malloc(size_t size); + ufbx_extern_abi void *ufbx_realloc(void *ptr, size_t old_size, size_t new_size); + ufbx_extern_abi void ufbx_free(void *ptr, size_t old_size); +#endif + +#if defined(UFBX_EXTERNAL_STDIO) + ufbx_extern_abi void *ufbx_stdio_open(const char *path, size_t path_len); + ufbx_extern_abi size_t ufbx_stdio_read(void *file, void *data, size_t size); + ufbx_extern_abi bool ufbx_stdio_skip(void *file, size_t size); + ufbx_extern_abi uint64_t ufbx_stdio_size(void *file); + ufbx_extern_abi void ufbx_stdio_close(void *file); +#endif + +#if defined(__cplusplus) +} +#endif + #endif #if !defined(UFBX_INFINITY) - #define UFBX_INFINITY (1e+300 * 1e+300) + #if defined(INFINITY) + #define UFBX_INFINITY INFINITY + #else + #define UFBX_INFINITY (1e+300 * 1e+300) + #endif #endif #if !defined(UFBX_NAN) - #define UFBX_NAN (UFBX_INFINITY * 0.0f) + #if defined(NAN) + #define UFBX_NAN NAN + #else + #define UFBX_NAN (UFBX_INFINITY * 0.0f) + #endif +#endif +#if !defined(UFBX_FLT_EPSILON) + #if defined(FLT_EPSILON) + #define UFBX_FLT_EPSILON FLT_EPSILON + #else + #define UFBX_FLT_EPSILON 1.192092896e-07f + #endif +#endif +#if !defined(UFBX_FLT_EVAL_METHOD) + #if defined(FLT_EVAL_METHOD) + #define UFBX_FLT_EVAL_METHOD FLT_EVAL_METHOD + #elif defined(__FLT_EVAL_METHOD__) + #define UFBX_FLT_EVAL_METHOD __FLT_EVAL_METHOD__ + #elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) + #define UFBX_FLT_EVAL_METHOD 0 + #else + #define UFBX_FLT_EVAL_METHOD -1 + #endif +#endif + +#if defined(ufbx_malloc) || defined(ufbx_realloc) || defined(ufbx_free) + // User provided allocators + #if !defined(ufbx_malloc) || !defined(ufbx_realloc) || !defined(ufbx_free) + #error Inconsistent custom global allocator + #endif +#elif defined(UFBX_NO_MALLOC) + #define ufbx_malloc(size) ((void)(size), (void*)NULL) + #define ufbx_realloc(ptr, old_size, new_size) ((void)(ptr), (void)(old_size), (void)(new_size), (void*)NULL) + #define ufbx_free(ptr, old_size) ((void)(ptr), (void*)(old_size)) +#elif defined(UFBX_EXTERNAL_MALLOC) + // Nop +#else + #define ufbx_malloc(size) malloc((size)) + #define ufbx_realloc(ptr, old_size, new_size) realloc((ptr), (new_size)) + #define ufbx_free(ptr, old_size) free((ptr)) +#endif + +#if !defined(ufbx_panic_handler) + static void ufbxi_panic_handler(const char *message) + { + (void)message; + #if !defined(UFBX_NO_STDIO) && !defined(UFBX_EXTERNAL_STDIO) + fprintf(stderr, "ufbx panic: %s\n", message); + #endif + ufbx_assert(false && "ufbx panic: See stderr for more information"); + } + #define ufbx_panic_handler ufbxi_panic_handler #endif // -- Platform @@ -414,8 +564,16 @@ #if defined(UFBX_STATIC_ANALYSIS) bool ufbxi_analysis_opaque; #define ufbxi_maybe_null(ptr) (ufbxi_analysis_opaque ? (ptr) : NULL) + #define ufbxi_analysis_assert(cond) ufbx_assert(cond) #else #define ufbxi_maybe_null(ptr) (ptr) + #define ufbxi_analysis_assert(cond) (void)0 +#endif + +#if defined(UFBX_STATIC_ANALYSIS) || defined(UFBX_UBSAN) + #define ufbxi_maybe_uninit(cond, value, def) ((cond) ? (value) : (def)) +#else + #define ufbxi_maybe_uninit(cond, value, def) (value) #endif #if !defined(ufbxi_trace) @@ -442,7 +600,7 @@ #endif #endif -#if !defined(UFBX_STANDARD_C) && (defined(_MSC_VER) && defined(_M_X64)) || ((defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)) || defined(UFBX_USE_SSE) +#if !defined(UFBX_STANDARD_C) && !defined(UFBX_NO_SSE) && (defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC)) || ((defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)) || defined(UFBX_USE_SSE) #define UFBXI_HAS_SSE 1 #include #include @@ -450,6 +608,108 @@ #define UFBXI_HAS_SSE 0 #endif +// -- Atomic counter + +#define UFBXI_THREAD_SAFE 1 + +#if defined(__cplusplus) + #define ufbxi_extern_c extern "C" +#else + #define ufbxi_extern_c +#endif + +#if !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) + typedef size_t ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_inc(ptr) __sync_fetch_and_add((ptr), 1) + #define ufbxi_atomic_counter_dec(ptr) __sync_fetch_and_sub((ptr), 1) + #define ufbxi_atomic_counter_load(ptr) __sync_fetch_and_add((ptr), 0) // TODO: Proper atomic load +#elif !defined(UFBX_STANDARD_C) && defined(_MSC_VER) + #if defined(_M_X64) || defined(_M_ARM64) + ufbxi_extern_c __int64 _InterlockedIncrement64(__int64 volatile * lpAddend); + ufbxi_extern_c __int64 _InterlockedDecrement64(__int64 volatile * lpAddend); + ufbxi_extern_c __int64 _InterlockedExchangeAdd64(__int64 volatile * lpAddend, __int64 Value); + typedef volatile __int64 ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_inc(ptr) ((size_t)_InterlockedIncrement64(ptr) - 1) + #define ufbxi_atomic_counter_dec(ptr) ((size_t)_InterlockedDecrement64(ptr) + 1) + #define ufbxi_atomic_counter_load(ptr) ((size_t)_InterlockedExchangeAdd64((ptr), 0)) + #else + ufbxi_extern_c long __cdecl _InterlockedIncrement(long volatile * lpAddend); + ufbxi_extern_c long __cdecl _InterlockedDecrement(long volatile * lpAddend); + ufbxi_extern_c long __cdecl _InterlockedExchangeAdd(long volatile * lpAddend, long Value); + typedef volatile long ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_inc(ptr) ((size_t)_InterlockedIncrement(ptr) - 1) + #define ufbxi_atomic_counter_dec(ptr) ((size_t)_InterlockedDecrement(ptr) + 1) + #define ufbxi_atomic_counter_load(ptr) ((size_t)_InterlockedExchangeAdd((ptr), 0)) + #endif +#elif !defined(UFBX_STANDARD_C) && defined(__TINYC__) + #if defined(__x86_64__) || defined(_AMD64_) + static size_t ufbxi_tcc_atomic_add(volatile size_t *dst, size_t value) { + __asm__ __volatile__("lock; xaddq %0, %1;" : "+r" (value), "=m" (*dst) : "m" (dst)); + return value; + } + #elif defined(__i386__) || defined(_X86_) + static size_t ufbxi_tcc_atomic_add(volatile size_t *dst, size_t value) { + __asm__ __volatile__("lock; xaddl %0, %1;" : "+r" (value), "=m" (*dst) : "m" (dst)); + return value; + } + #else + #error Unexpected TCC architecture + #endif + typedef volatile size_t ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_inc(ptr) ufbxi_tcc_atomic_add((ptr), 1) + #define ufbxi_atomic_counter_dec(ptr) ufbxi_tcc_atomic_add((ptr), SIZE_MAX) + #define ufbxi_atomic_counter_load(ptr) ufbxi_tcc_atomic_add((ptr), 0) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #include + #include + typedef struct { alignas(std::atomic_size_t) char data[sizeof(std::atomic_size_t)]; } ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) (new (&(ptr)->data) std::atomic_size_t(0)) + #define ufbxi_atomic_counter_free(ptr) (((std::atomic_size_t*)(ptr)->data)->~atomic()) + #define ufbxi_atomic_counter_inc(ptr) ((std::atomic_size_t*)(ptr)->data)->fetch_add(1) + #define ufbxi_atomic_counter_dec(ptr) ((std::atomic_size_t*)(ptr)->data)->fetch_sub(1) + #define ufbxi_atomic_counter_load(ptr) ((std::atomic_size_t*)(ptr)->data)->load(std::memory_order_acquire) +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) + #include + typedef volatile atomic_size_t ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) atomic_init(ptr, 0) + #define ufbxi_atomic_counter_free(ptr) (void)(ptr) + #define ufbxi_atomic_counter_inc(ptr) atomic_fetch_add((ptr), 1) + #define ufbxi_atomic_counter_dec(ptr) atomic_fetch_sub((ptr), 1) + #define ufbxi_atomic_counter_load(ptr) atomic_load_explicit((ptr), memory_order_acquire) +#else + typedef volatile size_t ufbxi_atomic_counter; + #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) + #define ufbxi_atomic_counter_inc(ptr) ((*(ptr))++) + #define ufbxi_atomic_counter_dec(ptr) ((*(ptr))--) + #define ufbxi_atomic_counter_load(ptr) (*(ptr)) + #undef UFBXI_THREAD_SAFE + #define UFBXI_THREAD_SAFE 0 +#endif + +// ^^ No references to before this point ^^ +// vv No more includes past this point vv + +#if defined(UFBX_STRING_PREFIX) + #define ufbxi_string_fn(name) ufbxi_pre_cat(UFBX_STRING_PREFIX, name) + #define strlen ufbxi_string_fn(strlen) + #define memcpy ufbxi_string_fn(memcpy) + #define memmove ufbxi_string_fn(memmove) + #define memset ufbxi_string_fn(memset) + #define memchr ufbxi_string_fn(memchr) + #define memcmp ufbxi_string_fn(memcmp) + #define strcmp ufbxi_string_fn(strcmp) + #define strncmp ufbxi_string_fn(strncmp) +#endif + #if !defined(UFBX_LITTLE_ENDIAN) #if !defined(UFBX_STANDARD_C) && (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__) || defined(__wasm__) || defined(__EMSCRIPTEN__)) #define UFBX_LITTLE_ENDIAN 1 @@ -570,7 +830,7 @@ ufbx_static_assert(sizeof_f64, sizeof(double) == 8); // -- Version -#define UFBX_SOURCE_VERSION ufbx_pack_version(0, 14, 3) +#define UFBX_SOURCE_VERSION ufbx_pack_version(0, 15, 0) ufbx_abi_data_def const uint32_t ufbx_source_version = UFBX_SOURCE_VERSION; ufbx_static_assert(source_header_version, UFBX_SOURCE_VERSION/1000u == UFBX_HEADER_VERSION/1000u); @@ -607,98 +867,16 @@ ufbx_static_assert(source_header_version, UFBX_SOURCE_VERSION/1000u == UFBX_HEAD #define ufbxi_wrap_shr64(a, b) ((a) >> ((b) & 63)) #endif -// -- Atomic counter - -#define UFBXI_THREAD_SAFE 1 - -#if defined(__cplusplus) - #define ufbxi_extern_c extern "C" -#else - #define ufbxi_extern_c -#endif - -#if !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) - typedef size_t ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_inc(ptr) __sync_fetch_and_add((ptr), 1) - #define ufbxi_atomic_counter_dec(ptr) __sync_fetch_and_sub((ptr), 1) - #define ufbxi_atomic_counter_load(ptr) __sync_fetch_and_add((ptr), 0) // TODO: Proper atomic load -#elif !defined(UFBX_STANDARD_C) && defined(_MSC_VER) - #if defined(_M_X64) || defined(_M_ARM64) - ufbxi_extern_c __int64 _InterlockedIncrement64(__int64 volatile * lpAddend); - ufbxi_extern_c __int64 _InterlockedDecrement64(__int64 volatile * lpAddend); - ufbxi_extern_c __int64 _InterlockedExchangeAdd64(__int64 volatile * lpAddend, __int64 Value); - typedef volatile __int64 ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_inc(ptr) ((size_t)_InterlockedIncrement64(ptr) - 1) - #define ufbxi_atomic_counter_dec(ptr) ((size_t)_InterlockedDecrement64(ptr) + 1) - #define ufbxi_atomic_counter_load(ptr) ((size_t)_InterlockedExchangeAdd64((ptr), 0)) - #else - ufbxi_extern_c long __cdecl _InterlockedIncrement(long volatile * lpAddend); - ufbxi_extern_c long __cdecl _InterlockedDecrement(long volatile * lpAddend); - ufbxi_extern_c long __cdecl _InterlockedExchangeAdd(long volatile * lpAddend, long Value); - typedef volatile long ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_inc(ptr) ((size_t)_InterlockedIncrement(ptr) - 1) - #define ufbxi_atomic_counter_dec(ptr) ((size_t)_InterlockedDecrement(ptr) + 1) - #define ufbxi_atomic_counter_load(ptr) ((size_t)_InterlockedExchangeAdd((ptr), 0)) - #endif -#elif !defined(UFBX_STANDARD_C) && defined(__TINYC__) - #if defined(__x86_64__) || defined(_AMD64_) - static size_t ufbxi_tcc_atomic_add(volatile size_t *dst, size_t value) { - __asm__ __volatile__("lock; xaddq %0, %1;" : "+r" (value), "=m" (*dst) : "m" (dst)); - return value; - } - #elif defined(__i386__) || defined(_X86_) - static size_t ufbxi_tcc_atomic_add(volatile size_t *dst, size_t value) { - __asm__ __volatile__("lock; xaddl %0, %1;" : "+r" (value), "=m" (*dst) : "m" (dst)); - return value; - } - #else - #error Unexpected TCC architecture - #endif - typedef volatile size_t ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_inc(ptr) ufbxi_tcc_atomic_add((ptr), 1) - #define ufbxi_atomic_counter_dec(ptr) ufbxi_tcc_atomic_add((ptr), SIZE_MAX) - #define ufbxi_atomic_counter_load(ptr) ufbxi_tcc_atomic_add((ptr), 0) -#elif defined(__cplusplus) && (__cplusplus >= 201103L) - #include - #include - typedef struct { alignas(std::atomic_size_t) char data[sizeof(std::atomic_size_t)]; } ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) (new (&(ptr)->data) std::atomic_size_t(0)) - #define ufbxi_atomic_counter_free(ptr) (((std::atomic_size_t*)(ptr)->data)->~atomic()) - #define ufbxi_atomic_counter_inc(ptr) ((std::atomic_size_t*)(ptr)->data)->fetch_add(1) - #define ufbxi_atomic_counter_dec(ptr) ((std::atomic_size_t*)(ptr)->data)->fetch_sub(1) - #define ufbxi_atomic_counter_load(ptr) ((std::atomic_size_t*)(ptr)->data)->load(std::memory_order_acquire) -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) - #include - typedef volatile atomic_size_t ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) atomic_init(ptr, 0) - #define ufbxi_atomic_counter_free(ptr) (void)(ptr) - #define ufbxi_atomic_counter_inc(ptr) atomic_fetch_add((ptr), 1) - #define ufbxi_atomic_counter_dec(ptr) atomic_fetch_sub((ptr), 1) - #define ufbxi_atomic_counter_load(ptr) atomic_load_explicit((ptr), memory_order_acquire) -#else - typedef volatile size_t ufbxi_atomic_counter; - #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0) - #define ufbxi_atomic_counter_inc(ptr) ((*(ptr))++) - #define ufbxi_atomic_counter_dec(ptr) ((*(ptr))--) - #define ufbxi_atomic_counter_load(ptr) (*(ptr)) - #undef UFBXI_THREAD_SAFE - #define UFBXI_THREAD_SAFE 0 -#endif - // -- Bit manipulation #if !defined(UFBX_STANDARD_C) && defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) ufbxi_extern_c unsigned char _BitScanReverse(unsigned long * _Index, unsigned long _Mask); ufbxi_extern_c unsigned char _BitScanReverse64(unsigned long * _Index, unsigned __int64 _Mask); + static ufbxi_forceinline ufbxi_unused uint32_t ufbxi_lzcnt32(uint32_t v) { + unsigned long index; + _BitScanReverse(&index, (unsigned long)v); + return 31 - (uint32_t)index; + } static ufbxi_forceinline ufbxi_unused uint32_t ufbxi_lzcnt64(uint64_t v) { unsigned long index; #if defined(_M_X64) @@ -713,14 +891,26 @@ ufbx_static_assert(source_header_version, UFBX_SOURCE_VERSION/1000u == UFBX_HEAD return 63 - (uint32_t)index; } #elif !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__)) + #define ufbxi_lzcnt32(v) ((uint32_t)__builtin_clz((unsigned)(v))) #define ufbxi_lzcnt64(v) ((uint32_t)__builtin_clzll((unsigned long long)(v))) #else // DeBrujin table lookup - static const uint8_t ufbxi_lzcnt_table[] = { + static const uint8_t ufbxi_lzcnt32_table[] = { + 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0, + }; + static const uint8_t ufbxi_lzcnt64_table[] = { 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2, 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1, 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18, 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0, }; + static ufbxi_noinline ufbxi_unused uint32_t ufbxi_lzcnt32(uint32_t v) { + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return ufbxi_lzcnt32_table[(v * 0x07c4acddu) >> 27]; + } static ufbxi_noinline ufbxi_unused uint32_t ufbxi_lzcnt64(uint64_t v) { v |= v >> 1; v |= v >> 2; @@ -728,10 +918,20 @@ ufbx_static_assert(source_header_version, UFBX_SOURCE_VERSION/1000u == UFBX_HEAD v |= v >> 8; v |= v >> 16; v |= v >> 32; - return ufbxi_lzcnt_table[(v * UINT64_C(0x03f79d71b4cb0a89)) >> 58]; + return ufbxi_lzcnt64_table[(v * UINT64_C(0x03f79d71b4cb0a89)) >> 58]; } #endif +// -- Bit conversion + +#if defined(__cplusplus) + #define ufbxi_bit_cast(m_dst_type, m_dst, m_src_type, m_src) memcpy(&(m_dst), &(m_src), sizeof(m_dst_type)) +#else + #define ufbxi_bit_cast(m_dst_type, m_dst, m_src_type, m_src) do { \ + union { m_dst_type mi_dst; m_src_type mi_src; } mi_union; \ + mi_union.mi_src = (m_src); (m_dst) = mi_union.mi_dst; } while (0) +#endif + // -- Debug #if defined(UFBX_DEBUG_BINARY_SEARCH) || defined(UFBX_REGRESSION) @@ -1081,321 +1281,389 @@ static ufbxi_noinline void ufbxi_unstable_sort(void *in_data, size_t size, size_ } // -- Float parsing -// -// Custom float parsing that handles floats up to (-)ddddddddddddddddddd.ddddddddddddddddddd -// If larger or scientific notation is used then it defers to `strtod()`. -// For the algorithm we need 128-bit division that is either provided by hardware on x64 or -// a custom implementation below. - -#if !defined(UFBX_STANDARD_C) && UFBXI_MSC_VER >= 1920 && defined(_M_X64) && !defined(__clang__) - ufbxi_extern_c extern unsigned __int64 __cdecl _udiv128(unsigned __int64 highdividend, - unsigned __int64 lowdividend, unsigned __int64 divisor, unsigned __int64 *remainder); - #define ufbxi_div128(a_hi, a_lo, b, p_rem) (_udiv128((a_hi), (a_lo), (b), (p_rem))) -#elif !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(_M_X64)) - static ufbxi_forceinline uint64_t ufbxi_div128(uint64_t a_hi, uint64_t a_lo, uint64_t b, uint64_t *p_rem) { - uint64_t quot, rem; - __asm__("divq %[v]" : "=a"(quot), "=d"(rem) : [v] "r"(b), "a"(a_lo), "d"(a_hi)); - *p_rem = rem; - return quot; - } -#else - static ufbxi_forceinline uint64_t ufbxi_div128(uint64_t a_hi, uint64_t a_lo, uint64_t b, uint64_t *p_rem) { - // Divide `(a_hi << 64 | a_lo)` by `b`, returns quotinent and stores reminder in `p_rem`. - // Based on TAOCP 2.4 multi-word division single algorithm digit step. - // - // Notation: - // b is the base (2^32) in this case - // aN is the Nth digit (base b) of a from the least significant digit - // { x y z } is a multi-digit number b^2*x + b*y + z - // ie. for a 64-bit number a = { a1 a0 } = b*a1 + a0 - // - // We do the division in two steps by dividing three digits in each iteration: - // - // q1, r = { a3 a2 a1 } / { b1 b0 } - // q0, r = { r1 r0 a0 } / { b1 b0 } - // - // In each step we want to compute the expression: - // - // q, r = { u2 u1 u0 } / { v1 v0 } - // - // However we cannot rely on being able to do `u96 / u64` division we estimate - // the result by considering only the leading digits: - // - // q^ = { u2 u1 } / v1 [A] - // r^ = { u2 u1 } % v1 = { u2 u1 } - v1 * q^ [B] - // - // As long as `v1 >= b/2` the estimate `q^` is at most two larger than the actual `q` - // (proof in TAOCP 2.4) so we can compute the correction amount `c`: - // - // q <= q^ <= q + 2 - // q = q^ - c [C] - // - // We can compute the final remainder (that must be non-negative) as follows: - // - // r = { u2 u1 u0 } - v*q - // r = { u2 u1 u0 } - v*(q^ - c) - // r = { u2 u1 u0 } - v*q^ + v*c - // r = { u2 u1 u0 } - { v1 v0 } * q^ + v*c - // r = b^2*u2 + b*u1 + u0 - b*v1*q^ - v0*q^ + v*c - // r = b*(b*u2 + u1 - v1*q^) + u0 - v0*q^ + v*c - // r = b*({ u2 u1 } - v1*q^) + u0 - v0*q^ + v*c - // r = b*r^ + u0 - v0*q^ + v*c - // r = { r^ u0 } - v0*q^ + v*c [D] - // - // As we know `0 <= c <= 2` we can first check if `r < 0` requiring `c >= 1`: - // - // { r^ u0 } - v0*q^ < 0 - // { r^ u0 } < v0*q^ [E] - // - // If we know that `r < 0` we can check if `r < -v` requiring `c = 2`: - // - // { r^ u0 } - v0*q^ < -v - // v0*q^ - { r^ u0 } > v [F] - // - - // First we need to make sure `v1 >= b/2`, we can do this by multiplying the whole - // expression by `2^shift` so that the high bit of `v` is set. - uint32_t shift = ufbxi_lzcnt64(b); - a_hi = (a_hi << shift) | (shift ? a_lo >> (64 - shift) : 0); - a_lo <<= shift; - b <<= shift; - - uint64_t v = b; - uint32_t v1 = (uint32_t)(v >> 32); - uint32_t v0 = (uint32_t)(v); - uint64_t q1, q0, r; - - // q1, r = { a3 a2 a1 } / { b1 b0 } - { - uint64_t u2_u1 = a_hi; - uint32_t u0 = (uint32_t)(a_lo >> 32u); - uint64_t qh = u2_u1 / v1; // q^ = { u2 u1 } / v1 [A] - uint64_t rh = u2_u1 % v1; // r^ = { u2 u1 } % v1 [B] - uint64_t rh_u0 = rh << 32u | u0; // { r^ u0 } - uint64_t v0qh = v0 * qh; // v0*q^ - uint32_t c = rh_u0 < v0qh ? 1 : 0; // { r^ u0 } < v0*q^ [E] - c += c & (v0qh - rh_u0 > v ? 1 : 0); // v0*q^ - { r^ u0 } > v [F] - q1 = qh - c; // q1 = q^ - c [C] - r = rh_u0 - v0qh + v*c; // r = { r^ u0 } - v0*q^ + v*c [D] - } +#define UFBXI_BIGINT_LIMB_BITS 32 +#define UFBXI_BIGINT_ACCUM_BITS (UFBXI_BIGINT_LIMB_BITS * 2) +#define UFBXI_BIGINT_LIMB_MAX (ufbxi_bigint_limb)(((ufbxi_bigint_accum)1 << UFBXI_BIGINT_LIMB_BITS) - 1) +typedef uint32_t ufbxi_bigint_limb; +typedef uint64_t ufbxi_bigint_accum; - // q0, r = { r1 r0 a0 } / { b1 b0 } - { - uint64_t u2_u1 = r; - uint32_t u0 = (uint32_t)a_lo; - - uint64_t qh = u2_u1 / v1; // q^ = { u2 u1 } / v1 [A] - uint64_t rh = u2_u1 % v1; // r^ = { u2 u1 } % v1 [B] - uint64_t rh_u0 = rh << 32u | u0; // { r^ u0 } - uint64_t v0qh = v0 * qh; // v0*q^ - uint32_t c = rh_u0 < v0qh ? 1 : 0; // { r^ u0 } < v0*q^ [E] - c += c & (v0qh - rh_u0 > v ? 1 : 0); // v0*q^ - { r^ u0 } > v [F] - q0 = qh - c; // q0 = q^ - c [C] - r = rh_u0 - v0qh + v*c; // r = { r^ u0 } - v0*q^ + v*c [D] - } +typedef struct { + ufbxi_bigint_limb *limbs; + uint32_t capacity; + uint32_t length; +} ufbxi_bigint; - // Un-normalize the remainder and return the quotinent - *p_rem = r >> shift; - return q1 << 32u | q0; - } -#endif +static ufbxi_bigint ufbxi_bigint_make(ufbxi_bigint_limb *limbs, size_t capacity) +{ + ufbxi_bigint bi = { limbs, (uint32_t)capacity }; + return bi; +} -typedef enum { - UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH = 0x1, - UFBXI_PARSE_DOUBLE_VERIFY_LENGTH = 0x2, -} ufbxi_parse_double_flag; +#define ufbxi_bigint_array(arr) ufbxi_bigint_make((arr), sizeof(arr) / sizeof(*(arr))) static const uint64_t ufbxi_pow5_tab[] = { - UINT64_C(0x8000000000000000), // 5^0 * 2^63 - UINT64_C(0xa000000000000000), // 5^1 * 2^61 - UINT64_C(0xc800000000000000), // 5^2 * 2^59 - UINT64_C(0xfa00000000000000), // 5^3 * 2^57 - UINT64_C(0x9c40000000000000), // 5^4 * 2^54 - UINT64_C(0xc350000000000000), // 5^5 * 2^52 - UINT64_C(0xf424000000000000), // 5^6 * 2^50 - UINT64_C(0x9896800000000000), // 5^7 * 2^47 - UINT64_C(0xbebc200000000000), // 5^8 * 2^45 - UINT64_C(0xee6b280000000000), // 5^9 * 2^43 - UINT64_C(0x9502f90000000000), // 5^10 * 2^40 - UINT64_C(0xba43b74000000000), // 5^11 * 2^38 - UINT64_C(0xe8d4a51000000000), // 5^12 * 2^36 - UINT64_C(0x9184e72a00000000), // 5^13 * 2^33 - UINT64_C(0xb5e620f480000000), // 5^14 * 2^31 - UINT64_C(0xe35fa931a0000000), // 5^15 * 2^29 - UINT64_C(0x8e1bc9bf04000000), // 5^16 * 2^26 - UINT64_C(0xb1a2bc2ec5000000), // 5^17 * 2^24 - UINT64_C(0xde0b6b3a76400000), // 5^18 * 2^22 - UINT64_C(0x8ac7230489e80000), // 5^19 * 2^19 - UINT64_C(0xad78ebc5ac620000), // 5^20 * 2^17 - UINT64_C(0xd8d726b7177a8000), // 5^21 * 2^15 - UINT64_C(0x878678326eac9000), // 5^22 * 2^12 - UINT64_C(0xa968163f0a57b400), // 5^23 * 2^10 - UINT64_C(0xd3c21bcecceda100), // 5^24 * 2^8 - UINT64_C(0x84595161401484a0), // 5^25 * 2^5 - UINT64_C(0xa56fa5b99019a5c8), // 5^26 * 2^3 - UINT64_C(0xcecb8f27f4200f3a), // 5^27 * 2^1 -}; -static const int8_t ufbxi_pow2_tab[] = { - 62, 59, 56, 53, 49, 46, 43, 39, 36, 33, 29, 26, 23, 19, 16, 13, 9, 6, 3, -1, -4, -7, -11, -14, -17, -21, -24, -27, + UINT64_C(0x1), UINT64_C(0x5), UINT64_C(0x19), UINT64_C(0x7d), UINT64_C(0x271), UINT64_C(0xc35), UINT64_C(0x3d09), UINT64_C(0x1312d), UINT64_C(0x5f5e1), + UINT64_C(0x1dcd65), UINT64_C(0x9502f9), UINT64_C(0x2e90edd), UINT64_C(0xe8d4a51), UINT64_C(0x48c27395), UINT64_C(0x16bcc41e9), UINT64_C(0x71afd498d), + UINT64_C(0x2386f26fc1), UINT64_C(0xb1a2bc2ec5), UINT64_C(0x3782dace9d9), UINT64_C(0x1158e460913d), UINT64_C(0x56bc75e2d631), UINT64_C(0x1b1ae4d6e2ef5), + UINT64_C(0x878678326eac9), UINT64_C(0x2a5a058fc295ed), UINT64_C(0xd3c21bcecceda1), UINT64_C(0x422ca8b0a00a425), UINT64_C(0x14adf4b7320334b9), UINT64_C(0x6765c793fa10079d), }; + static const double ufbxi_pow10_tab_f64[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, }; -static ufbxi_noinline uint32_t ufbxi_parse_double_init_flags() +static ufbxi_noinline void ufbxi_bigint_mad(ufbxi_bigint *bigint, ufbxi_bigint_accum multiplicand, ufbxi_bigint_accum addend) +{ + ufbxi_dev_assert((multiplicand | addend) >> (UFBXI_BIGINT_ACCUM_BITS - 1) == 0); + ufbxi_bigint b = *bigint; + ufbxi_bigint_limb m_lo = (ufbxi_bigint_limb)multiplicand; + ufbxi_bigint_limb m_hi = (ufbxi_bigint_limb)(multiplicand >> UFBXI_BIGINT_LIMB_BITS); + ufbxi_bigint_accum carry = addend; + for (uint32_t i = 0; i < b.length; i++) { + ufbxi_bigint_accum limb = (ufbxi_bigint_accum)b.limbs[i]; + ufbxi_bigint_accum lo = limb * m_lo + (carry & UFBXI_BIGINT_LIMB_MAX); + ufbxi_bigint_accum hi = limb * m_hi; + b.limbs[i] = (ufbxi_bigint_limb)lo; + carry = (carry >> 32u) + (lo >> 32u) + hi; + } + while (carry) { + b.limbs[b.length++] = (ufbxi_bigint_limb)carry; + ufbxi_dev_assert(b.length < b.capacity); + carry >>= 32u; + } + bigint->length = b.length; +} + +static ufbxi_noinline bool ufbxi_bigint_div(ufbxi_bigint *q, ufbxi_bigint *u, ufbxi_bigint *v) +{ + int32_t n = (int32_t)v->length; + int32_t m = (int32_t)u->length - n; + ufbxi_bigint_limb v_hi = v->limbs[v->length - 1]; + ufbxi_bigint_limb *un = u->limbs, *vn = v->limbs; + ufbxi_dev_assert(n >= 2 && m >= 1 && v_hi >> (UFBXI_BIGINT_LIMB_BITS - 1) != 0 && un[n+m - 1] >> (UFBXI_BIGINT_LIMB_BITS - 1) == 0); + un[n + m] = 0; + q->length = 0; + for (int32_t j = m - 1; j >= 0; j--) { + ufbxi_bigint_accum u_hi = ((ufbxi_bigint_accum)un[n+j] << UFBXI_BIGINT_LIMB_BITS) | un[n+j-1]; + ufbxi_bigint_accum t, qhat = u_hi / v_hi, rhat = u_hi % v_hi; + while (qhat >> UFBXI_BIGINT_LIMB_BITS != 0 || qhat*vn[n-2] > ((rhat<> UFBXI_BIGINT_LIMB_BITS != 0) break; + } + ufbxi_bigint_limb carry = 0; + for (int32_t i = 0; i < n; i++) { + ufbxi_bigint_accum p = qhat * vn[i]; + t = (ufbxi_bigint_accum)un[i+j] - carry - (ufbxi_bigint_limb)p; + un[i+j] = (ufbxi_bigint_limb)t; + carry = (ufbxi_bigint_limb)((p >> UFBXI_BIGINT_LIMB_BITS) - (t >> UFBXI_BIGINT_LIMB_BITS)); + } + t = (ufbxi_bigint_accum)un[j+n] - carry; + un[j+n] = (ufbxi_bigint_limb)t; + if (t >> UFBXI_BIGINT_LIMB_BITS != 0) { + qhat -= 1; + carry = 0; + for (int32_t i = 0; i < n; i++) { + t = (ufbxi_bigint_accum)un[i+j] + vn[i] + carry; + un[i+j] = (ufbxi_bigint_limb)t; + carry = (ufbxi_bigint_limb)(t >> UFBXI_BIGINT_LIMB_BITS); + } + un[j+n] += carry; + } + q->limbs[j] = (ufbxi_bigint_limb)qhat; + if (qhat && !q->length) { + ufbxi_dev_assert(j + 1 < (int32_t)q->capacity); + q->length = (uint32_t)(j + 1); + } + } + for (int32_t i = 0; i < n; i++) { + if (un[i]) return true; + } + return false; +} + +static void ufbxi_bigint_mul_pow5(ufbxi_bigint *b, uint32_t power) { - // We require evaluation in double precision, either for doubles (0) or always (1) - // and rounding to nearest, which we can check for with `1 + eps == 1 - eps`. - #if defined(FLT_EVAL_METHOD) - #if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 - static volatile double ufbxi_volatile_eps = 2.2250738585072014e-308; - if (1.0 + ufbxi_volatile_eps == 1.0 - ufbxi_volatile_eps) return UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH; - #endif - #endif + for (; power > 27; power -= 27) { + ufbxi_bigint_mad(b, ufbxi_pow5_tab[27], 0); + } + ufbxi_bigint_mad(b, ufbxi_pow5_tab[power], 0); +} - return 0; +static ufbxi_noinline void ufbxi_bigint_shift_left(ufbxi_bigint *bigint, uint32_t amount) +{ + uint32_t words = amount / UFBXI_BIGINT_LIMB_BITS, bits = amount % UFBXI_BIGINT_LIMB_BITS; + ufbxi_bigint b = *bigint; + ufbxi_dev_assert(b.length + words + 1 < b.capacity && b.capacity >= 4); + uint32_t bits_down = UFBXI_BIGINT_LIMB_BITS - bits - 1; + bigint->length += words + (b.limbs[b.length - 1] >> 1 >> bits_down != 0 ? 1 : 0); + b.limbs[b.length] = 0; + if (b.length <= 3 && words <= 3) { + ufbxi_bigint_limb l0 = ufbxi_maybe_uninit(b.length >= 0, b.limbs[0], ~0u); + ufbxi_bigint_limb l1 = ufbxi_maybe_uninit(b.length >= 1, b.limbs[1], ~0u); + ufbxi_bigint_limb l2 = ufbxi_maybe_uninit(b.length >= 2, b.limbs[2], ~0u); + b.limbs[0] = 0; + b.limbs[1] = 0; + b.limbs[2] = 0; + b.limbs[words + 0] = l0 << bits; + b.limbs[words + 1] = (l1 << bits) | (l0 >> 1 >> bits_down); + b.limbs[words + 2] = (l2 << bits) | (l1 >> 1 >> bits_down); + b.limbs[words + 3] = (l2 >> 1 >> bits_down); + } else { + for (uint32_t i = b.length + 1; i-- > 1; ) { + b.limbs[i + words] = (b.limbs[i] << bits) | (b.limbs[i - 1] >> 1 >> bits_down); + } + b.limbs[words] = b.limbs[0] << bits; + for (uint32_t i = 0; i < words; i++) { + b.limbs[i] = 0; + } + } +} + +static ufbxi_bigint_limb ufbxi_bigint_top_limb(const ufbxi_bigint b, uint32_t index) { + return index < b.length ? b.limbs[b.length - 1 - index] : 0; +} + +static ufbxi_noinline uint64_t ufbxi_bigint_extract_high(const ufbxi_bigint b, int32_t *p_exponent, bool *p_tail) +{ + ufbxi_dev_assert(b.length != 0); + uint64_t result = 0; + const uint32_t limb_count = 64 / UFBXI_BIGINT_LIMB_BITS; + for (uint32_t i = 0; i < limb_count; i++) { + result = (result << UFBXI_BIGINT_LIMB_BITS) | ufbxi_bigint_top_limb(b, i); + } + uint32_t shift = ufbxi_lzcnt64(result); + result <<= shift; + ufbxi_bigint_limb lo = ufbxi_bigint_top_limb(b, limb_count); + if (shift > 0) { + result |= lo >> (UFBXI_BIGINT_LIMB_BITS - shift); + } + *p_tail |= (ufbxi_bigint_limb)(lo << shift) != 0; + for (uint32_t i = limb_count + 1; i < b.length; i++) { + *p_tail |= ufbxi_bigint_top_limb(b, i) != 0; + } + *p_exponent += (int32_t)(b.length * UFBXI_BIGINT_LIMB_BITS - shift - 1); + return result; } -static ufbxi_noinline double ufbxi_parse_double_slow(const char *str, char **end) +static uint64_t ufbxi_shift_right_round(uint64_t value, uint32_t shift, bool tail) { - // TODO: Locales - return strtod(str, end); + if (shift == 0) return value; + if (shift > 64) return 0; + uint64_t result = value >> (shift - 1); + uint64_t tail_mask = (UINT64_C(1) << (shift - 1)) - 1; + + bool r_odd = (result & 0x2) != 0; + bool r_round = (result & 0x1) != 0; + bool r_tail = tail || (value & tail_mask) != 0; + uint64_t round_bit = (r_round && (r_odd || r_tail)) ? 1u : 0u; + + return (result >> 1u) + round_bit; } +typedef enum { + UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH = 0x1, + UFBXI_PARSE_DOUBLE_VERIFY_LENGTH = 0x2, + UFBXI_PARSE_DOUBLE_AS_BINARY32 = 0x4, +} ufbxi_parse_double_flag; + static ufbxi_noinline double ufbxi_parse_double(const char *str, size_t max_length, char **end, uint32_t flags) { - // TODO: Use this for optimizing digit parsing - (void)max_length; + const uint32_t max_limbs = 14; - uint64_t integer = 0; - uint32_t n_integer = 0; - int32_t n_decimals = 0; - uint32_t n_exp = 0; - bool negative = false; + ufbxi_bigint_limb mantissa_limbs[42], divisor_limbs[42], quotient_limbs[42]; + ufbxi_bigint big_mantissa = ufbxi_bigint_array(mantissa_limbs); + ufbxi_bigint big_quotient = ufbxi_bigint_array(quotient_limbs); + int32_t dec_exponent = 0, has_dot = 0; + bool negative = false, tail = false, digits_valid = true; + uint64_t digits = 0; + uint32_t num_digits = 0; - // Parse /[+-]?[0-9]*(\.[0-9]*)([eE][+-]?[0-9]*)?/ retaining all digits - // in `integer` and number of decimals in `n_decimals`, exponent simply - // modifies `n_decimals` accordingly. const char *p = str; - if (*p == '-') { - negative = true; - p++; - } else if (*p == '+') { - p++; - } - while (((uint32_t)*p - '0') < 10) { - integer = integer * 10 + (uint64_t)(*p++ - '0'); - n_integer++; + if (*p == '+' || *p == '-') { + negative = *p++ == '-'; } - if (*p == '.') { - p++; - while (((uint32_t)*p - '0') < 10) { - integer = integer * 10 + (uint64_t)(*p++ - '0'); - n_integer++; - n_decimals++; + for (;;) { + char c = *p++; + if (c >= '0' && c <= '9') { + if (big_mantissa.length < max_limbs) { + digits = digits * 10 + (uint64_t)(c - '0'); + num_digits++; + if (num_digits >= 18) { + ufbxi_bigint_mad(&big_mantissa, ufbxi_pow5_tab[num_digits] << num_digits, digits); + digits = 0; + num_digits = 0; + digits_valid = false; + } + dec_exponent -= has_dot; + } else { + dec_exponent += 1 - has_dot; + } + } else if (c == '.' && !has_dot) { + has_dot = true; + } else { + break; } } - if ((*p | 0x20) == 'e') { + p--; + if (*p == 'e' || *p == 'E') { p++; - int32_t exp = 0; - int32_t exp_sign = -1; - if (*p == '-') { - p++; - exp_sign = 1; - } else if (*p == '+') { + bool exp_negative = false; + if (*p == '+' || *p == '-') { + exp_negative = *p == '-'; p++; } - while (((uint32_t)*p - '0') < 10) { - exp = exp * 10 + (int32_t)(*p++ - '0'); - n_exp++; + int32_t exp = 0; + for (;;) { + char c = *p; + if (c >= '0' && c <= '9') { + p++; + exp = exp * 10 + (c - '0'); + if (exp >= 10000) break; + } else { + break; + } } - n_decimals += exp * exp_sign; + dec_exponent += exp_negative ? -exp : exp; } - *end = (char*)p; + *end = (char*)p; // Check that the number is not potentially truncated. if (ufbxi_to_size(p - str) >= max_length && (flags & UFBXI_PARSE_DOUBLE_VERIFY_LENGTH) != 0) { *end = NULL; return 0.0; } - // Overflowed either 64-bit `integer` or 31-bit `exp`. - if (n_integer > 19 || n_exp > 9 || (integer >> 63) != 0) { - return ufbxi_parse_double_slow(str, end); - } - // Both power of 10 and integer are exactly representable as doubles // Powers of 10 are factored as 2*5, and 2^N can be always exactly represented. - if ((flags & UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH) != 0 && n_decimals >= -22 && n_decimals <= 22 && (integer >> 53) == 0) { + if ((flags & UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH) != 0 && big_mantissa.length == 0 && dec_exponent >= -22 && dec_exponent <= 22 && (digits >> 53) == 0) { double value; - if (n_decimals > 0) { - value = (double)integer / ufbxi_pow10_tab_f64[n_decimals]; + if (dec_exponent < 0) { + value = (double)digits / ufbxi_pow10_tab_f64[-dec_exponent]; } else { - value = (double)integer * ufbxi_pow10_tab_f64[-n_decimals]; + value = (double)digits * ufbxi_pow10_tab_f64[dec_exponent]; } return negative ? -value : value; } - // Cannot handle positive exponents here, fortunately the fast case should - // take care of most of them, for negative exponents we can only handle - // up to e-27 as `5^28 > 2^64` and cannot be used as a divisor below. - if (n_decimals < 0) { - return ufbxi_parse_double_slow(str, end); - } else if (!n_decimals || !integer) { - double value = (double)integer; - return negative ? -value : value; - } else if (n_decimals > 27) { - return ufbxi_parse_double_slow(str, end); - } - - // We want to compute `integer / 10^N` precisely, we can do this - // using 128-bit division `2^64 * dividend / divisor`: - // dividend = integer * 2^S (S set such that highest bit is 62) - // divisor = 10^N * 2^T (T set such that highest bit is 63) - // We have to compensate for the shifts in the exponent: - // (2^64 * integer * 2^S) / (10^N * 2^T) * 2^(-1 - S + T) - // To get larger exponent range split 10^N to 5^N * 2^N and move 2^N to the exponent - // (2^64 * integer * 2^S) / (5^N * 2^T) * 2^(-1 - S + T - N) - uint32_t shift = ufbxi_lzcnt64(integer) - 1; - uint64_t dividend = integer << shift; - uint64_t divisor = ufbxi_pow5_tab[n_decimals]; - int32_t exponent = (int32_t)ufbxi_pow2_tab[n_decimals] - (int32_t)shift; // (-1 + T - N) - S - uint64_t rem_hi; - uint64_t b_hi = ufbxi_div128(dividend, 0, divisor, &rem_hi); - - // Align the mantissa so that high bit is set, due to the shifting of the - // divisor and dividend the smallest result is `2^62 + N`, so we need to - // shift at most by one bit. - uint64_t b_bit = 1 - (b_hi >> 63u); - uint64_t mantissa = b_hi << b_bit; - exponent -= (int32_t)b_bit; - - // Round to 53 bits, accounting for potential remainder. - bool nonzero_tail = rem_hi != 0; - bool r_odd = mantissa & (1 << 11u); - bool r_round = mantissa & (1 << 10u); - bool r_tail = (mantissa & ((1 << 10u) - 1)) != 0 || nonzero_tail; - uint64_t round = (r_round && (r_odd || r_tail)) ? 1u : 0u; - - // Assemble the IEEE 754 binary64 number. - uint64_t bits - = (uint64_t)negative << 63u - | (uint64_t)(exponent + 1023) << 52u - | ((mantissa >> 11u) & ~(UINT64_C(1) << 52u)); - bits += round; - - // Type punning via unions is safe in C but in C++ the only safe way - // (pre std::bit_cast) is to use `memcpy()` and hope it gets optimized out. -#if defined(__cplusplus) - double result; - memcpy(&result, &bits, 8); - return result; -#else - union { uint64_t u; double d; } u_to_d; - u_to_d.u = bits; - return u_to_d.d; -#endif + if (big_mantissa.length == 0) { + big_mantissa.limbs[0] = (ufbxi_bigint_limb)digits; + big_mantissa.limbs[1] = (ufbxi_bigint_limb)(digits >> 32u); + big_mantissa.length = (digits >> 32u) ? 2 : digits ? 1 : 0; + if (big_mantissa.length == 0) return negative ? -0.0 : 0.0; + } else { + ufbxi_bigint_mad(&big_mantissa, ufbxi_pow5_tab[num_digits] << num_digits, digits); + } + + uint32_t enc_sign_shift = 63; + uint32_t enc_mantissa_bits = 53; + int32_t enc_max_exponent = 1023; + if (flags & UFBXI_PARSE_DOUBLE_AS_BINARY32) { + enc_sign_shift = 31; + enc_mantissa_bits = 24; + enc_max_exponent = 127; + } + + int32_t exponent = 0; + if (dec_exponent < 0) { + if (dec_exponent + (int32_t)big_mantissa.length * 10 <= -325) return negative ? -0.0 : 0.0; + + ufbxi_bigint big_divisor = ufbxi_bigint_array(divisor_limbs); + uint32_t pow5 = (uint32_t)-dec_exponent; + uint32_t initial_pow5 = pow5 <= 27 ? pow5 : 27; + uint64_t pow5_value = ufbxi_pow5_tab[initial_pow5]; + pow5 -= initial_pow5; + exponent += dec_exponent; + + if (pow5 == 0 && digits_valid && digits >> 63 == 0) { + uint32_t divisor_zeros = ufbxi_lzcnt64(pow5_value); + uint64_t mantissa_zeros = ufbxi_lzcnt64(digits) - 1; + uint64_t divisor_bits = pow5_value << divisor_zeros; + uint64_t mantissa_bits = digits << mantissa_zeros; + big_divisor.limbs[0] = (ufbxi_bigint_limb)divisor_bits; + big_divisor.limbs[1] = (ufbxi_bigint_limb)(divisor_bits >> 32u); + big_divisor.length = 2; + big_mantissa.limbs[0] = 0; + big_mantissa.limbs[1] = 0; + big_mantissa.limbs[2] = (ufbxi_bigint_limb)mantissa_bits; + big_mantissa.limbs[3] = (ufbxi_bigint_limb)(mantissa_bits >> 32u); + big_mantissa.length = 4; + exponent += (int32_t)divisor_zeros - (int32_t)mantissa_zeros - 64; + } else { + big_divisor.limbs[0] = (ufbxi_bigint_limb)pow5_value; + big_divisor.limbs[1] = (ufbxi_bigint_limb)(pow5_value >> 32u); + big_divisor.length = (pow5_value >> 32u) != 0 ? 2 : 1; + if (pow5 > 0) { + ufbxi_bigint_mul_pow5(&big_divisor, pow5); + } + + uint32_t divisor_zeros = ufbxi_lzcnt32(big_divisor.limbs[big_divisor.length - 1]); + if (big_divisor.length == 1) divisor_zeros += UFBXI_BIGINT_LIMB_BITS; + ufbxi_bigint_shift_left(&big_divisor, divisor_zeros); + uint32_t divisor_bits = big_divisor.length * UFBXI_BIGINT_LIMB_BITS; + + uint32_t mantissa_zeros = ufbxi_lzcnt32(big_mantissa.limbs[big_mantissa.length - 1]); + uint32_t mantissa_bits = big_mantissa.length * UFBXI_BIGINT_LIMB_BITS - mantissa_zeros; + uint32_t mantissa_min_bits = divisor_bits + enc_mantissa_bits + 2; + uint32_t mantissa_shift = mantissa_bits < mantissa_min_bits ? mantissa_min_bits - mantissa_bits : 0; + // Align mantissa to never have a high bit, this means we can skip the first digit during division. + mantissa_shift += ((mantissa_shift - mantissa_zeros) & (UFBXI_BIGINT_LIMB_BITS - 1)) == 0 ? 1 : 0; + if (mantissa_shift > 0) { + ufbxi_bigint_shift_left(&big_mantissa, mantissa_shift); + } + exponent += (int32_t)divisor_zeros - (int32_t)mantissa_shift; + } + + tail = ufbxi_bigint_div(&big_quotient, &big_mantissa, &big_divisor); + big_mantissa = big_quotient; + } else if (dec_exponent > 0) { + if (dec_exponent + (int32_t)(big_mantissa.length - 1) * 9 >= 310) return negative ? -UFBX_INFINITY : UFBX_INFINITY; + + exponent += dec_exponent; + ufbxi_bigint_mul_pow5(&big_mantissa, (uint32_t)dec_exponent); + } + + uint64_t mantissa = ufbxi_bigint_extract_high(big_mantissa, &exponent, &tail); + uint64_t sign_bit = (uint64_t)(negative ? 1u : 0u) << enc_sign_shift; + + uint32_t mantissa_shift = 64 - enc_mantissa_bits; + if (exponent > enc_max_exponent) { + return negative ? -UFBX_INFINITY : UFBX_INFINITY; + } else if (exponent <= -enc_max_exponent) { + mantissa_shift += (uint32_t)(-enc_max_exponent + 1 - exponent); + exponent = -enc_max_exponent + 1; + } + + mantissa = ufbxi_shift_right_round(mantissa, mantissa_shift, tail); + if (mantissa == 0) return negative ? -0.0 : 0.0; + + uint64_t bits = mantissa; + bits += (uint64_t)(exponent + enc_max_exponent - 1) << (enc_mantissa_bits - 1); + bits |= sign_bit; + + if (flags & UFBXI_PARSE_DOUBLE_AS_BINARY32) { + uint32_t bits_lo = (uint32_t)bits; + float result; + ufbxi_bit_cast(float, result, uint32_t, bits_lo); + return result; + } else { + double result; + ufbxi_bit_cast(double, result, uint64_t, bits); + return result; + } +} + +static ufbxi_noinline uint32_t ufbxi_parse_double_init_flags() +{ + // We require evaluation in double precision, either for doubles (0) or always (1) + // and rounding to nearest, which we can check for with `1 + eps == 1 - eps`. + #if UFBX_FLT_EVAL_METHOD == 0 || UFBX_FLT_EVAL_METHOD == 1 + static volatile double ufbxi_volatile_eps = 2.2250738585072014e-308; + if (1.0 + ufbxi_volatile_eps == 1.0 - ufbxi_volatile_eps) return UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH; + #endif + + return 0; } static ufbxi_forceinline int64_t ufbxi_parse_int64(const char *str, char **end) @@ -1421,6 +1689,24 @@ static ufbxi_forceinline int64_t ufbxi_parse_int64(const char *str, char **end) return negative ? -(int64_t)abs_val : (int64_t)abs_val; } +static ufbxi_noinline uint32_t ufbxi_parse_uint32_radix(const char *str, uint32_t radix) +{ + uint32_t value = 0; + for (const char *p = str; ; p++) { + char c = *p; + if (c >= '0' && c <= '9') { + value = value * radix + (uint32_t)(c - '0'); + } else if (radix == 16 && (c >= 'a' && c <= 'f')) { + value = value * radix + (uint32_t)(c + (10 - 'a')); + } else if (radix == 16 && (c >= 'A' && c <= 'F')) { + value = value * radix + (uint32_t)(c + (10 - 'A')); + } else { + break; + } + } + return value; +} + // -- DEFLATE implementation #if !defined(ufbx_inflate) @@ -2838,35 +3124,111 @@ ufbxi_extern_c ptrdiff_t ufbx_inflate(void *dst, size_t dst_size, const ufbx_inf uint32_t ref = (uint32_t)bits; ref = (ref>>24) | ((ref>>8)&0xff00) | ((ref<<8)&0xff0000) | (ref<<24); - uint32_t checksum = ufbxi_adler32(dc.out_begin, ufbxi_to_size(dc.out_ptr - dc.out_begin)); - if (ref != checksum) { - return -9; + uint32_t checksum = ufbxi_adler32(dc.out_begin, ufbxi_to_size(dc.out_ptr - dc.out_begin)); + if (ref != checksum) { + return -9; + } + } + } + + return dc.out_ptr - dc.out_begin; +} + +#endif // !defined(ufbx_inflate) + +// -- Printf + +typedef struct { + char *dst; + size_t length; + size_t pos; +} ufbxi_print_buffer; + +#define UFBXI_PRINT_UNSIGNED 0x1 +#define UFBXI_PRINT_STRING 0x2 +#define UFBXI_PRINT_SIZE_T 0x10 + +static void ufbxi_print_append(ufbxi_print_buffer *buf, size_t min_width, size_t max_width, const char *str) +{ + size_t width = 0; + for (width = 0; width < max_width; width++) { + if (!str[width]) break; + } + size_t pad = min_width > width ? min_width - width : 0; + for (size_t i = 0; i < pad; i++) { + if (buf->pos < buf->length) buf->dst[buf->pos++] = ' '; + } + for (size_t i = 0; i < width; i++) { + if (buf->pos < buf->length) buf->dst[buf->pos++] = str[i]; + } +} + +static char *ufbxi_print_format_int(char *buffer, uint64_t value) +{ + *--buffer = '\0'; + do { + uint32_t digit = (uint32_t)(value % 10); + value = value / 10; + *--buffer = (char)('0' + digit); + } while (value > 0); + return buffer; +} + +static void ufbxi_vprint(ufbxi_print_buffer *buf, const char *fmt, va_list args) +{ + char buffer[96]; // ufbxi_uninit + for (const char *p = fmt; *p;) { + if (*p == '%' && *++p != '%') { + size_t min_width = 0, max_width = SIZE_MAX; + if (*p == '*') { + p++; + min_width = (size_t)va_arg(args, int); + } + if (*p == '.') { + ufbxi_dev_assert(p[1] == '*'); + p += 2; + max_width = (size_t)va_arg(args, int); + } + uint32_t flags = 0; + switch (*p) { + case 'z': p++; flags |= UFBXI_PRINT_SIZE_T; break; + default: break; + } + switch (*p++) { + case 'u': flags |= UFBXI_PRINT_UNSIGNED; break; + case 's': flags |= UFBXI_PRINT_STRING; break; + default: break; + } + if (flags & UFBXI_PRINT_STRING) { + const char *str = va_arg(args, const char*); + ufbxi_print_append(buf, min_width, max_width, str); + } else if (flags & UFBXI_PRINT_UNSIGNED) { + uint64_t value = (flags & UFBXI_PRINT_SIZE_T) != 0 ? (uint64_t)va_arg(args, size_t) : (uint64_t)va_arg(args, uint32_t); + char *str = ufbxi_print_format_int(buffer + sizeof(buffer), value); + ufbxi_print_append(buf, min_width, max_width, str); + } else { + ufbxi_unreachable("Bad printf format"); } + } else { + if (buf->pos < buf->length) buf->dst[buf->pos++] = *p; + p++; } } - - return dc.out_ptr - dc.out_begin; + if (buf->length && buf->dst) { + size_t end = buf->pos <= buf->length - 1 ? buf->pos : buf->length - 1; + buf->dst[end] = '\0'; + } } -#endif // !defined(ufbx_inflate) - // -- Errors static const char ufbxi_empty_char[1] = { '\0' }; static ufbxi_noinline int ufbxi_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list args) { - int result = vsnprintf(buf, buf_size, fmt, args); - - if (result < 0) result = 0; - if ((size_t)result >= buf_size - 1) result = (int)buf_size - 1; - - // HACK: On some MSYS/MinGW implementations `vsnprintf` is broken and does - // not write the null terminator on truncation, it's always safe to do so - // let's just do it unconditionally here... - buf[result] = '\0'; - - return result; + ufbxi_print_buffer buffer = { buf, buf_size }; + ufbxi_vprint(&buffer, fmt, args); + return (int)ufbxi_min_sz(buffer.pos, buf_size - 1); } static ufbxi_noinline int ufbxi_snprintf(char *buf, size_t buf_size, const char *fmt, ...) @@ -2883,21 +3245,19 @@ static ufbxi_noinline void ufbxi_panicf_imp(ufbx_panic *panic, const char *fmt, if (panic && panic->did_panic) return; va_list args; // ufbxi_uninit - va_start(args, fmt); if (panic) { + va_start(args, fmt); panic->did_panic = true; panic->message_length = (size_t)ufbxi_vsnprintf(panic->message, sizeof(panic->message), fmt, args); + va_end(args); } else { - fprintf(stderr, "ufbx panic: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - } - - va_end(args); + va_start(args, fmt); + char message[UFBX_PANIC_MESSAGE_LENGTH]; + ufbxi_vsnprintf(message, sizeof(message), fmt, args); + va_end(args); - if (!panic) { - ufbx_assert(false && "ufbx panic: See stderr for more information"); + ufbx_panic_handler(message); } } @@ -3046,7 +3406,7 @@ static ufbxi_noinline void ufbxi_clear_error(ufbx_error *err) #define ufbxi_fail_err_msg(err, desc, msg) return ufbxi_fail_imp_err(err, ufbxi_error_msg(desc, msg), ufbxi_function, ufbxi_line) #define ufbxi_report_err_msg(err, desc, msg) (void)ufbxi_fail_imp_err(err, ufbxi_error_msg(desc, msg), ufbxi_function, ufbxi_line) -static ufbxi_noinline void ufbxi_fix_error_type(ufbx_error *error, const char *default_desc) +static ufbxi_noinline void ufbxi_fix_error_type(ufbx_error *error, const char *default_desc, ufbx_error *p_error) { const char *desc = error->description.data; if (!desc) desc = default_desc; @@ -3096,6 +3456,9 @@ static ufbxi_noinline void ufbxi_fix_error_type(ufbx_error *error, const char *d } error->description.data = desc; error->description.length = strlen(desc); + if (p_error) { + memcpy(p_error, error, sizeof(ufbx_error)); + } } // -- Allocator @@ -3168,7 +3531,7 @@ static ufbxi_noinline void *ufbxi_alloc_size(ufbxi_allocator *ator, size_t size, } else if (ator->ator.allocator.realloc_fn) { ptr = ator->ator.allocator.realloc_fn(ator->ator.allocator.user, NULL, 0, total); } else { - ptr = malloc(total); + ptr = ufbx_malloc(total); } if (!ptr) { @@ -3215,7 +3578,7 @@ static ufbxi_noinline void *ufbxi_realloc_size(ufbxi_allocator *ator, size_t siz ator->ator.allocator.free_fn(ator->ator.allocator.user, old_ptr, old_total); } } else { - ptr = realloc(old_ptr, total); + ptr = ufbx_realloc(old_ptr, old_total, total); } ufbxi_check_return_err_msg(ator->error, ptr, NULL, "Out of memory"); @@ -3249,7 +3612,7 @@ static ufbxi_noinline void ufbxi_free_size(ufbxi_allocator *ator, size_t size, v ator->ator.allocator.realloc_fn(ator->ator.allocator.user, ptr, total, 0); } } else { - free(ptr); + ufbx_free(ptr, total); } } @@ -3888,7 +4251,7 @@ static ufbxi_noinline void ufbxi_map_init(ufbxi_map *map, ufbxi_allocator *ator, // allocation counts. We can work around this using a local allocator that doesn't // count the allocations. { - ufbxi_allocator *regression_ator = (ufbxi_allocator*)malloc(sizeof(ufbxi_allocator)); + ufbxi_allocator *regression_ator = (ufbxi_allocator*)ufbx_malloc(sizeof(ufbxi_allocator)); ufbx_assert(regression_ator); memset(regression_ator, 0, sizeof(ufbxi_allocator)); regression_ator->name = "regression"; @@ -3922,7 +4285,7 @@ static ufbxi_noinline void ufbxi_map_free(ufbxi_map *map) #if defined(UFBX_REGRESSION) if (regression_ator) { ufbxi_free_ator(regression_ator); - free(regression_ator); + ufbx_free(regression_ator, sizeof(ufbxi_allocator)); } #endif } @@ -5923,10 +6286,8 @@ typedef struct { // IO uint64_t data_offset; - ufbx_read_fn *read_fn; ufbx_skip_fn *skip_fn; - ufbx_close_fn *close_fn; void *read_user; char *read_buffer; @@ -6026,6 +6387,10 @@ typedef struct { // Temporary per-element flags uint8_t *tmp_element_flag; + // IO (cold) + ufbx_close_fn *close_fn; + ufbx_size_fn *size_fn; + ufbxi_ascii ascii; bool has_geometry_transform_nodes; @@ -6065,6 +6430,10 @@ typedef struct { ufbxi_warnings warnings; bool deferred_failure; + bool deferred_load; + + const char *load_filename; + size_t load_filename_len; bool parse_threaded; ufbxi_thread_pool thread_pool; @@ -6348,8 +6717,6 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_to(ufbxi_context *uc, void return 1; } -// -- File IO - static ufbxi_noinline void ufbxi_init_ator(ufbx_error *error, ufbxi_allocator *ator, const ufbx_allocator_opts *opts, const char *name) { ufbx_allocator_opts zero_opts; @@ -6369,19 +6736,56 @@ static ufbxi_noinline void ufbxi_init_ator(ufbx_error *error, ufbxi_allocator *a ator->name = name; } -static ufbxi_noinline FILE *ufbxi_fopen(const char *path, size_t path_len, ufbxi_allocator *tmp_ator) +typedef struct { + ufbx_error error; + + ufbxi_allocator *parent_ator; + ufbxi_allocator ator; +} ufbxi_file_context; + +static ufbxi_noinline void ufbxi_begin_file_context(ufbxi_file_context *fc, ufbx_open_file_context ctx, const ufbx_allocator_opts *ator_opts) { -#if !defined(UFBX_STANDARD_C) && defined(_WIN32) - wchar_t wpath_buf[256]; - wchar_t *wpath = NULL; + memset(fc, 0, sizeof(ufbxi_file_context)); + if (ctx) { + fc->parent_ator = (ufbxi_allocator*)ctx; + fc->ator = *fc->parent_ator; + fc->ator.error = &fc->error; + } else { + ufbxi_init_ator(&fc->error, &fc->ator, ator_opts, "file"); + } +} - if (path_len == SIZE_MAX) { - path_len = strlen(path); +static ufbxi_noinline void ufbxi_end_file_context(ufbxi_file_context *fc, ufbx_error *error, bool ok) +{ + if (fc->parent_ator) { + fc->ator.error = fc->parent_ator->error; + *fc->parent_ator = fc->ator; + } else { + ufbxi_free_ator(&fc->ator); + } + if (error) { + if (!ok) { + ufbxi_fix_error_type(&fc->error, "Failed to open file", error); + } else { + ufbxi_clear_error(error); + } } +} + +// -- File IO + +#if !defined(UFBX_NO_STDIO) && !defined(UFBX_EXTERNAL_STDIO) + +static ufbxi_noinline FILE *ufbxi_fopen(ufbxi_file_context *fc, const char *path, size_t path_len, bool null_terminated) +{ + FILE *file = NULL; +#if !defined(UFBX_STANDARD_C) && defined(_WIN32) + (void)null_terminated; + wchar_t wpath_buf[256], *wpath = NULL; // ufbxi_uninit if (path_len < ufbxi_arraycount(wpath_buf) - 1) { wpath = wpath_buf; } else { - wpath = ufbxi_alloc(tmp_ator, wchar_t, path_len + 1); + wpath = ufbxi_alloc(&fc->ator, wchar_t, path_len + 1); if (!wpath) return NULL; } @@ -6416,45 +6820,38 @@ static ufbxi_noinline FILE *ufbxi_fopen(const char *path, size_t path_len, ufbxi } wpath[wlen] = 0; - FILE *file = NULL; -#if UFBXI_MSC_VER >= 1400 - if (_wfopen_s(&file, wpath, L"rb") != 0) { - file = NULL; - } -#else - file = _wfopen(wpath, L"rb"); -#endif - + #if UFBXI_MSC_VER >= 1400 + if (_wfopen_s(&file, wpath, L"rb") != 0) file = NULL; + #else + file = _wfopen(wpath, L"rb"); + #endif if (wpath != wpath_buf) { - ufbxi_free(tmp_ator, wchar_t, wpath, path_len + 1); + ufbxi_free(&fc->ator, wchar_t, wpath, path_len + 1); } - - return file; #else - if (path_len == SIZE_MAX) { - return fopen(path, "rb"); - } - - char copy_buf[256]; // ufbxi_uninit - char *copy = NULL; - - if (path_len < ufbxi_arraycount(copy_buf) - 1) { - copy = copy_buf; + char copy_buf[256], *copy = NULL; // ufbxi_uninit + if (null_terminated) { + copy = (char*)path; } else { - copy = ufbxi_alloc(tmp_ator, char, path_len + 1); - if (!copy) return NULL; + if (path_len < ufbxi_arraycount(copy_buf) - 1) { + copy = copy_buf; + } else { + copy = ufbxi_alloc(&fc->ator, char, path_len + 1); + if (!copy) return NULL; + } + memcpy(copy, path, path_len); + copy[path_len] = '\0'; } - memcpy(copy, path, path_len); - copy[path_len] = '\0'; - - FILE *file = fopen(copy, "rb"); - - if (copy != copy_buf) { - ufbxi_free(tmp_ator, char, copy, path_len + 1); + file = fopen(copy, "rb"); + if (!null_terminated && copy != copy_buf) { + ufbxi_free(&fc->ator, char, copy, path_len + 1); } - - return file; #endif + if (!file) { + ufbxi_set_err_info(&fc->error, path, path_len); + ufbxi_report_err_msg(&fc->error, "file", "File not found"); + } + return file; } static uint64_t ufbxi_ftell(FILE *file) @@ -6466,20 +6863,20 @@ static uint64_t ufbxi_ftell(FILE *file) int64_t result = _ftelli64(file); if (result >= 0) return (uint64_t)result; #else - long result = ftell(file); + int64_t result = ftell(file); if (result >= 0) return (uint64_t)result; #endif return UINT64_MAX; } -static size_t ufbxi_file_read(void *user, void *data, size_t max_size) +static size_t ufbxi_stdio_read(void *user, void *data, size_t max_size) { FILE *file = (FILE*)user; if (ferror(file)) return SIZE_MAX; return fread(data, 1, max_size, file); } -static bool ufbxi_file_skip(void *user, size_t size) +static bool ufbxi_stdio_skip(void *user, size_t size) { FILE *file = (FILE*)user; ufbx_assert(size <= UFBXI_MAX_SKIP_SIZE); @@ -6488,12 +6885,94 @@ static bool ufbxi_file_skip(void *user, size_t size) return true; } -static void ufbxi_file_close(void *user) +static uint64_t ufbxi_stdio_size(void *user) +{ + FILE *file = (FILE*)user; + uint64_t result = 0; + uint64_t begin = ufbxi_ftell(file); + if (begin < UINT64_MAX) { + fpos_t pos; // ufbxi_uninit + if (fgetpos(file, &pos) == 0) { + if (fseek(file, 0, SEEK_END) == 0) { + uint64_t end = ufbxi_ftell(file); + if (end != UINT64_MAX && begin < end) { + result = end - begin; + } + // Both `rewind()` and `fsetpos()` to reset error and EOF + rewind(file); + fsetpos(file, &pos); + } + } + } + return result; +} + +static void ufbxi_stdio_close(void *user) { FILE *file = (FILE*)user; fclose(file); } +static ufbxi_noinline void ufbxi_stdio_init(ufbx_stream *stream, void *file, bool close) +{ + stream->read_fn = &ufbxi_stdio_read; + stream->skip_fn = &ufbxi_stdio_skip; + stream->size_fn = &ufbxi_stdio_size; + stream->close_fn = close ? &ufbxi_stdio_close : NULL; + stream->user = file; +} + +static ufbxi_noinline bool ufbxi_stdio_open(ufbxi_file_context *fc, ufbx_stream *stream, const char *path, size_t path_len, bool null_terminated) +{ + FILE *file = ufbxi_fopen(fc, path, path_len, null_terminated); + if (!file) return false; + ufbxi_stdio_init(stream, file, true); + return true; +} + +#elif defined(UFBX_EXTERNAL_STDIO) + +static ufbxi_noinline void ufbxi_stdio_init(ufbx_stream *stream, void *file, bool close) +{ + stream->read_fn = &ufbx_stdio_read; + stream->skip_fn = &ufbx_stdio_skip; + stream->size_fn = &ufbx_stdio_size; + stream->close_fn = close ? &ufbx_stdio_close : NULL; + stream->user = file; +} + +static ufbxi_noinline bool ufbxi_stdio_open(ufbxi_file_context *fc, ufbx_stream *stream, const char *path, size_t path_len, bool null_terminated) +{ + char copy_buf[256], *copy = NULL; // ufbxi_uninit + if (null_terminated) { + copy = (char*)path; + } else { + if (path_len < ufbxi_arraycount(copy_buf) - 1) { + copy = copy_buf; + } else { + copy = ufbxi_alloc(&fc->ator, char, path_len + 1); + if (!copy) return false; + } + memcpy(copy, path, path_len); + copy[path_len] = '\0'; + } + void *file = ufbx_stdio_open(copy, path_len); + if (!null_terminated && copy != copy_buf) { + ufbxi_free(&fc->ator, char, copy, path_len + 1); + } + if (!file) { + ufbxi_set_err_info(&fc->error, path, path_len); + ufbxi_report_err_msg(&fc->error, "file", "File not found"); + return false; + } + ufbxi_stdio_init(stream, file, true); + return true; +} + +#endif + +// -- Memory IO + typedef struct { const void *data; size_t size; @@ -6502,7 +6981,8 @@ typedef struct { // Own allocation information size_t self_size; - ufbxi_allocator ator; + ufbxi_allocator *parent_ator; + ufbxi_allocator local_ator; ufbx_error error; char data_copy[]; } ufbxi_memory_stream; @@ -6524,6 +7004,12 @@ static bool ufbxi_memory_skip(void *user, size_t size) return true; } +static uint64_t ufbxi_memory_size(void *user) +{ + ufbxi_memory_stream *stream = (ufbxi_memory_stream*)user; + return stream->size; +} + static void ufbxi_memory_close(void *user) { ufbxi_memory_stream *stream = (ufbxi_memory_stream*)user; @@ -6531,9 +7017,13 @@ static void ufbxi_memory_close(void *user) stream->close_cb.fn(stream->close_cb.user, (void*)stream->data, stream->size); } - ufbxi_allocator ator = stream->ator; - ufbxi_free(&ator, char, stream, stream->self_size); - ufbxi_free_ator(&ator); + if (stream->parent_ator) { + ufbxi_free(stream->parent_ator, char, stream, stream->self_size); + } else { + ufbxi_allocator ator = stream->local_ator; + ufbxi_free(&ator, char, stream, stream->self_size); + ufbxi_free_ator(&ator); + } } // -- XML @@ -6703,9 +7193,9 @@ static ufbxi_noinline int ufbxi_xml_read_until(ufbxi_xml_context *xc, ufbx_strin if (entity[0] == '#') { unsigned long code = 0; if (entity[1] == 'x') { - code = strtoul(entity + 2, NULL, 16); + code = ufbxi_parse_uint32_radix(entity + 2, 16); } else { - code = strtoul(entity + 1, NULL, 10); + code = ufbxi_parse_uint32_radix(entity + 1, 10); } char bytes[5] = { 0 }; @@ -9098,11 +9588,9 @@ ufbxi_nodiscard ufbxi_noinline static int ufbxi_ascii_next_token(ufbxi_context * token->value.i64 = ufbxi_parse_int64(token->str_data, &end); ufbxi_check(end == token->str_data + token->str_len - 1); } else if (token->type == UFBXI_ASCII_FLOAT) { - if (ua->parse_as_f32) { - token->value.f64 = strtof(token->str_data, &end); - } else { - token->value.f64 = ufbxi_parse_double(token->str_data, token->str_len, &end, uc->double_parse_flags); - } + uint32_t flags = uc->double_parse_flags; + if (ua->parse_as_f32) flags = UFBXI_PARSE_DOUBLE_AS_BINARY32; + token->value.f64 = ufbxi_parse_double(token->str_data, token->str_len, &end, flags); ufbxi_check(end == token->str_data + token->str_len - 1); } } @@ -9499,8 +9987,6 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_ascii_read_float_array(ufbxi_con *v = (float)val; } - // TODO: Collect ASCII numbers to deferred parse integer/string segments - // Try to parse the next value, we don't commit this until we find a comma after it above. char *num_end = NULL; size_t left = ufbxi_to_size(end - src_scan); @@ -15725,44 +16211,12 @@ ufbxi_nodiscard ufbxi_noinline static int ufbxi_resolve_relative_filename(ufbxi_ // Open file utility -static void *ufbxi_ator_alloc(void *user, size_t size) -{ - ufbxi_allocator *ator = (ufbxi_allocator*)user; - return ufbxi_alloc(ator, char, size); -} - -static void *ufbxi_ator_realloc(void *user, void *old_ptr, size_t old_size, size_t new_size) -{ - ufbxi_allocator *ator = (ufbxi_allocator*)user; - return ufbxi_realloc(ator, char, old_ptr, old_size, new_size); -} - -static void ufbxi_ator_free(void *user, void *ptr, size_t size) -{ - ufbxi_allocator *ator = (ufbxi_allocator*)user; - ufbxi_free(ator, char, ptr, size); -} - -static ufbxi_noinline void ufbxi_setup_ator_allocator(ufbx_allocator *allocator, ufbxi_allocator *ator) -{ - allocator->alloc_fn = &ufbxi_ator_alloc; - allocator->realloc_fn = &ufbxi_ator_realloc; - allocator->free_fn = &ufbxi_ator_free; - allocator->free_allocator_fn = NULL; - allocator->user = ator; -} - static ufbxi_noinline bool ufbxi_open_file(const ufbx_open_file_cb *cb, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_blob *original_filename, ufbxi_allocator *ator, ufbx_open_file_type type) { if (!cb || !cb->fn) return false; ufbx_open_file_info info; // ufbxi_uninit - if (ator) { - ufbxi_setup_ator_allocator(&info.temp_allocator, ator); - } else { - memset(&info.temp_allocator, 0, sizeof(info.temp_allocator)); - } - + info.context = (uintptr_t)ator; if (original_filename) { info.original_filename = *original_filename; } else { @@ -17084,6 +17538,7 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_load_mtl(ufbxi_context *uc) if (!has_stream && uc->opts.load_external_files && uc->opts.obj_search_mtl_by_filename && path.length > 4) { ufbx_string ext = { path.data + path.length - 4, 4 }; if (ufbxi_match(&ext, "\\c.obj")) { + ufbxi_analysis_assert(path.length < SIZE_MAX - 1); char *copy = ufbxi_push_copy(&uc->tmp, char, path.length + 1, path.data); ufbxi_check(copy); copy[path.length - 3] = copy[path.length - 3] == 'O' ? 'M' : 'm'; @@ -23237,9 +23692,9 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_xml_imp(ufbxi_cache_c if (tag_fps) { ufbxi_xml_attrib *fps = ufbxi_xml_find_attrib(tag_fps, "TimePerFrame"); if (fps) { - int value = atoi(fps->value.data); + uint32_t value = ufbxi_parse_uint32_radix(fps->value.data, 10); if (value > 0) { - cc->xml_ticks_per_frame = (uint32_t)value; + cc->xml_ticks_per_frame = value; } } } @@ -23264,9 +23719,9 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_xml_imp(ufbxi_cache_c ufbxi_xml_attrib *start_time = ufbxi_xml_find_attrib(tag, "StartTime"); ufbxi_xml_attrib *end_time = ufbxi_xml_find_attrib(tag, "EndTime"); if (sampling_rate && start_time && end_time) { - channel->sample_rate = (uint32_t)atoi(sampling_rate->value.data); - channel->start_time = (uint32_t)atoi(start_time->value.data); - channel->end_time = (uint32_t)atoi(end_time->value.data); + channel->sample_rate = ufbxi_parse_uint32_radix(sampling_rate->value.data, 10); + channel->start_time = ufbxi_parse_uint32_radix(start_time->value.data, 10); + channel->end_time = ufbxi_parse_uint32_radix(end_time->value.data, 10); channel->current_time = channel->start_time; channel->try_load = true; } @@ -23591,7 +24046,7 @@ ufbxi_noinline static ufbx_geometry_cache *ufbxi_cache_load(ufbxi_cache_context if (ok) { return &cc->imp->cache; } else { - ufbxi_fix_error_type(&cc->error, "Failed to load geometry cache"); + ufbxi_fix_error_type(&cc->error, "Failed to load geometry cache", NULL); if (!cc->owned_by_scene) { ufbxi_buf_free(&cc->string_pool.buf); ufbxi_free_ator(&cc->ator_result); @@ -24090,6 +24545,50 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_load_imp(ufbxi_context *uc) { // Check for deferred failure if (uc->deferred_failure) return 0; + if (uc->deferred_load) { + ufbx_stream stream = { 0 }; + ufbx_open_file_opts opts = { 0 }; + const char *filename = uc->load_filename; + size_t filename_len = uc->load_filename_len; + bool ok = false; + if (filename_len == SIZE_MAX) { + opts.filename_null_terminated = true; + filename_len = strlen(filename); + } + if (uc->opts.filename.length == 0 || uc->opts.filename.data == NULL) { + uc->opts.filename.data = filename; + uc->opts.filename.length = filename_len; + } + ufbx_error error; + error.type = UFBX_ERROR_NONE; + if (uc->opts.open_main_file_with_default || uc->opts.open_file_cb.fn == &ufbx_default_open_file) { + ufbx_open_file_context ctx = (ufbx_open_file_context)&uc->ator_tmp; + ok = ufbx_open_file_ctx(&stream, ctx, filename, filename_len, &opts, &error); + } else { + ok = ufbxi_open_file(&uc->opts.open_file_cb, &stream, uc->load_filename, filename_len, NULL, &uc->ator_tmp, UFBX_OPEN_FILE_MAIN_MODEL); + } + if (!ok) { + if (error.type != UFBX_ERROR_NONE) { + // cppcheck-suppress uninitStructMember + uc->error = error; + } else { + ufbxi_set_err_info(&uc->error, filename, filename_len); + } + ufbxi_fail_msg("open_file_fn()", "File not found"); + } + uc->read_fn = stream.read_fn; + uc->skip_fn = stream.skip_fn; + uc->size_fn = stream.size_fn; + uc->close_fn = stream.close_fn; + uc->read_user = stream.user; + } + + if (uc->opts.progress_cb.fn && uc->progress_bytes_total == 0 && uc->size_fn) { + uint64_t total = uc->size_fn(uc->read_user); + ufbxi_check(total != UINT64_MAX); + uc->progress_bytes_total = total; + } + ufbxi_check(uc->opts.path_separator >= 0x20 && uc->opts.path_separator <= 0x7e); ufbxi_check(ufbxi_fixup_opts_string(uc, &uc->opts.filename, false)); @@ -24431,34 +24930,24 @@ static ufbxi_noinline ufbx_scene *ufbxi_load(ufbxi_context *uc, const ufbx_load_ int ok = ufbxi_load_imp(uc); - ufbxi_free_temp(uc); - if (uc->close_fn) { uc->close_fn(uc->read_user); } + ufbxi_free_temp(uc); + if (ok) { if (p_error) { ufbxi_clear_error(p_error); } return &uc->scene_imp->scene; } else { - ufbxi_fix_error_type(&uc->error, "Failed to load"); - if (p_error) *p_error = uc->error; + ufbxi_fix_error_type(&uc->error, "Failed to load", p_error); ufbxi_free_result(uc); return NULL; } } -static ufbxi_noinline ufbx_scene *ufbxi_load_not_found(const char *filename, size_t filename_len, ufbx_error *p_error) -{ - ufbxi_context uc = { UFBX_ERROR_NONE }; - ufbxi_set_err_info(&uc.error, filename, filename_len); - ufbxi_report_err_msg(&uc.error, "File not found", "File not found"); - uc.deferred_failure = true; - return ufbxi_load(&uc, NULL, p_error); -} - // -- Animation evaluation static ufbxi_forceinline bool ufbxi_override_less_than_prop(const ufbx_prop_override *over, uint32_t element_id, const ufbx_prop *prop) @@ -25240,8 +25729,7 @@ ufbxi_nodiscard static ufbxi_noinline ufbx_scene *ufbxi_evaluate_scene(ufbxi_eva } return &ec->scene_imp->scene; } else { - ufbxi_fix_error_type(&ec->error, "Failed to evaluate"); - if (p_error) *p_error = ec->error; + ufbxi_fix_error_type(&ec->error, "Failed to evaluate", p_error); ufbxi_buf_free(&ec->tmp); ufbxi_buf_free(&ec->result); ufbxi_free_ator(&ec->ator_tmp); @@ -25310,11 +25798,11 @@ static bool ufbxi_prop_override_less(void *user, const void *va, const void *vb) return strcmp(a->prop_name.data, b->prop_name.data) < 0; } -static int ufbxi_cmp_transform_override(const void *va, const void *vb) +static bool ufbxi_transform_override_less(void *user, const void *va, const void *vb) { + (void)user; const ufbx_transform_override *a = (const ufbx_transform_override*)va, *b = (const ufbx_transform_override*)vb; - if (a->node_id != b->node_id) return a->node_id < b->node_id ? -1 : 1; - return 0; + return a->node_id < b->node_id; } ufbxi_nodiscard static ufbxi_noinline int ufbxi_create_anim_imp(ufbxi_create_anim_context *ac) @@ -25419,8 +25907,7 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_create_anim_imp(ufbxi_create_ani anim->transform_overrides.count = ac->opts.transform_overrides.count; anim->transform_overrides.data = ufbxi_push_copy(&ac->result, ufbx_transform_override, anim->transform_overrides.count, ac->opts.transform_overrides.data); ufbxi_check_err(&ac->error, anim->transform_overrides.data); - - qsort(anim->transform_overrides.data, anim->transform_overrides.count, sizeof(ufbx_transform_override), &ufbxi_cmp_transform_override); + ufbxi_unstable_sort(anim->transform_overrides.data, anim->transform_overrides.count, sizeof(ufbx_transform_override), &ufbxi_transform_override_less, NULL); } ac->imp = ufbxi_push(&ac->result, ufbxi_anim_imp, 1); @@ -25473,6 +25960,9 @@ typedef struct { ufbx_baked_node **baked_nodes; bool *nodes_to_bake; + char *tmp_arr; + size_t tmp_arr_size; + const ufbx_scene *scene; const ufbx_anim *anim; ufbx_bake_opts opts; @@ -25495,14 +25985,15 @@ typedef struct { ufbx_anim_value *anim_value; } ufbxi_bake_prop; -static int ufbxi_cmp_bake_prop(const void *va, const void *vb) +static bool ufbxi_bake_prop_less(void *user, const void *va, const void *vb) { + (void)user; const ufbxi_bake_prop *a = (const ufbxi_bake_prop*)va; const ufbxi_bake_prop *b = (const ufbxi_bake_prop*)vb; - if (a->sort_id != b->sort_id) return a->sort_id < b->sort_id ? -1 : 1; - if (a->element_id != b->element_id) return a->element_id < b->element_id ? -1 : 1; - if (a->prop_name != b->prop_name) return strcmp(a->prop_name, b->prop_name); - return a->anim_value < b->anim_value; + if (a->sort_id != b->sort_id) return a->sort_id < b->sort_id; + if (a->element_id != b->element_id) return a->element_id < b->element_id; + if (a->prop_name != b->prop_name) return strcmp(a->prop_name, b->prop_name) < 0; + return false; } ufbx_static_assert(bake_step_left, UFBX_BAKED_KEY_STEP_LEFT == 0x1); @@ -25518,13 +26009,6 @@ static ufbxi_forceinline int ufbxi_cmp_bake_time(ufbxi_bake_time a, ufbxi_bake_t return 0; } -static int ufbxi_cmp_bake_time_fn(const void *va, const void *vb) -{ - const ufbxi_bake_time a = *(const ufbxi_bake_time*)va; - const ufbxi_bake_time b = *(const ufbxi_bake_time*)vb; - return ufbxi_cmp_bake_time(a, b); -} - ufbxi_nodiscard static ufbxi_forceinline int ufbxi_bake_push_time(ufbxi_bake_context *bc, double time, uint32_t flags) { ufbxi_bake_time *p_key = ufbxi_push_fast(&bc->tmp_times, ufbxi_bake_time, 1); @@ -25609,6 +26093,13 @@ ufbxi_nodiscard static ufbxi_noinline bool ufbxi_in_list(const char *const *item return false; } +ufbxi_nodiscard static ufbxi_noinline int ufbxi_sort_bake_times(ufbxi_bake_context *bc, ufbxi_bake_time *times, size_t count) +{ + ufbxi_check_err(&bc->error, ufbxi_grow_array(&bc->ator_tmp, &bc->tmp_arr, &bc->tmp_arr_size, count * sizeof(ufbxi_bake_time))); + ufbxi_macro_stable_sort(ufbxi_bake_time, 32, times, bc->tmp_arr, count, ( ufbxi_cmp_bake_time(*a, *b) < 0 )); + return 1; +} + ufbxi_nodiscard static ufbxi_noinline int ufbxi_finalize_bake_times(ufbxi_bake_context *bc, ufbxi_bake_time_list *p_dst) { if (bc->layer_weight_times.count > 0) { @@ -25624,8 +26115,7 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_finalize_bake_times(ufbxi_bake_c ufbxi_bake_time *times = ufbxi_push_pop(&bc->tmp_prop, &bc->tmp_times, ufbxi_bake_time, num_times); ufbxi_check_err(&bc->error, times); - // TODO: Something better - qsort(times, num_times, sizeof(ufbxi_bake_time), &ufbxi_cmp_bake_time_fn); + ufbxi_check_err(&bc->error, ufbxi_sort_bake_times(bc, times, num_times)); // Deduplicate times if (num_times > 0) { @@ -25736,13 +26226,13 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_finalize_bake_times(ufbxi_bake_c #define ufbxi_add_epsilon(a, epsilon) ((a)>0 ? (a)*(epsilon) : (a)/(epsilon)) #define ufbxi_sub_epsilon(a, epsilon) ((a)>0 ? (a)/(epsilon) : (a)*(epsilon)) -static ufbxi_noinline bool ufbxi_postprocess_step(ufbxi_bake_context *bc, double prev_time, double next_time, double *p_time, uint32_t flags) +static ufbxi_noinline bool ufbxi_postprocess_step(ufbxi_bake_context *bc, double prev_time, double next_time, double *p_time, ufbx_baked_key_flags flags) { ufbxi_dev_assert((flags & (UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT)) != 0); bool left = (flags & UFBX_BAKED_KEY_STEP_LEFT) != 0; double step = 0.001; - double epsilon = 1.0 + FLT_EPSILON * 4.0f; + double epsilon = 1.0 + UFBX_FLT_EPSILON * 4.0f; double time = *p_time; switch (bc->opts.step_handling) { @@ -25982,7 +26472,7 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_push_resampled_times(ufbxi_bake_ ufbxi_bake_time *times = ufbxi_push(&bc->tmp_times, ufbxi_bake_time, keys.count); ufbxi_check_err(&bc->error, times); for (size_t i = 0; i < keys.count; i++) { - uint32_t flags = keys.data[i].flags; + ufbx_baked_key_flags flags = keys.data[i].flags; double time = keys.data[i].time; if ((flags & UFBX_BAKED_KEY_STEP_LEFT) != 0 && i + 1 < keys.count && (keys.data[i + 1].flags & UFBX_BAKED_KEY_STEP_KEY) != 0) { time = keys.data[i + 1].time; @@ -26402,8 +26892,7 @@ ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_anim(ufbxi_bake_context *bc ufbxi_bake_prop *props = ufbxi_push_pop(&bc->tmp, &bc->tmp_bake_props, ufbxi_bake_prop, num_props); ufbxi_check_err(&bc->error, props); - // TODO: Macro unstable/non allocating sort - qsort(props, num_props, sizeof(ufbxi_bake_prop), &ufbxi_cmp_bake_prop); + ufbxi_unstable_sort(props, num_props, sizeof(ufbxi_bake_prop), &ufbxi_bake_prop_less, NULL); // Pre-bake layer weight times if (!bc->opts.ignore_layer_weight_animation) { @@ -27453,19 +27942,19 @@ ufbxi_noinline static uint32_t ufbxi_triangulate_ngon(ufbxi_ngon_context *nc, ui #endif -static int ufbxi_cmp_topo_index_prev_next(const void *va, const void *vb) +static bool ufbxi_topo_less_index_prev_next(void *user, const void *va, const void *vb) { + (void)user; const ufbx_topo_edge *a = (const ufbx_topo_edge*)va, *b = (const ufbx_topo_edge*)vb; - if ((int32_t)a->prev != (int32_t)b->prev) return (int32_t)a->prev < (int32_t)b->prev ? -1 : +1; - if ((int32_t)a->next != (int32_t)b->next) return (int32_t)a->next < (int32_t)b->next ? -1 : +1; - return 0; + if ((int32_t)a->prev != (int32_t)b->prev) return (int32_t)a->prev < (int32_t)b->prev; + return (int32_t)a->next < (int32_t)b->next; } -static int ufbxi_cmp_topo_index_index(const void *va, const void *vb) +static bool ufbxi_topo_less_index_index(void *user, const void *va, const void *vb) { + (void)user; const ufbx_topo_edge *a = (const ufbx_topo_edge*)va, *b = (const ufbx_topo_edge*)vb; - if ((int32_t)a->index != (int32_t)b->index) return (int32_t)a->index < (int32_t)b->index ? -1 : +1; - return 0; + return (int32_t)a->index < (int32_t)b->index; } ufbxi_noinline static void ufbxi_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo) @@ -27494,8 +27983,7 @@ ufbxi_noinline static void ufbxi_compute_topology(const ufbx_mesh *mesh, ufbx_to } } - // TODO: Macro unstable/non allocating sort - qsort(topo, num_indices, sizeof(ufbx_topo_edge), &ufbxi_cmp_topo_index_prev_next); + ufbxi_unstable_sort(topo, num_indices, sizeof(ufbx_topo_edge), &ufbxi_topo_less_index_prev_next, NULL); if (mesh->edges.data) { for (uint32_t ei = 0; ei < mesh->num_edges; ei++) { @@ -27535,8 +28023,7 @@ ufbxi_noinline static void ufbxi_compute_topology(const ufbx_mesh *mesh, ufbx_to i0 = i1 + 1; } - // TODO: Macro unstable/non allocating sort - qsort(topo, num_indices, sizeof(ufbx_topo_edge), &ufbxi_cmp_topo_index_index); + ufbxi_unstable_sort(topo, num_indices, sizeof(ufbx_topo_edge), &ufbxi_topo_less_index_index, NULL); // Fix `prev` and `next` to the actual index values for (uint32_t fi = 0; fi < mesh->num_faces; fi++) { @@ -27702,12 +28189,13 @@ static int ufbxi_subdivide_sum_vec4(void *user, void *output, const ufbxi_subdiv return 1; } -static ufbxi_noinline int ufbxi_cmp_subdivision_weight(const void *va, const void *vb) +static ufbxi_noinline bool ufbxi_subdivision_weight_less(void *user, const void *va, const void *vb) { + (void)user; ufbx_subdivision_weight a = *(const ufbx_subdivision_weight*)va, b = *(const ufbx_subdivision_weight*)vb; ufbxi_dev_assert(a.index != b.index); - if (a.weight != b.weight) return a.weight > b.weight ? -1 : +1; - return a.index < b.index ? -1 : +1; + if (a.weight != b.weight) return a.weight > b.weight; + return a.index < b.index; } static int ufbxi_subdivide_sum_vertex_weights(void *user, void *output, const ufbxi_subdivide_input *inputs, size_t num_inputs) @@ -27743,7 +28231,7 @@ static int ufbxi_subdivide_sum_vertex_weights(void *user, void *output, const uf vertex_weights[vx] = 0.0f; } - qsort(tmp_weights, num_weights, sizeof(ufbx_subdivision_weight), ufbxi_cmp_subdivision_weight); + ufbxi_unstable_sort(tmp_weights, num_weights, sizeof(ufbx_subdivision_weight), ufbxi_subdivision_weight_less, NULL); if (sc->max_vertex_weights != SIZE_MAX) { num_weights = ufbxi_min_sz(sc->max_vertex_weights, num_weights); @@ -28823,8 +29311,7 @@ ufbxi_noinline static ufbx_mesh *ufbxi_subdivide_mesh(const ufbx_mesh *mesh, siz ufbxi_mesh_imp *imp = sc.imp; return &imp->mesh; } else { - ufbxi_fix_error_type(&sc.error, "Failed to subdivide"); - if (p_error) *p_error = sc.error; + ufbxi_fix_error_type(&sc.error, "Failed to subdivide", p_error); ufbxi_buf_free(&sc.result); ufbxi_free_ator(&sc.ator_tmp); ufbxi_free_ator(&sc.ator_result); @@ -28976,7 +29463,7 @@ static ufbxi_noinline size_t ufbxi_generate_indices(const ufbx_vertex_stream *us ufbxi_clear_error(error); } else { - ufbxi_fix_error_type(error, "Failed to generate indices"); + ufbxi_fix_error_type(error, "Failed to generate indices", NULL); } if (streams && streams != local_streams) { @@ -29169,29 +29656,43 @@ ufbx_abi_data_def const size_t ufbx_element_type_size[UFBX_ELEMENT_TYPE_COUNT] = sizeof(ufbx_metadata_object), }; -ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len) +ufbx_abi bool ufbx_default_open_file(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info) { - ufbxi_allocator tmp_ator = { 0 }; - ufbx_error tmp_error = { UFBX_ERROR_NONE }; - ufbxi_init_ator(&tmp_error, &tmp_ator, NULL, "filename"); - FILE *f = ufbxi_fopen(path, path_len, &tmp_ator); - if (!f) return false; + (void)user; + return ufbx_open_file_ctx(stream, info->context, path, path_len, NULL, NULL); +} - stream->read_fn = &ufbxi_file_read; - stream->skip_fn = &ufbxi_file_skip; - stream->close_fn = &ufbxi_file_close; - stream->user = f; - return true; +ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_opts *opts, ufbx_error *error) +{ + return ufbx_open_file_ctx(stream, (ufbx_open_file_context)NULL, path, path_len, opts, error); } -ufbx_abi bool ufbx_default_open_file(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info) +ufbx_abi bool ufbx_open_file_ctx(ufbx_stream *stream, ufbx_open_file_context ctx, const char *path, size_t path_len, const ufbx_open_file_opts *opts, ufbx_error *error) { - (void)user; - (void)info; - return ufbx_open_file(stream, path, path_len); + bool ok = false; + ufbxi_file_context fc; // ufbxi_uninit + ufbxi_begin_file_context(&fc, ctx, NULL); + if (path_len == SIZE_MAX) path_len = strlen(path); +#if !defined(UFBX_NO_STDIO) + ok = ufbxi_stdio_open(&fc, stream, path, path_len, opts ? opts->filename_null_terminated : false); +#else + (void)stream; + (void)path; + (void)path_len; + (void)opts; + ufbxi_fmt_err_info(&fc.error, "UFBX_NO_STDIO"); + ufbxi_report_err_msg(&fc.error, "UFBX_NO_STDIO", "Feature disabled"); +#endif + ufbxi_end_file_context(&fc, error, ok); + return ok; } ufbx_abi bool ufbx_open_memory(ufbx_stream *stream, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error) +{ + return ufbx_open_memory_ctx(stream, (ufbx_open_file_context)NULL, data, data_size, opts, error); +} + +ufbx_abi bool ufbx_open_memory_ctx(ufbx_stream *stream, ufbx_open_file_context ctx, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error) { ufbx_open_memory_opts local_opts; // ufbxi_uninit if (!opts) { @@ -29200,22 +29701,17 @@ ufbx_abi bool ufbx_open_memory(ufbx_stream *stream, const void *data, size_t dat } ufbx_assert(opts->_begin_zero == 0 && opts->_end_zero == 0); - ufbx_error local_error = { UFBX_ERROR_NONE }; - if (!error) error = &local_error; - ufbxi_clear_error(error); - - ufbxi_allocator ator = { 0 }; - ufbxi_init_ator(error, &ator, &opts->allocator, "memory"); + ufbxi_file_context fc; // ufbxi_uninit + ufbxi_begin_file_context(&fc, ctx, &opts->allocator); size_t copy_size = opts->no_copy ? 0 : data_size; // Align the allocation size to 8 bytes to make sure the header is aligned. size_t self_size = ufbxi_align_to_mask(sizeof(ufbxi_memory_stream) + copy_size, 7); - void *memory = ufbxi_alloc(&ator, char, self_size); + void *memory = ufbxi_alloc(&fc.ator, char, self_size); if (!memory) { - ufbxi_free_ator(&ator); - ufbxi_fix_error_type(error, "Failed to open memory"); + ufbxi_end_file_context(&fc, error, false); return false; } @@ -29234,14 +29730,20 @@ ufbx_abi bool ufbx_open_memory(ufbx_stream *stream, const void *data, size_t dat } // Transplant the allocator in the result blob - mem->ator = ator; - mem->ator.error = &mem->error; + if (fc.parent_ator) { + mem->parent_ator = fc.parent_ator; + } else { + fc.parent_ator = &mem->local_ator; + } stream->read_fn = ufbxi_memory_read; stream->skip_fn = ufbxi_memory_skip; + stream->size_fn = ufbxi_memory_size; stream->close_fn = ufbxi_memory_close; stream->user = mem; + ufbxi_end_file_context(&fc, error, true); + return true; } @@ -29253,7 +29755,8 @@ ufbx_abi bool ufbx_is_thread_safe(void) ufbx_abi ufbx_scene *ufbx_load_memory(const void *data, size_t size, const ufbx_load_opts *opts, ufbx_error *error) { ufbxi_check_opts_ptr(ufbx_scene, opts, error); - ufbxi_context uc = { UFBX_ERROR_NONE }; + ufbxi_context uc; // ufbxi_uninit + memset(&uc, 0, sizeof(ufbxi_context)); uc.data_begin = uc.data = (const char *)data; uc.data_size = size; uc.progress_bytes_total = size; @@ -29268,42 +29771,12 @@ ufbx_abi ufbx_scene *ufbx_load_file(const char *filename, const ufbx_load_opts * ufbx_abi ufbx_scene *ufbx_load_file_len(const char *filename, size_t filename_len, const ufbx_load_opts *opts, ufbx_error *error) { ufbxi_check_opts_ptr(ufbx_scene, opts, error); - ufbx_load_opts opts_copy; - if (opts) { - opts_copy = *opts; - } else { - memset(&opts_copy, 0, sizeof(opts_copy)); - opts = &opts_copy; - } - if (opts_copy.filename.length == 0 || opts_copy.filename.data == NULL) { - opts_copy.filename.data = filename; - opts_copy.filename.length = filename_len; - } - - // Defer to `ufbx_load_stream()` if the user so prefers. - if (!opts->open_main_file_with_default && opts->open_file_cb.fn) { - ufbx_stream stream = { 0 }; - if (ufbxi_open_file(&opts->open_file_cb, &stream, filename, filename_len, NULL, NULL, UFBX_OPEN_FILE_MAIN_MODEL)) { - return ufbx_load_stream_prefix(&stream, NULL, 0, &opts_copy, error); - } else { - return ufbxi_load_not_found(filename, filename_len, error); - } - } - - ufbxi_allocator tmp_ator = { 0 }; - ufbx_error tmp_error = { UFBX_ERROR_NONE }; - ufbxi_init_ator(&tmp_error, &tmp_ator, opts ? &opts->temp_allocator : NULL, "filename"); - - FILE *file = ufbxi_fopen(filename, filename_len, &tmp_ator); - if (!file) { - return ufbxi_load_not_found(filename, filename_len, error); - } - - ufbx_scene *scene = ufbx_load_stdio(file, &opts_copy, error); - - fclose(file); - - return scene; + ufbxi_context uc; // ufbxi_uninit + memset(&uc, 0, sizeof(ufbxi_context)); + uc.deferred_load = true; + uc.load_filename = filename; + uc.load_filename_len = filename_len; + return ufbxi_load(&uc, opts, error); } ufbx_abi ufbx_scene *ufbx_load_stdio(void *file_void, const ufbx_load_opts *opts, ufbx_error *error) @@ -29313,37 +29786,24 @@ ufbx_abi ufbx_scene *ufbx_load_stdio(void *file_void, const ufbx_load_opts *opts ufbx_abi ufbx_scene *ufbx_load_stdio_prefix(void *file_void, const void *prefix, size_t prefix_size, const ufbx_load_opts *opts, ufbx_error *error) { - ufbxi_check_opts_ptr(ufbx_scene, opts, error); - FILE *file = (FILE*)file_void; - - ufbxi_context uc = { UFBX_ERROR_NONE }; - uc.data_begin = uc.data = (const char *)prefix; - uc.data_size = prefix_size; - uc.read_fn = &ufbxi_file_read; - uc.skip_fn = &ufbxi_file_skip; - uc.read_user = file; - - if (opts && opts->progress_cb.fn && opts->file_size_estimate == 0) { - uint64_t begin = ufbxi_ftell(file); - if (begin < UINT64_MAX) { - fpos_t pos; // ufbxi_uninit - if (fgetpos(file, &pos) == 0) { - if (fseek(file, 0, SEEK_END) == 0) { - uint64_t end = ufbxi_ftell(file); - if (end != UINT64_MAX && begin < end) { - uc.progress_bytes_total = end - begin; - } - - // Both `rewind()` and `fsetpos()` to reset error and EOF - rewind(file); - fsetpos(file, &pos); - } - } - } - } - - ufbx_scene *scene = ufbxi_load(&uc, opts, error); - return scene; +#if !defined(UFBX_NO_STDIO) + if (!file_void) return NULL; + ufbx_stream stream = { 0 }; + ufbxi_stdio_init(&stream, file_void, false); + return ufbx_load_stream_prefix(&stream, prefix, prefix_size, opts, error); +#else + (void)file_void; + (void)prefix; + (void)prefix_size; + (void)opts; + + ufbxi_context uc; // ufbxi_uninit + memset(&uc, 0, sizeof(ufbxi_context)); + ufbxi_fmt_err_info(&uc.error, "UFBX_NO_STDIO"); + ufbxi_report_err_msg(&uc.error, "UFBX_NO_STDIO", "Feature disabled"); + uc.deferred_failure = true; + return ufbxi_load(&uc, NULL, error); +#endif } ufbx_abi ufbx_scene *ufbx_load_stream(const ufbx_stream *stream, const ufbx_load_opts *opts, ufbx_error *error) @@ -29354,13 +29814,16 @@ ufbx_abi ufbx_scene *ufbx_load_stream(const ufbx_stream *stream, const ufbx_load ufbx_abi ufbx_scene *ufbx_load_stream_prefix(const ufbx_stream *stream, const void *prefix, size_t prefix_size, const ufbx_load_opts *opts, ufbx_error *error) { ufbxi_check_opts_ptr(ufbx_scene, opts, error); - ufbxi_context uc = { UFBX_ERROR_NONE }; + ufbxi_context uc; // ufbxi_uninit + memset(&uc, 0, sizeof(ufbxi_context)); uc.data_begin = uc.data = (const char *)prefix; uc.data_size = prefix_size; uc.read_fn = stream->read_fn; uc.skip_fn = stream->skip_fn; + uc.size_fn = stream->size_fn; uc.close_fn = stream->close_fn; uc.read_user = stream->user; + ufbx_scene *scene = ufbxi_load(&uc, opts, error); return scene; } @@ -29412,9 +29875,10 @@ ufbx_abi ufbxi_noinline size_t ufbx_format_error(char *dst, size_t dst_size, con } size_t stack_size = ufbxi_min_sz(error->stack_size, UFBX_ERROR_STACK_MAX_DEPTH); + int line_width = 6; for (size_t i = 0; i < stack_size; i++) { const ufbx_error_frame *frame = &error->stack[i]; - int num = ufbxi_snprintf(dst + offset, dst_size - offset, "%6u:%s: %s\n", frame->source_line, frame->function.data, frame->description.data); + int num = ufbxi_snprintf(dst + offset, dst_size - offset, "%*u:%s: %s\n", line_width, frame->source_line, frame->function.data, frame->description.data); if (num > 0) offset = ufbxi_min_sz(offset + (size_t)num, dst_size - 1); } @@ -29958,8 +30422,7 @@ ufbx_abi ufbx_anim *ufbx_create_anim(const ufbx_scene *scene, const ufbx_anim_op ufbxi_anim_imp *imp = ac.imp; return &imp->anim; } else { - ufbxi_fix_error_type(&ac.error, "Failed to create anim"); - if (error) *error = ac.error; + ufbxi_fix_error_type(&ac.error, "Failed to create anim", error); ufbxi_buf_free(&ac.result); ufbxi_free_ator(&ac.ator_result); return NULL; @@ -30014,6 +30477,7 @@ ufbx_abi ufbx_baked_anim *ufbx_bake_anim(const ufbx_scene *scene, const ufbx_ani ufbxi_buf_free(&bc.tmp_elements); ufbxi_buf_free(&bc.tmp_props); ufbxi_buf_free(&bc.tmp_bake_stack); + ufbxi_free(&bc.ator_tmp, char, bc.tmp_arr, bc.tmp_arr_size); ufbxi_free_ator(&bc.ator_tmp); if (ok) { @@ -30021,8 +30485,7 @@ ufbx_abi ufbx_baked_anim *ufbx_bake_anim(const ufbx_scene *scene, const ufbx_ani ufbxi_baked_anim_imp *imp = bc.imp; return &imp->bake; } else { - ufbxi_fix_error_type(&bc.error, "Failed to bake anim"); - if (error) *error = bc.error; + ufbxi_fix_error_type(&bc.error, "Failed to bake anim", error); ufbxi_buf_free(&bc.result); ufbxi_free_ator(&bc.ator_result); return NULL; @@ -31046,8 +31509,7 @@ ufbx_abi ufbx_line_curve *ufbx_tessellate_nurbs_curve(const ufbx_nurbs_curve *cu ufbxi_line_curve_imp *imp = tc.imp; return &imp->curve; } else { - ufbxi_fix_error_type(&tc.error, "Failed to tessellate"); - if (error) *error = tc.error; + ufbxi_fix_error_type(&tc.error, "Failed to tessellate", error); ufbxi_buf_free(&tc.result); ufbxi_free_ator(&tc.ator_result); return NULL; @@ -31087,8 +31549,7 @@ ufbx_abi ufbx_mesh *ufbx_tessellate_nurbs_surface(const ufbx_nurbs_surface *surf ufbxi_mesh_imp *imp = tc.imp; return &imp->mesh; } else { - ufbxi_fix_error_type(&tc.error, "Failed to tessellate"); - if (error) *error = tc.error; + ufbxi_fix_error_type(&tc.error, "Failed to tessellate", error); ufbxi_buf_free(&tc.result); ufbxi_free_ator(&tc.ator_result); return NULL; @@ -31230,7 +31691,7 @@ ufbx_abi void ufbx_catch_compute_topology(ufbx_panic *panic, const ufbx_mesh *me ufbx_abi uint32_t ufbx_catch_topo_next_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) { if (index == UFBX_NO_INDEX) return UFBX_NO_INDEX; - if (ufbxi_panicf(panic, (size_t)index < num_topo, "index (%d) out of bounds (%zu)", index, num_topo)) return UFBX_NO_INDEX; + if (ufbxi_panicf(panic, (size_t)index < num_topo, "index (%u) out of bounds (%zu)", index, num_topo)) return UFBX_NO_INDEX; uint32_t twin = topo[index].twin; if (twin == UFBX_NO_INDEX) return UFBX_NO_INDEX; if (ufbxi_panicf(panic, (size_t)twin < num_topo, "Corrupted topology structure")) return UFBX_NO_INDEX; @@ -31240,7 +31701,7 @@ ufbx_abi uint32_t ufbx_catch_topo_next_vertex_edge(ufbx_panic *panic, const ufbx ufbx_abi uint32_t ufbx_catch_topo_prev_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) { if (index == UFBX_NO_INDEX) return UFBX_NO_INDEX; - if (ufbxi_panicf(panic, (size_t)index < num_topo, "index (%d) out of bounds (%zu)", index, num_topo)) return UFBX_NO_INDEX; + if (ufbxi_panicf(panic, (size_t)index < num_topo, "index (%u) out of bounds (%zu)", index, num_topo)) return UFBX_NO_INDEX; return topo[topo[index].prev].twin; } @@ -31340,7 +31801,7 @@ ufbx_abi void ufbx_catch_compute_normals(ufbx_panic *panic, const ufbx_mesh *mes for (size_t ix = 0; ix < face.num_indices; ix++) { uint32_t index = normal_indices[face.index_begin + ix]; - if (ufbxi_panicf(panic, index < num_normals, "Normal index (%d) out of bounds (%zu) at %zu", index, num_normals, ix)) return; + if (ufbxi_panicf(panic, index < num_normals, "Normal index (%u) out of bounds (%zu) at %zu", index, num_normals, ix)) return; ufbx_vec3 *n = &normals[index]; *n = ufbxi_add3(*n, normal); @@ -31820,12 +32281,63 @@ ufbx_abi ufbx_audio_clip *ufbx_as_audio_clip(const ufbx_element *element) { retu ufbx_abi ufbx_pose *ufbx_as_pose(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_POSE ? (ufbx_pose*)element : NULL; } ufbx_abi ufbx_metadata_object *ufbx_as_metadata_object(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_METADATA_OBJECT ? (ufbx_metadata_object*)element : NULL; } +// -- String API + +ufbx_abi ufbx_prop *ufbx_find_prop(const ufbx_props *props, const char *name) { return ufbx_find_prop_len(props, name, strlen(name)); } +ufbx_abi ufbx_real ufbx_find_real(const ufbx_props *props, const char *name, ufbx_real def) { return ufbx_find_real_len(props, name, strlen(name), def); } +ufbx_abi ufbx_vec3 ufbx_find_vec3(const ufbx_props *props, const char *name, ufbx_vec3 def) { return ufbx_find_vec3_len(props, name, strlen(name), def); } +ufbx_abi int64_t ufbx_find_int(const ufbx_props *props, const char *name, int64_t def) { return ufbx_find_int_len(props, name, strlen(name), def); } +ufbx_abi bool ufbx_find_bool(const ufbx_props *props, const char *name, bool def) { return ufbx_find_bool_len(props, name, strlen(name), def); } +ufbx_abi ufbx_string ufbx_find_string(const ufbx_props *props, const char *name, ufbx_string def) { return ufbx_find_string_len(props, name, strlen(name), def); } +ufbx_abi ufbx_blob ufbx_find_blob(const ufbx_props *props, const char *name, ufbx_blob def) { return ufbx_find_blob_len(props, name, strlen(name), def); } +ufbx_abi ufbx_element *ufbx_find_prop_element(const ufbx_element *element, const char *name, ufbx_element_type type) { return ufbx_find_prop_element_len(element, name, strlen(name), type); } +ufbx_abi ufbx_element *ufbx_find_element(const ufbx_scene *scene, ufbx_element_type type, const char *name) { return ufbx_find_element_len(scene, type, name, strlen(name)); } +ufbx_abi ufbx_node *ufbx_find_node(const ufbx_scene *scene, const char *name) { return ufbx_find_node_len(scene, name, strlen(name)); } +ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack(const ufbx_scene *scene, const char *name) { return ufbx_find_anim_stack_len(scene, name, strlen(name)); } +ufbx_abi ufbx_material *ufbx_find_material(const ufbx_scene *scene, const char *name) { return ufbx_find_material_len(scene, name, strlen(name)); } +ufbx_abi ufbx_anim_prop *ufbx_find_anim_prop(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop) { return ufbx_find_anim_prop_len(layer, element, prop, strlen(prop)); } +ufbx_abi ufbx_prop ufbx_evaluate_prop(const ufbx_anim *anim, const ufbx_element *element, const char *name, double time) { return ufbx_evaluate_prop_len(anim, element, name, strlen(name), time); } +ufbx_abi ufbx_texture *ufbx_find_prop_texture(const ufbx_material *material, const char *name) { return ufbx_find_prop_texture_len(material, name, strlen(name)); } +ufbx_abi ufbx_string ufbx_find_shader_prop(const ufbx_shader *shader, const char *name) { return ufbx_find_shader_prop_len(shader, name, strlen(name)); } +ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings(const ufbx_shader *shader, const char *name) { return ufbx_find_shader_prop_bindings_len(shader, name, strlen(name)); } +ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input(const ufbx_shader_texture *shader, const char *name) { return ufbx_find_shader_texture_input_len(shader, name, strlen(name)); } +ufbx_abi ufbx_dom_node *ufbx_dom_find(const ufbx_dom_node *parent, const char *name) { return ufbx_dom_find_len(parent, name, strlen(name)); } + +// -- Catch API + +ufbx_abi uint32_t ufbx_triangulate_face(uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face) { + return ufbx_catch_triangulate_face(NULL, indices, num_indices, mesh, face); +} +ufbx_abi void ufbx_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo) { + ufbx_catch_compute_topology(NULL, mesh, topo, num_topo); +} +ufbx_abi uint32_t ufbx_topo_next_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) { + return ufbx_catch_topo_next_vertex_edge(NULL, topo, num_topo, index); +} +ufbx_abi uint32_t ufbx_topo_prev_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) { + return ufbx_catch_topo_prev_vertex_edge(NULL, topo, num_topo, index); +} +ufbx_abi ufbx_vec3 ufbx_get_weighted_face_normal(const ufbx_vertex_vec3 *positions, ufbx_face face) { + return ufbx_catch_get_weighted_face_normal(NULL, positions, face); +} + #ifdef __cplusplus } #endif #endif +#if defined(UFBX_STRING_PREFIX) + #undef strlen + #undef memcpy + #undef memmove + #undef memset + #undef memchr + #undef memcmp + #undef strcmp + #undef strncmp +#endif + #if defined(_MSC_VER) #pragma warning(pop) #elif defined(__clang__) diff --git a/godot/thirdparty/ufbx/ufbx.h b/godot/thirdparty/ufbx/ufbx.h index 8d856eda..1fc9a103 100644 --- a/godot/thirdparty/ufbx/ufbx.h +++ b/godot/thirdparty/ufbx/ufbx.h @@ -9,10 +9,11 @@ // -- Headers -#include -#include -#include -#include +#if !defined(UFBX_NO_LIBC_TYPES) + #include + #include + #include +#endif // -- Platform @@ -99,7 +100,7 @@ // make sure that it is also used within `ufbx.c`. // Defining `UFBX_NO_ASSERT` to any value disables assertions. #ifndef ufbx_assert - #if defined(UFBX_NO_ASSERT) + #if defined(UFBX_NO_ASSERT) || defined(UFBX_NO_LIBC) #define ufbx_assert(cond) (void)0 #else #include @@ -266,7 +267,7 @@ struct ufbx_converter { }; // `ufbx_source_version` contains the version of the corresponding source file. // HINT: The version can be compared numerically to the result of `ufbx_pack_version()`, // for example `#if UFBX_VERSION >= ufbx_pack_version(0, 12, 0)`. -#define UFBX_HEADER_VERSION ufbx_pack_version(0, 14, 3) +#define UFBX_HEADER_VERSION ufbx_pack_version(0, 15, 0) #define UFBX_VERSION UFBX_HEADER_VERSION // -- Basic types @@ -3984,12 +3985,17 @@ typedef size_t ufbx_read_fn(void *user, void *data, size_t size); // Skip `size` bytes in the file. typedef bool ufbx_skip_fn(void *user, size_t size); +// Get the size of the file. +// Return `0` if unknown, `UINT64_MAX` if error. +typedef uint64_t ufbx_size_fn(void *user); + // Close the file typedef void ufbx_close_fn(void *user); typedef struct ufbx_stream { ufbx_read_fn *read_fn; // < Required ufbx_skip_fn *skip_fn; // < Optional: Will use `read_fn()` if missing + ufbx_size_fn *size_fn; // < Optional ufbx_close_fn *close_fn; // < Optional // Context passed to other functions @@ -4006,13 +4012,17 @@ typedef enum ufbx_open_file_type UFBX_ENUM_REPR { UFBX_ENUM_TYPE(ufbx_open_file_type, UFBX_OPEN_FILE_TYPE, UFBX_OPEN_FILE_OBJ_MTL); +typedef uintptr_t ufbx_open_file_context; + typedef struct ufbx_open_file_info { + // Context that can be passed to the following functions to use a shared allocator: + // ufbx_open_file_ctx() + // ufbx_open_memory_ctx() + ufbx_open_file_context context; + // Kind of file to load. ufbx_open_file_type type; - // Temporary allocator to use. - ufbx_allocator temp_allocator; - // Original filename in the file, not resolved or UTF-8 encoded. // NOTE: Not necessarily NULL-terminated! ufbx_blob original_filename; @@ -4030,6 +4040,19 @@ typedef struct ufbx_open_file_cb { (stream, path, path_len, info)) } ufbx_open_file_cb; +// Options for `ufbx_open_file()`. +typedef struct ufbx_open_file_opts { + uint32_t _begin_zero; + + // Allocator to allocate the memory with. + ufbx_allocator_opts allocator; + + // The filename is guaranteed to be NULL-terminated. + ufbx_unsafe bool filename_null_terminated; + + uint32_t _end_zero; +} ufbx_open_file_opts; + // Memory stream options typedef void ufbx_close_memory_fn(void *user, void *data, size_t data_size); @@ -5092,6 +5115,7 @@ ufbx_abi_data const size_t ufbx_element_type_size[UFBX_ELEMENT_TYPE_COUNT]; // Version of the source file, comparable to `UFBX_HEADER_VERSION` ufbx_abi_data const uint32_t ufbx_source_version; + // Practically always `true` (see below), if not you need to be careful with threads. // // Guaranteed to be `true` in _any_ of the following conditions: @@ -5160,23 +5184,23 @@ ufbx_abi size_t ufbx_format_error(char *dst, size_t dst_size, const ufbx_error * // Find a property `name` from `props`, returns `NULL` if not found. // Searches through `ufbx_props.defaults` as well. ufbx_abi ufbx_prop *ufbx_find_prop_len(const ufbx_props *props, const char *name, size_t name_len); -ufbx_inline ufbx_prop *ufbx_find_prop(const ufbx_props *props, const char *name) { return ufbx_find_prop_len(props, name, strlen(name));} +ufbx_abi ufbx_prop *ufbx_find_prop(const ufbx_props *props, const char *name); // Utility functions for finding the value of a property, returns `def` if not found. // NOTE: For `ufbx_string` you need to ensure the lifetime of the default is // sufficient as no copy is made. ufbx_abi ufbx_real ufbx_find_real_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_real def); -ufbx_inline ufbx_real ufbx_find_real(const ufbx_props *props, const char *name, ufbx_real def) { return ufbx_find_real_len(props, name, strlen(name), def); } +ufbx_abi ufbx_real ufbx_find_real(const ufbx_props *props, const char *name, ufbx_real def); ufbx_abi ufbx_vec3 ufbx_find_vec3_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_vec3 def); -ufbx_inline ufbx_vec3 ufbx_find_vec3(const ufbx_props *props, const char *name, ufbx_vec3 def) { return ufbx_find_vec3_len(props, name, strlen(name), def); } +ufbx_abi ufbx_vec3 ufbx_find_vec3(const ufbx_props *props, const char *name, ufbx_vec3 def); ufbx_abi int64_t ufbx_find_int_len(const ufbx_props *props, const char *name, size_t name_len, int64_t def); -ufbx_inline int64_t ufbx_find_int(const ufbx_props *props, const char *name, int64_t def) { return ufbx_find_int_len(props, name, strlen(name), def); } +ufbx_abi int64_t ufbx_find_int(const ufbx_props *props, const char *name, int64_t def); ufbx_abi bool ufbx_find_bool_len(const ufbx_props *props, const char *name, size_t name_len, bool def); -ufbx_inline bool ufbx_find_bool(const ufbx_props *props, const char *name, bool def) { return ufbx_find_bool_len(props, name, strlen(name), def); } +ufbx_abi bool ufbx_find_bool(const ufbx_props *props, const char *name, bool def); ufbx_abi ufbx_string ufbx_find_string_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_string def); -ufbx_inline ufbx_string ufbx_find_string(const ufbx_props *props, const char *name, ufbx_string def) { return ufbx_find_string_len(props, name, strlen(name), def); } +ufbx_abi ufbx_string ufbx_find_string(const ufbx_props *props, const char *name, ufbx_string def); ufbx_abi ufbx_blob ufbx_find_blob_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_blob def); -ufbx_inline ufbx_blob ufbx_find_blob(const ufbx_props *props, const char *name, ufbx_blob def) { return ufbx_find_blob_len(props, name, strlen(name), def); } +ufbx_abi ufbx_blob ufbx_find_blob(const ufbx_props *props, const char *name, ufbx_blob def); // Find property in `props` with concatendated `parts[num_parts]`. ufbx_abi ufbx_prop *ufbx_find_prop_concat(const ufbx_props *props, const ufbx_string *parts, size_t num_parts); @@ -5186,30 +5210,30 @@ ufbx_abi ufbx_element *ufbx_get_prop_element(const ufbx_element *element, const // Find an element connected to a property by name. ufbx_abi ufbx_element *ufbx_find_prop_element_len(const ufbx_element *element, const char *name, size_t name_len, ufbx_element_type type); -ufbx_inline ufbx_element *ufbx_find_prop_element(const ufbx_element *element, const char *name, ufbx_element_type type) { return ufbx_find_prop_element_len(element, name, strlen(name), type); } +ufbx_abi ufbx_element *ufbx_find_prop_element(const ufbx_element *element, const char *name, ufbx_element_type type); // Find any element of type `type` in `scene` by `name`. // For example if you want to find `ufbx_material` named `Mat`: // (ufbx_material*)ufbx_find_element(scene, UFBX_ELEMENT_MATERIAL, "Mat"); ufbx_abi ufbx_element *ufbx_find_element_len(const ufbx_scene *scene, ufbx_element_type type, const char *name, size_t name_len); -ufbx_inline ufbx_element *ufbx_find_element(const ufbx_scene *scene, ufbx_element_type type, const char *name) { return ufbx_find_element_len(scene, type, name, strlen(name)); } +ufbx_abi ufbx_element *ufbx_find_element(const ufbx_scene *scene, ufbx_element_type type, const char *name); // Find node in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_NODE)`). ufbx_abi ufbx_node *ufbx_find_node_len(const ufbx_scene *scene, const char *name, size_t name_len); -ufbx_inline ufbx_node *ufbx_find_node(const ufbx_scene *scene, const char *name) { return ufbx_find_node_len(scene, name, strlen(name)); } +ufbx_abi ufbx_node *ufbx_find_node(const ufbx_scene *scene, const char *name); // Find an animation stack in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_ANIM_STACK)`) ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack_len(const ufbx_scene *scene, const char *name, size_t name_len); -ufbx_inline ufbx_anim_stack *ufbx_find_anim_stack(const ufbx_scene *scene, const char *name) { return ufbx_find_anim_stack_len(scene, name, strlen(name)); } +ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack(const ufbx_scene *scene, const char *name); // Find a material in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_MATERIAL)`). ufbx_abi ufbx_material *ufbx_find_material_len(const ufbx_scene *scene, const char *name, size_t name_len); -ufbx_inline ufbx_material *ufbx_find_material(const ufbx_scene *scene, const char *name) { return ufbx_find_material_len(scene, name, strlen(name)); } +ufbx_abi ufbx_material *ufbx_find_material(const ufbx_scene *scene, const char *name); // Find a single animated property `prop` of `element` in `layer`. // Returns `NULL` if not found. ufbx_abi ufbx_anim_prop *ufbx_find_anim_prop_len(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop, size_t prop_len); -ufbx_inline ufbx_anim_prop *ufbx_find_anim_prop(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop) { return ufbx_find_anim_prop_len(layer, element, prop, strlen(prop)); } +ufbx_abi ufbx_anim_prop *ufbx_find_anim_prop(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop); // Find all animated properties of `element` in `layer`. ufbx_abi ufbx_anim_prop_list ufbx_find_anim_props(const ufbx_anim_layer *layer, const ufbx_element *element); @@ -5228,16 +5252,18 @@ ufbx_abi ufbx_matrix ufbx_get_compatible_matrix_for_normals(const ufbx_node *nod // but the rest can be uninitialized. ufbx_abi ptrdiff_t ufbx_inflate(void *dst, size_t dst_size, const ufbx_inflate_input *input, ufbx_inflate_retain *retain); -// Open a `ufbx_stream` from a file. -// Use `path_len == SIZE_MAX` for NULL terminated string. -ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len); - // Same as `ufbx_open_file()` but compatible with the callback in `ufbx_open_file_fn`. // The `user` parameter is actually not used here. ufbx_abi bool ufbx_default_open_file(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info); +// Open a `ufbx_stream` from a file. +// Use `path_len == SIZE_MAX` for NULL terminated string. +ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_opts *opts, ufbx_error *error); +ufbx_unsafe ufbx_abi bool ufbx_open_file_ctx(ufbx_stream *stream, ufbx_open_file_context ctx, const char *path, size_t path_len, const ufbx_open_file_opts *opts, ufbx_error *error); + // NOTE: Uses the default ufbx allocator! ufbx_abi bool ufbx_open_memory(ufbx_stream *stream, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error); +ufbx_unsafe ufbx_abi bool ufbx_open_memory_ctx(ufbx_stream *stream, ufbx_open_file_context ctx, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error); // Animation evaluation @@ -5252,9 +5278,7 @@ ufbx_abi ufbx_vec3 ufbx_evaluate_anim_value_vec3(const ufbx_anim_value *anim_val // Evaluate an animated property `name` from `element` at `time`. // NOTE: If the property is not found it will have the flag `UFBX_PROP_FLAG_NOT_FOUND`. ufbx_abi ufbx_prop ufbx_evaluate_prop_len(const ufbx_anim *anim, const ufbx_element *element, const char *name, size_t name_len, double time); -ufbx_inline ufbx_prop ufbx_evaluate_prop(const ufbx_anim *anim, const ufbx_element *element, const char *name, double time) { - return ufbx_evaluate_prop_len(anim, element, name, strlen(name), time); -} +ufbx_abi ufbx_prop ufbx_evaluate_prop(const ufbx_anim *anim, const ufbx_element *element, const char *name, double time); // Evaluate all _animated_ properties of `element`. // HINT: This function returns an `ufbx_props` structure with the original properties as @@ -5351,27 +5375,19 @@ ufbx_abi ufbx_bone_pose *ufbx_get_bone_pose(const ufbx_pose *pose, const ufbx_no // Find a texture for a given material FBX property. ufbx_abi ufbx_texture *ufbx_find_prop_texture_len(const ufbx_material *material, const char *name, size_t name_len); -ufbx_inline ufbx_texture *ufbx_find_prop_texture(const ufbx_material *material, const char *name) { - return ufbx_find_prop_texture_len(material, name, strlen(name)); -} +ufbx_abi ufbx_texture *ufbx_find_prop_texture(const ufbx_material *material, const char *name); // Find a texture for a given shader property. ufbx_abi ufbx_string ufbx_find_shader_prop_len(const ufbx_shader *shader, const char *name, size_t name_len); -ufbx_inline ufbx_string ufbx_find_shader_prop(const ufbx_shader *shader, const char *name) { - return ufbx_find_shader_prop_len(shader, name, strlen(name)); -} +ufbx_abi ufbx_string ufbx_find_shader_prop(const ufbx_shader *shader, const char *name); // Map from a shader property to material property. ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings_len(const ufbx_shader *shader, const char *name, size_t name_len); -ufbx_inline ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings(const ufbx_shader *shader, const char *name) { - return ufbx_find_shader_prop_bindings_len(shader, name, strlen(name)); -} +ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings(const ufbx_shader *shader, const char *name); // Find an input in a shader texture. ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input_len(const ufbx_shader_texture *shader, const char *name, size_t name_len); -ufbx_inline ufbx_shader_texture_input *ufbx_find_shader_texture_input(const ufbx_shader_texture *shader, const char *name) { - return ufbx_find_shader_texture_input_len(shader, name, strlen(name)); -} +ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input(const ufbx_shader_texture *shader, const char *name); // Math @@ -5471,37 +5487,27 @@ ufbx_abi uint32_t ufbx_find_face_index(ufbx_mesh *mesh, size_t index); // NOTE: You need to space for `(face.num_indices - 2) * 3 - 1` indices! // HINT: Using `ufbx_mesh.max_face_triangles * 3` is always safe. ufbx_abi uint32_t ufbx_catch_triangulate_face(ufbx_panic *panic, uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face); -ufbx_inline uint32_t ufbx_triangulate_face(uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face) { - return ufbx_catch_triangulate_face(NULL, indices, num_indices, mesh, face); -} +ufbx_abi uint32_t ufbx_triangulate_face(uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face); // Generate the half-edge representation of `mesh` to `topo[mesh->num_indices]` ufbx_abi void ufbx_catch_compute_topology(ufbx_panic *panic, const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo); -ufbx_inline void ufbx_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo) { - ufbx_catch_compute_topology(NULL, mesh, topo, num_topo); -} +ufbx_abi void ufbx_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo); // Get the next/previous edge around a vertex // NOTE: Does not return the half-edge on the opposite side (ie. `topo[index].twin`) // Get the next half-edge in `topo`. ufbx_abi uint32_t ufbx_catch_topo_next_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index); -ufbx_inline uint32_t ufbx_topo_next_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) { - return ufbx_catch_topo_next_vertex_edge(NULL, topo, num_topo, index); -} +ufbx_abi uint32_t ufbx_topo_next_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index); // Get the previous half-edge in `topo`. ufbx_abi uint32_t ufbx_catch_topo_prev_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index); -ufbx_inline uint32_t ufbx_topo_prev_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) { - return ufbx_catch_topo_prev_vertex_edge(NULL, topo, num_topo, index); -} +ufbx_abi uint32_t ufbx_topo_prev_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index); // Calculate a normal for a given face. // The returned normal is weighted by face area. ufbx_abi ufbx_vec3 ufbx_catch_get_weighted_face_normal(ufbx_panic *panic, const ufbx_vertex_vec3 *positions, ufbx_face face); -ufbx_inline ufbx_vec3 ufbx_get_weighted_face_normal(const ufbx_vertex_vec3 *positions, ufbx_face face) { - return ufbx_catch_get_weighted_face_normal(NULL, positions, face); -} +ufbx_abi ufbx_vec3 ufbx_get_weighted_face_normal(const ufbx_vertex_vec3 *positions, ufbx_face face); // Generate indices for normals from the topology. // Respects smoothing groups. @@ -5558,7 +5564,7 @@ ufbx_abi size_t ufbx_sample_geometry_cache_vec3(const ufbx_cache_channel *channe // Find a DOM node given a name. ufbx_abi ufbx_dom_node *ufbx_dom_find_len(const ufbx_dom_node *parent, const char *name, size_t name_len); -ufbx_inline ufbx_dom_node *ufbx_dom_find(const ufbx_dom_node *parent, const char *name) { return ufbx_dom_find_len(parent, name, strlen(name)); } +ufbx_abi ufbx_dom_node *ufbx_dom_find(const ufbx_dom_node *parent, const char *name); // Utility