From 0e56515db781ef2e3daeab0744f4dea1c30d7aa5 Mon Sep 17 00:00:00 2001 From: ActoryOu Date: Tue, 5 Mar 2024 11:40:05 +0800 Subject: [PATCH] Add SDP component as submodule after re-factoring (#1913) * Add SDP component as submodule after re-factoring --- .gitmodules | 2 + CMake/Dependencies/libkvssdp-CMakeLists.txt | 23 ++ CMake/Utilities.cmake | 3 +- CMakeLists.txt | 16 +- configs/sdp_config.h | 25 ++ samples/CMakeLists.txt | 8 +- .../kinesis/video/webrtcclient/Include.h | 49 ++-- src/source/Sdp/Deserialize.c | 195 ++++++++------- src/source/Sdp/Sdp.h | 33 +-- src/source/Sdp/SdpUtils.c | 75 ++++++ src/source/Sdp/Serialize.c | 231 +++++++++++------- tst/SdpApiTest.cpp | 12 +- 12 files changed, 433 insertions(+), 239 deletions(-) create mode 100644 CMake/Dependencies/libkvssdp-CMakeLists.txt create mode 100644 configs/sdp_config.h create mode 100644 src/source/Sdp/SdpUtils.c diff --git a/.gitmodules b/.gitmodules index 519151ebec..a8ed9bdde5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,8 @@ [submodule "open-source/amazon-kinesis-video-streams-pic"] path = open-source/amazon-kinesis-video-streams-pic url = https://github.com/awslabs/amazon-kinesis-video-streams-pic.git + update = none [submodule "open-source/amazon-kinesis-video-streams-producer-c"] path = open-source/amazon-kinesis-video-streams-producer-c url = https://github.com/awslabs/amazon-kinesis-video-streams-producer-c.git + update = none diff --git a/CMake/Dependencies/libkvssdp-CMakeLists.txt b/CMake/Dependencies/libkvssdp-CMakeLists.txt new file mode 100644 index 0000000000..32afc66fd8 --- /dev/null +++ b/CMake/Dependencies/libkvssdp-CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.6.3) + +project(libkvssdp NONE) + +include(ExternalProject) +if (BUILD_STATIC_LIBS OR WIN32) + set(LIBKVSSDP_SHARED_LIBS OFF) +else() + set(LIBKVSSDP_SHARED_LIBS ON) +endif() + +ExternalProject_Add(libkvssdp + GIT_REPOSITORY https://github.com/awslabs/amazon-kinesis-video-streams-sdp.git + GIT_TAG eca4928122c5cc0191d72cf1e87f54ffaddd017b + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/build + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DBUILD_SHARED_LIBS=${LIBKVSSDP_SHARED_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + BUILD_ALWAYS TRUE + TEST_COMMAND "" +) diff --git a/CMake/Utilities.cmake b/CMake/Utilities.cmake index 23869d3d68..2e2ec00fc0 100644 --- a/CMake/Utilities.cmake +++ b/CMake/Utilities.cmake @@ -13,7 +13,8 @@ function(build_dependency lib_name) curl mbedtls kvspic - kvsCommonLws) + kvsCommonLws + kvssdp) list(FIND supported_libs ${lib_name} index) if(${index} EQUAL -1) message(WARNING "${lib_name} is not supported to build from source") diff --git a/CMakeLists.txt b/CMakeLists.txt index 3459626922..dcf44fa7d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,12 +205,21 @@ if(BUILD_DEPENDENCIES) build_dependency(srtp ${BUILD_ARGS}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/configs") + set(BUILD_ARGS + -DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}) + + build_dependency(kvssdp ${BUILD_ARGS}) + set(BUILD_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}) build_dependency(usrsctp ${BUILD_ARGS}) + if(BUILD_TEST) build_dependency(gtest) @@ -366,10 +375,11 @@ endif() file(GLOB WEBRTC_SIGNALING_CLIENT_SOURCE_FILES "src/source/Signaling/*.c") - include_directories(${OPEN_SRC_INCLUDE_DIRS}) include_directories(${OPEN_SRC_INSTALL_PREFIX}/include) include_directories(${KINESIS_VIDEO_WEBRTC_CLIENT_SRC}/src/include) +# include sdp_config.h +include_directories(src/source/Sdp/kvssdp) add_library(kvsWebrtcClient ${LINKAGE} ${WEBRTC_CLIENT_SOURCE_FILES} ${DATACHANNEL_SRC}) @@ -388,6 +398,7 @@ target_link_libraries( kvsWebrtcClient PRIVATE kvspicUtils kvspicState + kvssdp ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} @@ -408,7 +419,8 @@ target_link_libraries( kvsWebrtcSignalingClient PUBLIC kvsCommonLws - ${LIBWEBSOCKETS_LIBRARIES} + ${LIBWEBSOCKETS_LIBRARIES} + kvssdp PRIVATE kvspicUtils kvspicState ${CMAKE_THREAD_LIBS_INIT} diff --git a/configs/sdp_config.h b/configs/sdp_config.h new file mode 100644 index 0000000000..70ce7bf216 --- /dev/null +++ b/configs/sdp_config.h @@ -0,0 +1,25 @@ +// +// Session Description Protocol Configuration +// + +#ifndef __KINESIS_VIDEO_WEBRTC_CLIENT_SDP_SDP_CONFIG__ +#define __KINESIS_VIDEO_WEBRTC_CLIENT_SDP_SDP_CONFIG__ + +#include + +/** + * @brief SDP print format for uint64_t. + */ +#define SDP_PRINT_FMT_UINT64 PRIu64 + +/** + * @brief SDP print format for uint32_t. + */ +#define SDP_PRINT_FMT_UINT32 PRIu32 + +/** + * @brief SDP print format for uint16_t. + */ +#define SDP_PRINT_FMT_UINT16 "hu" + +#endif //__KINESIS_VIDEO_WEBRTC_CLIENT_SDP_SDP_CONFIG__ diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 2a0b0a4622..02a235f4be 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -61,18 +61,18 @@ add_executable( kvsWebrtcClientMaster Common.c kvsWebRTCClientMaster.c) -target_link_libraries(kvsWebrtcClientMaster kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets) +target_link_libraries(kvsWebrtcClientMaster kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets kvssdp) add_executable( kvsWebrtcClientViewer Common.c kvsWebRTCClientViewer.c) -target_link_libraries(kvsWebrtcClientViewer kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets) +target_link_libraries(kvsWebrtcClientViewer kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets kvssdp) add_executable( discoverNatBehavior discoverNatBehavior.c) -target_link_libraries(discoverNatBehavior kvsWebrtcClient ${EXTRA_DEPS}) +target_link_libraries(discoverNatBehavior kvsWebrtcClient ${EXTRA_DEPS} kvssdp) if(GST_FOUND) add_executable( @@ -80,7 +80,7 @@ if(GST_FOUND) Common.c kvsWebRTCClientMasterGstSample.c ) - target_link_libraries(kvsWebrtcClientMasterGstSample kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} ${GST_SAMPLE_LIBRARIES} kvsCommonLws kvspicUtils websockets) + target_link_libraries(kvsWebrtcClientMasterGstSample kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} ${GST_SAMPLE_LIBRARIES} kvsCommonLws kvspicUtils websockets kvssdp) install(TARGETS kvsWebrtcClientMasterGstSample RUNTIME DESTINATION bin diff --git a/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h b/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h index 217cd06f73..232667c613 100644 --- a/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h +++ b/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h @@ -107,22 +107,39 @@ extern "C" { * (0x56000000) * @{ */ -#define STATUS_SDP_BASE STATUS_WEBRTC_BASE + 0x01000000 -#define STATUS_SDP_MISSING_ITEMS STATUS_SDP_BASE + 0x00000001 -#define STATUS_SDP_ATTRIBUTES_ERROR STATUS_SDP_BASE + 0x00000002 -#define STATUS_SDP_BANDWIDTH_ERROR STATUS_SDP_BASE + 0x00000003 -#define STATUS_SDP_CONNECTION_INFORMATION_ERROR STATUS_SDP_BASE + 0x00000004 -#define STATUS_SDP_EMAIL_ADDRESS_ERROR STATUS_SDP_BASE + 0x00000005 -#define STATUS_SDP_ENCYRPTION_KEY_ERROR STATUS_SDP_BASE + 0x00000006 -#define STATUS_SDP_INFORMATION_ERROR STATUS_SDP_BASE + 0x00000007 -#define STATUS_SDP_MEDIA_NAME_ERROR STATUS_SDP_BASE + 0x00000008 -#define STATUS_SDP_ORIGIN_ERROR STATUS_SDP_BASE + 0x00000009 -#define STATUS_SDP_PHONE_NUMBER_ERROR STATUS_SDP_BASE + 0x0000000A -#define STATUS_SDP_TIME_DECRYPTION_ERROR STATUS_SDP_BASE + 0x0000000B -#define STATUS_SDP_TIMEZONE_ERROR STATUS_SDP_BASE + 0x0000000C -#define STATUS_SDP_URI_ERROR STATUS_SDP_BASE + 0x0000000D -#define STATUS_SDP_VERSION_ERROR STATUS_SDP_BASE + 0x0000000E -#define STATUS_SDP_ATTRIBUTE_MAX_EXCEEDED STATUS_SDP_BASE + 0x0000000F +#define STATUS_SDP_BASE STATUS_WEBRTC_BASE + 0x01000000 +#define STATUS_SDP_MISSING_ITEMS STATUS_SDP_BASE + 0x00000001 +#define STATUS_SDP_ATTRIBUTES_ERROR STATUS_SDP_BASE + 0x00000002 +#define STATUS_SDP_BANDWIDTH_ERROR STATUS_SDP_BASE + 0x00000003 +#define STATUS_SDP_CONNECTION_INFORMATION_ERROR STATUS_SDP_BASE + 0x00000004 +#define STATUS_SDP_EMAIL_ADDRESS_ERROR STATUS_SDP_BASE + 0x00000005 +#define STATUS_SDP_ENCYRPTION_KEY_ERROR STATUS_SDP_BASE + 0x00000006 +#define STATUS_SDP_INFORMATION_ERROR STATUS_SDP_BASE + 0x00000007 +#define STATUS_SDP_MEDIA_NAME_ERROR STATUS_SDP_BASE + 0x00000008 +#define STATUS_SDP_ORIGIN_ERROR STATUS_SDP_BASE + 0x00000009 +#define STATUS_SDP_PHONE_NUMBER_ERROR STATUS_SDP_BASE + 0x0000000A +#define STATUS_SDP_TIME_DECRYPTION_ERROR STATUS_SDP_BASE + 0x0000000B +#define STATUS_SDP_TIMEZONE_ERROR STATUS_SDP_BASE + 0x0000000C +#define STATUS_SDP_URI_ERROR STATUS_SDP_BASE + 0x0000000D +#define STATUS_SDP_VERSION_ERROR STATUS_SDP_BASE + 0x0000000E +#define STATUS_SDP_ATTRIBUTE_MAX_EXCEEDED STATUS_SDP_BASE + 0x0000000F +#define STATUS_SDP_MESSAGE_MALFORMED STATUS_SDP_BASE + 0x00000010 +#define STATUS_SDP_MESSAGE_MALFORMED_NOT_ENOUGH_INFO STATUS_SDP_BASE + 0x00000011 +#define STATUS_SDP_MESSAGE_MALFORMED_EQUAL_NOT_FOUND STATUS_SDP_BASE + 0x00000012 +#define STATUS_SDP_MESSAGE_MALFORMED_NEWLINE_NOT_FOUND STATUS_SDP_BASE + 0x00000013 +#define STATUS_SDP_MESSAGE_MALFORMED_NO_VALUE STATUS_SDP_BASE + 0x00000014 +#define STATUS_SDP_MESSAGE_MALFORMED_NO_SESSION_ID STATUS_SDP_BASE + 0x00000015 +#define STATUS_SDP_MESSAGE_MALFORMED_NO_SESSION_VERSION STATUS_SDP_BASE + 0x00000016 +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_NETWORK_TYPE STATUS_SDP_BASE + 0x00000017 +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_ADDRESS_TYPE STATUS_SDP_BASE + 0x00000018 +#define STATUS_SDP_MESSAGE_MALFORMED_REDUNDANT_INFO STATUS_SDP_BASE + 0x00000019 +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_BANDWIDTH STATUS_SDP_BASE + 0x0000001A +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_START_TIME STATUS_SDP_BASE + 0x0000001B +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_STOP_TIME STATUS_SDP_BASE + 0x0000001C +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_PORT STATUS_SDP_BASE + 0x0000001D +#define STATUS_SDP_MESSAGE_MALFORMED_INVALID_PORTNUM STATUS_SDP_BASE + 0x0000001E +#define STATUS_SDP_SNPRINTF_ERROR STATUS_SDP_BASE + 0x0000001F +#define STATUS_SDP_UNKNOWN_ERROR STATUS_SDP_BASE + 0x00000020 /*!@} */ ///////////////////////////////////////////////////// diff --git a/src/source/Sdp/Deserialize.c b/src/source/Sdp/Deserialize.c index 2fbf731239..a6937613fa 100644 --- a/src/source/Sdp/Deserialize.c +++ b/src/source/Sdp/Deserialize.c @@ -1,14 +1,21 @@ -#define LOG_CLASS "SDP" +#define LOG_CLASS "SDPDeserialize" #include "../Include_i.h" +#include "kvssdp/sdp_deserializer.h" -STATUS parseMediaName(PSessionDescription pSessionDescription, PCHAR pch, UINT32 lineLen) +// Convert error code from SDP library to STATUS. +extern STATUS convertSdpErrorCode(SdpResult_t sdpResult); + +STATUS parseMediaName(PSessionDescription pSessionDescription, PCHAR mediaValue, SIZE_T mediaValueLength) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; + SIZE_T minMediaValueLength; + CHK(pSessionDescription->mediaCount < MAX_SDP_SESSION_MEDIA_COUNT, STATUS_SESSION_DESCRIPTION_MAX_MEDIA_COUNT); - STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount].mediaName, (pch + SDP_ATTRIBUTE_LENGTH), - MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); + minMediaValueLength = MIN(MAX_SDP_MEDIA_NAME_LENGTH, mediaValueLength); + STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount].mediaName, mediaValue, minMediaValueLength); + pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount].mediaName[minMediaValueLength] = '\0'; pSessionDescription->mediaCount++; CleanUp: @@ -16,22 +23,30 @@ STATUS parseMediaName(PSessionDescription pSessionDescription, PCHAR pch, UINT32 return retStatus; } -STATUS parseSessionAttributes(PSessionDescription pSessionDescription, PCHAR pch, UINT32 lineLen) +STATUS parseSessionAttributes(PSessionDescription pSessionDescription, PCHAR pValue, SIZE_T valueLength) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - PCHAR search; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpAttribute_t attribute; + SIZE_T minAttributeLength; CHK(pSessionDescription->sessionAttributesCount < MAX_SDP_ATTRIBUTES_COUNT, STATUS_SDP_ATTRIBUTE_MAX_EXCEEDED); - if ((search = STRNCHR(pch, lineLen, ':')) == NULL) { - STRNCPY(pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeName, pch + SDP_ATTRIBUTE_LENGTH, - MIN(MAX_SDP_ATTRIBUTE_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } else { - STRNCPY(pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeName, pch + SDP_ATTRIBUTE_LENGTH, - (search - (pch + SDP_ATTRIBUTE_LENGTH))); - STRNCPY(pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeValue, search + 1, - MIN(MAX_SDP_ATTRIBUTE_VALUE_LENGTH, lineLen - (search - pch + 1))); + // Session attributes + sdpResult = SdpDeserializer_ParseAttribute(pValue, valueLength, &attribute); + CHK(sdpResult == SDP_RESULT_OK, convertSdpErrorCode(sdpResult)); + + minAttributeLength = MIN(MAX_SDP_ATTRIBUTE_NAME_LENGTH, attribute.attributeNameLength); + STRNCPY(pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeName, attribute.pAttributeName, + minAttributeLength); + pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeName[minAttributeLength] = '\0'; + + if (attribute.pAttributeValue != NULL) { + minAttributeLength = MIN(MAX_SDP_ATTRIBUTE_VALUE_LENGTH, attribute.attributeValueLength); + STRNCPY(pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeValue, attribute.pAttributeValue, + minAttributeLength); + pSessionDescription->sdpAttributes[pSessionDescription->sessionAttributesCount].attributeValue[minAttributeLength] = '\0'; } pSessionDescription->sessionAttributesCount++; @@ -42,27 +57,37 @@ STATUS parseSessionAttributes(PSessionDescription pSessionDescription, PCHAR pch return retStatus; } -STATUS parseMediaAttributes(PSessionDescription pSessionDescription, PCHAR pch, UINT32 lineLen) +STATUS parseMediaAttributes(PSessionDescription pSessionDescription, PCHAR pValue, SIZE_T valueLength) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - PCHAR search; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpAttribute_t attribute; UINT16 currentMediaAttributesCount; + UINT32 mediaIdx = pSessionDescription->mediaCount - 1; + SIZE_T minAttributeNameLength; - currentMediaAttributesCount = pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].mediaAttributesCount; + currentMediaAttributesCount = pSessionDescription->mediaDescriptions[mediaIdx].mediaAttributesCount; CHK(currentMediaAttributesCount < MAX_SDP_ATTRIBUTES_COUNT, STATUS_SDP_ATTRIBUTE_MAX_EXCEEDED); - if ((search = STRNCHR(pch, lineLen, ':')) == NULL) { - STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].sdpAttributes[currentMediaAttributesCount].attributeName, - pch + SDP_ATTRIBUTE_LENGTH, MIN(MAX_SDP_ATTRIBUTE_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } else { - STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].sdpAttributes[currentMediaAttributesCount].attributeName, - pch + SDP_ATTRIBUTE_LENGTH, (search - (pch + SDP_ATTRIBUTE_LENGTH))); - STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].sdpAttributes[currentMediaAttributesCount].attributeValue, - search + 1, MIN(MAX_SDP_ATTRIBUTE_VALUE_LENGTH, lineLen - (search - pch + 1))); + // Media attributes + sdpResult = SdpDeserializer_ParseAttribute(pValue, valueLength, &attribute); + CHK(sdpResult == SDP_RESULT_OK, convertSdpErrorCode(sdpResult)); + + minAttributeNameLength = MIN(MAX_SDP_ATTRIBUTE_NAME_LENGTH, attribute.attributeNameLength); + STRNCPY(pSessionDescription->mediaDescriptions[mediaIdx].sdpAttributes[currentMediaAttributesCount].attributeName, attribute.pAttributeName, + minAttributeNameLength); + pSessionDescription->mediaDescriptions[mediaIdx].sdpAttributes[currentMediaAttributesCount].attributeName[minAttributeNameLength] = '\0'; + + if (attribute.pAttributeValue != NULL) { + minAttributeNameLength = MIN(MAX_SDP_ATTRIBUTE_VALUE_LENGTH, attribute.attributeValueLength); + STRNCPY(pSessionDescription->mediaDescriptions[mediaIdx].sdpAttributes[currentMediaAttributesCount].attributeValue, attribute.pAttributeValue, + minAttributeNameLength); + pSessionDescription->mediaDescriptions[mediaIdx].sdpAttributes[currentMediaAttributesCount].attributeValue[minAttributeNameLength] = '\0'; } - pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].mediaAttributesCount++; + + pSessionDescription->mediaDescriptions[mediaIdx].mediaAttributesCount++; CleanUp: @@ -74,74 +99,76 @@ STATUS deserializeSessionDescription(PSessionDescription pSessionDescription, PC { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - PCHAR curr, tail, next; - UINT32 lineLen; - CHK(sdpBytes != NULL, STATUS_SESSION_DESCRIPTION_INVALID_SESSION_DESCRIPTION); + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpDeserializerContext_t ctx; + CHAR* pValue; + SIZE_T valueLength; + UINT8 type; + SIZE_T minLength; - curr = sdpBytes; - tail = sdpBytes + STRLEN(sdpBytes); + CHK(sdpBytes != NULL, STATUS_SESSION_DESCRIPTION_INVALID_SESSION_DESCRIPTION); - while ((next = STRNCHR(curr, tail - curr, '\n')) != NULL) { - lineLen = (UINT32) (next - curr); + sdpResult = SdpDeserializer_Init(&ctx, sdpBytes, STRLEN(sdpBytes)); + CHK(sdpResult == SDP_RESULT_OK, convertSdpErrorCode(sdpResult)); - if (lineLen > 0 && curr[lineLen - 1] == '\r') { - lineLen--; - } + while (sdpResult == SDP_RESULT_OK) { + sdpResult = SdpDeserializer_GetNext(&ctx, &type, (const CHAR**) &pValue, (size_t*) &valueLength); - if (0 == STRNCMP(curr, SDP_MEDIA_NAME_MARKER, (ARRAY_SIZE(SDP_MEDIA_NAME_MARKER) - 1))) { - CHK_STATUS(parseMediaName(pSessionDescription, curr, lineLen)); + if (sdpResult == SDP_RESULT_OK) { + /* Do nothing. */ + } else { + retStatus = convertSdpErrorCode(sdpResult); + break; } - if (pSessionDescription->mediaCount != 0) { - if (0 == STRNCMP(curr, SDP_ATTRIBUTE_MARKER, (ARRAY_SIZE(SDP_ATTRIBUTE_MARKER) - 1))) { - CHK_STATUS(parseMediaAttributes(pSessionDescription, curr, lineLen)); - } - - // Media Title - if (0 == STRNCMP(curr, SDP_INFORMATION_MARKER, (ARRAY_SIZE(SDP_INFORMATION_MARKER) - 1))) { - STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].mediaTitle, (curr + SDP_ATTRIBUTE_LENGTH), - MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); + if (type == SDP_TYPE_MEDIA) { + CHK_STATUS(parseMediaName(pSessionDescription, pValue, valueLength)); + } else if (pSessionDescription->mediaCount != 0) { + if (type == SDP_TYPE_ATTRIBUTE) { + CHK_STATUS(parseMediaAttributes(pSessionDescription, pValue, valueLength)); + } else if (type == SDP_TYPE_SESSION_INFO) { + // Media Title + minLength = MIN(MAX_SDP_MEDIA_TITLE_LENGTH, valueLength); + STRNCPY(pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].mediaTitle, pValue, minLength); + pSessionDescription->mediaDescriptions[pSessionDescription->mediaCount - 1].mediaTitle[minLength] = '\0'; + } else { + /* Do nothing. */ } } else { - // SDP Session Name - if (0 == STRNCMP(curr, SDP_SESSION_NAME_MARKER, (ARRAY_SIZE(SDP_SESSION_NAME_MARKER) - 1))) { - STRNCPY(pSessionDescription->sessionName, (curr + SDP_ATTRIBUTE_LENGTH), - MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } - - // SDP Session Name - if (0 == STRNCMP(curr, SDP_INFORMATION_MARKER, (ARRAY_SIZE(SDP_INFORMATION_MARKER) - 1))) { - STRNCPY(pSessionDescription->sessionInformation, (curr + SDP_ATTRIBUTE_LENGTH), - MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } - - // SDP URI - if (0 == STRNCMP(curr, SDP_URI_MARKER, (ARRAY_SIZE(SDP_URI_MARKER) - 1))) { - STRNCPY(pSessionDescription->uri, (curr + SDP_ATTRIBUTE_LENGTH), MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } - - // SDP Email Address - if (0 == STRNCMP(curr, SDP_EMAIL_ADDRESS_MARKER, (ARRAY_SIZE(SDP_EMAIL_ADDRESS_MARKER) - 1))) { - STRNCPY(pSessionDescription->emailAddress, (curr + SDP_ATTRIBUTE_LENGTH), - MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } - - // SDP Phone number - if (0 == STRNCMP(curr, SDP_PHONE_NUMBER_MARKER, (ARRAY_SIZE(SDP_PHONE_NUMBER_MARKER) - 1))) { - STRNCPY(pSessionDescription->phoneNumber, (curr + SDP_ATTRIBUTE_LENGTH), - MIN(MAX_SDP_MEDIA_NAME_LENGTH, lineLen - SDP_ATTRIBUTE_LENGTH)); - } - - if (0 == STRNCMP(curr, SDP_VERSION_MARKER, (ARRAY_SIZE(SDP_VERSION_MARKER) - 1))) { - STRTOUI64(curr + SDP_ATTRIBUTE_LENGTH, curr + MIN(lineLen, MAX_SDP_TOKEN_LENGTH), 10, &pSessionDescription->version); - } - - if (0 == STRNCMP(curr, SDP_ATTRIBUTE_MARKER, (ARRAY_SIZE(SDP_ATTRIBUTE_MARKER) - 1))) { - CHK_STATUS(parseSessionAttributes(pSessionDescription, curr, lineLen)); + if (type == SDP_TYPE_SESSION_NAME) { + // SDP Session Name + minLength = MIN(MAX_SDP_SESSION_NAME_LENGTH, valueLength); + STRNCPY(pSessionDescription->sessionName, pValue, minLength); + pSessionDescription->sessionName[minLength] = '\0'; + } else if (type == SDP_TYPE_SESSION_INFO) { + // SDP Session Information + minLength = MIN(MAX_SDP_SESSION_INFORMATION_LENGTH, valueLength); + STRNCPY(pSessionDescription->sessionInformation, pValue, minLength); + pSessionDescription->sessionInformation[minLength] = '\0'; + } else if (type == SDP_TYPE_URI) { + // SDP URI + minLength = MIN(MAX_SDP_SESSION_URI_LENGTH, valueLength); + STRNCPY(pSessionDescription->uri, pValue, minLength); + pSessionDescription->uri[minLength] = '\0'; + } else if (type == SDP_TYPE_EMAIL) { + // SDP Email Address + minLength = MIN(MAX_SDP_SESSION_EMAIL_ADDRESS_LENGTH, valueLength); + STRNCPY(pSessionDescription->emailAddress, pValue, minLength); + pSessionDescription->emailAddress[minLength] = '\0'; + } else if (type == SDP_TYPE_PHONE) { + // SDP Phone number + minLength = MIN(MAX_SDP_SESSION_PHONE_NUMBER_LENGTH, valueLength); + STRNCPY(pSessionDescription->phoneNumber, pValue, minLength); + pSessionDescription->phoneNumber[minLength] = '\0'; + } else if (type == SDP_TYPE_VERSION) { + // Version + STRTOUI64(pValue, pValue + valueLength, 10, &pSessionDescription->version); + } else if (type == SDP_TYPE_ATTRIBUTE) { + CHK_STATUS(parseSessionAttributes(pSessionDescription, pValue, valueLength)); + } else { + /* Do nothing. */ } } - - curr = next + 1; } CleanUp: diff --git a/src/source/Sdp/Sdp.h b/src/source/Sdp/Sdp.h index 6077a4e100..8651acd2ad 100644 --- a/src/source/Sdp/Sdp.h +++ b/src/source/Sdp/Sdp.h @@ -11,38 +11,12 @@ extern "C" { #endif -#define SDP_ATTRIBUTE_MARKER "a=" -#define SDP_BANDWIDTH_MARKER "b=" -#define SDP_CONNECTION_INFORMATION_MARKER "c=" -#define SDP_EMAIL_ADDRESS_MARKER "e=" -#define SDP_ENCRYPTION_KEY_MARKER "k=" - -// Media title information or Session information -#define SDP_INFORMATION_MARKER "i=" - -#define SDP_MEDIA_NAME_MARKER "m=" -#define SDP_ORIGIN_MARKER "o=" -#define SDP_PHONE_NUMBER_MARKER "p=" -#define SDP_SESSION_NAME_MARKER "s=" -#define SDP_TIME_DESCRIPTION_MARKER "t=" -#define SDP_TIMEZONE_MARKER "z=" -#define SDP_URI_MARKER "u=" -#define SDP_VERSION_MARKER "v=" - -// The sequence CRLF (0x0d0a) is used to end a record, although parsers SHOULD be -// tolerant and also accept records terminated with a single newline -// character. -// Reference: https://tools.ietf.org/html/rfc4566#section-5 -#define SDP_LINE_SEPARATOR "\r\n" - #define SDP_CANDIDATE_TYPE_HOST "host" #define SDP_CANDIDATE_TYPE_SERFLX "srflx" #define SDP_CANDIDATE_TYPE_PRFLX "prflx" #define SDP_CANDIDATE_TYPE_RELAY "relay" #define SDP_CANDIDATE_TYPE_UNKNOWN "unknown" -#define SDP_ATTRIBUTE_LENGTH 2 - #define MAX_SDP_OFFSET_LENGTH 255 #define MAX_SDP_ENCRYPTION_KEY_METHOD_LENGTH 255 #define MAX_SDP_ENCRYPTION_KEY_LENGTH 255 @@ -91,8 +65,7 @@ extern "C" { #define MAX_SDP_SESSION_EMAIL_ADDRESS_LENGTH 255 #define MAX_SDP_SESSION_PHONE_NUMBER_LENGTH 255 -#define MAX_SDP_TOKEN_LENGTH 128 -#define MAX_SDP_FMTP_VALUES 64 +#define MAX_SDP_FMTP_VALUES 64 #define MAX_SDP_SESSION_TIME_DESCRIPTION_COUNT 2 #define MAX_SDP_SESSION_TIMEZONE_COUNT 2 @@ -237,10 +210,6 @@ STATUS deserializeSessionDescription(PSessionDescription, PCHAR); // Return code maps to a code if we are trying to serialize an invalid session_description STATUS serializeSessionDescription(PSessionDescription, PCHAR, PUINT32); -STATUS parseMediaName(PSessionDescription, PCHAR, UINT32); -STATUS parseSessionAttributes(PSessionDescription, PCHAR, UINT32); -STATUS parseMediaAttributes(PSessionDescription, PCHAR, UINT32); - #ifdef __cplusplus } #endif diff --git a/src/source/Sdp/SdpUtils.c b/src/source/Sdp/SdpUtils.c new file mode 100644 index 0000000000..b9ad8e5612 --- /dev/null +++ b/src/source/Sdp/SdpUtils.c @@ -0,0 +1,75 @@ +#define LOG_CLASS "SDPUtils" +#include "../Include_i.h" +#include "kvssdp/sdp_data_types.h" + +STATUS convertSdpErrorCode(SdpResult_t sdpResult) +{ + STATUS retStatus = STATUS_SUCCESS; + + switch (sdpResult) { + case SDP_RESULT_OK: + case SDP_RESULT_MESSAGE_END: + /* SDP_RESULT_MESSAGE_END means content is completely parsed, no error happens. */ + retStatus = STATUS_SUCCESS; + break; + case SDP_RESULT_BAD_PARAM: + retStatus = STATUS_INVALID_ARG; + break; + case SDP_RESULT_MESSAGE_MALFORMED: + retStatus = STATUS_SDP_MESSAGE_MALFORMED; + break; + case SDP_RESULT_MESSAGE_MALFORMED_NOT_ENOUGH_INFO: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_NOT_ENOUGH_INFO; + break; + case SDP_RESULT_MESSAGE_MALFORMED_EQUAL_NOT_FOUND: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_EQUAL_NOT_FOUND; + break; + case SDP_RESULT_MESSAGE_MALFORMED_NEWLINE_NOT_FOUND: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_NEWLINE_NOT_FOUND; + break; + case SDP_RESULT_MESSAGE_MALFORMED_NO_VALUE: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_NO_VALUE; + break; + case SDP_RESULT_MESSAGE_MALFORMED_NO_SESSION_ID: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_NO_SESSION_ID; + break; + case SDP_RESULT_MESSAGE_MALFORMED_NO_SESSION_VERSION: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_NO_SESSION_VERSION; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_NETWORK_TYPE: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_NETWORK_TYPE; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_ADDRESS_TYPE: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_ADDRESS_TYPE; + break; + case SDP_RESULT_MESSAGE_MALFORMED_REDUNDANT_INFO: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_REDUNDANT_INFO; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_BANDWIDTH: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_BANDWIDTH; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_START_TIME: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_START_TIME; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_STOP_TIME: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_STOP_TIME; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_PORT: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_PORT; + break; + case SDP_RESULT_MESSAGE_MALFORMED_INVALID_PORTNUM: + retStatus = STATUS_SDP_MESSAGE_MALFORMED_INVALID_PORTNUM; + break; + case SDP_RESULT_OUT_OF_MEMORY: + retStatus = STATUS_BUFFER_TOO_SMALL; + break; + case SDP_RESULT_SNPRINTF_ERROR: + retStatus = STATUS_SDP_SNPRINTF_ERROR; + break; + default: + retStatus = STATUS_SDP_UNKNOWN_ERROR; + break; + } + + return retStatus; +} diff --git a/src/source/Sdp/Serialize.c b/src/source/Sdp/Serialize.c index 1f1533550b..625ab7a752 100644 --- a/src/source/Sdp/Serialize.c +++ b/src/source/Sdp/Serialize.c @@ -1,136 +1,146 @@ -#define LOG_CLASS "SDP" +#define LOG_CLASS "SDPSerialize" #include "../Include_i.h" +#include "kvssdp/sdp_serializer.h" -STATUS serializeVersion(UINT64 version, PCHAR* ppOutputData, PUINT32 pTotalWritten, PUINT32 pBufferSize) +// Convert error code from SDP library to STATUS. +extern STATUS convertSdpErrorCode(SdpResult_t sdpResult); + +static STATUS serializeVersion(SdpSerializerContext_t* pCtx, UINT64 version) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; - - currentWriteSize = SNPRINTF(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_VERSION_MARKER "%" PRIu64 SDP_LINE_SEPARATOR, version); + SdpResult_t sdpResult = SDP_RESULT_OK; - CHK(*ppOutputData == NULL || ((*pBufferSize - *pTotalWritten) >= currentWriteSize), STATUS_BUFFER_TOO_SMALL); - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; - } + sdpResult = SdpSerializer_AddU64(pCtx, SDP_TYPE_VERSION, version); -CleanUp: + retStatus = convertSdpErrorCode(sdpResult); LEAVES(); return retStatus; } -STATUS serializeOrigin(PSdpOrigin pSDPOrigin, PCHAR* ppOutputData, PUINT32 pTotalWritten, PUINT32 pBufferSize) +static STATUS serializeOrigin(SdpSerializerContext_t* pCtx, PSdpOrigin pSDPOrigin) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpOriginator_t origin; CHK(pSDPOrigin != NULL, STATUS_NULL_ARG); if (pSDPOrigin->userName[0] != '\0' && pSDPOrigin->sdpConnectionInformation.networkType[0] != '\0' && pSDPOrigin->sdpConnectionInformation.addressType[0] != '\0' && pSDPOrigin->sdpConnectionInformation.connectionAddress[0] != '\0') { - currentWriteSize = SNPRINTF(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_ORIGIN_MARKER "%s %" PRIu64 " %" PRIu64 " %s %s %s" SDP_LINE_SEPARATOR, pSDPOrigin->userName, - pSDPOrigin->sessionId, pSDPOrigin->sessionVersion, pSDPOrigin->sdpConnectionInformation.networkType, - pSDPOrigin->sdpConnectionInformation.addressType, pSDPOrigin->sdpConnectionInformation.connectionAddress); - - CHK(*ppOutputData == NULL || ((*pBufferSize - *pTotalWritten) >= currentWriteSize), STATUS_BUFFER_TOO_SMALL); - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; - } + origin.pUserName = pSDPOrigin->userName; + origin.userNameLength = STRNLEN(pSDPOrigin->userName, MAX_SDP_SESSION_USERNAME_LENGTH); + origin.sessionId = pSDPOrigin->sessionId; + origin.sessionVersion = pSDPOrigin->sessionVersion; + + CHK(STRCMP(pSDPOrigin->sdpConnectionInformation.networkType, "IN") == 0, STATUS_INVALID_ARG); + + origin.connectionInfo.networkType = SDP_NETWORK_IN; + } + + CHK(STRCMP(pSDPOrigin->sdpConnectionInformation.addressType, "IP4") == 0 || STRCMP(pSDPOrigin->sdpConnectionInformation.addressType, "IP6") == 0, + STATUS_INVALID_ARG); + + if (STRCMP(pSDPOrigin->sdpConnectionInformation.addressType, "IP4") == 0) { + origin.connectionInfo.addressType = SDP_ADDRESS_IPV4; + } else { + origin.connectionInfo.addressType = SDP_ADDRESS_IPV6; } + origin.connectionInfo.pAddress = pSDPOrigin->sdpConnectionInformation.connectionAddress; + origin.connectionInfo.addressLength = STRNLEN(pSDPOrigin->sdpConnectionInformation.connectionAddress, MAX_SDP_CONNECTION_ADDRESS_LENGTH); + + sdpResult = SdpSerializer_AddOriginator(pCtx, SDP_TYPE_ORIGINATOR, &origin); + + retStatus = convertSdpErrorCode(sdpResult); + CleanUp: LEAVES(); return retStatus; } -STATUS serializeSessionName(PCHAR sessionName, PCHAR* ppOutputData, PUINT32 pTotalWritten, PUINT32 pBufferSize) +static STATUS serializeSessionName(SdpSerializerContext_t* pCtx, PCHAR sessionName, UINT32 sessionNameSize) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; - if (sessionName[0] != '\0') { - currentWriteSize = SNPRINTF(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_SESSION_NAME_MARKER "%s" SDP_LINE_SEPARATOR, sessionName); + /* Check if session name available. */ + if ((sessionName != NULL) && (sessionName[0] != '\0')) { + sdpResult = SdpSerializer_AddBuffer(pCtx, SDP_TYPE_SESSION_NAME, sessionName, STRNLEN(sessionName, sessionNameSize)); - CHK(*ppOutputData == NULL || ((*pBufferSize - *pTotalWritten) >= currentWriteSize), STATUS_BUFFER_TOO_SMALL); - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; - } + retStatus = convertSdpErrorCode(sdpResult); } -CleanUp: - LEAVES(); return retStatus; } -STATUS serializeTimeDescription(PSdpTimeDescription pSDPTimeDescription, PCHAR* ppOutputData, PUINT32 pTotalWritten, PUINT32 pBufferSize) +static STATUS serializeTimeDescription(SdpSerializerContext_t* pCtx, PSdpTimeDescription pSDPTimeDescription) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpTimeDescription_t time; - currentWriteSize = SNPRINTF(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_TIME_DESCRIPTION_MARKER "%" PRIu64 " %" PRIu64 SDP_LINE_SEPARATOR, pSDPTimeDescription->startTime, - pSDPTimeDescription->stopTime); + CHK(pSDPTimeDescription != NULL, STATUS_NULL_ARG); - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; - } + time.startTime = pSDPTimeDescription->startTime; + time.stopTime = pSDPTimeDescription->stopTime; + sdpResult = SdpSerializer_AddTimeActive(pCtx, SDP_TYPE_TIME_ACTIVE, &time); + + retStatus = convertSdpErrorCode(sdpResult); + +CleanUp: LEAVES(); return retStatus; } -STATUS serializeAttribute(PSdpAttributes pSDPAttributes, PCHAR* ppOutputData, PUINT32 pTotalWritten, PUINT32 pBufferSize) +static STATUS serializeAttribute(SdpSerializerContext_t* pCtx, PSdpAttributes pSDPAttributes) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpAttribute_t attribute; + + CHK(pSDPAttributes != NULL, STATUS_NULL_ARG); + + attribute.pAttributeName = pSDPAttributes->attributeName; + attribute.attributeNameLength = STRNLEN(pSDPAttributes->attributeName, MAX_SDP_ATTRIBUTE_NAME_LENGTH); if (pSDPAttributes->attributeValue[0] == '\0') { - currentWriteSize = SNPRINTF(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_ATTRIBUTE_MARKER "%s" SDP_LINE_SEPARATOR, pSDPAttributes->attributeName); + attribute.pAttributeValue = NULL; + attribute.attributeValueLength = 0; } else { - currentWriteSize = snprintf(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_ATTRIBUTE_MARKER "%s:%s" SDP_LINE_SEPARATOR, pSDPAttributes->attributeName, pSDPAttributes->attributeValue); + attribute.pAttributeValue = pSDPAttributes->attributeValue; + attribute.attributeValueLength = STRNLEN(pSDPAttributes->attributeValue, MAX_SDP_ATTRIBUTE_VALUE_LENGTH); } - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; - } + sdpResult = SdpSerializer_AddAttribute(pCtx, SDP_TYPE_ATTRIBUTE, &attribute); + + retStatus = convertSdpErrorCode(sdpResult); + +CleanUp: LEAVES(); return retStatus; } -STATUS serializeMediaName(PCHAR pMediaName, PCHAR* ppOutputData, PUINT32 pTotalWritten, PUINT32 pBufferSize) +static STATUS serializeMediaName(SdpSerializerContext_t* pCtx, PCHAR pMediaName, UINT32 mediaNameSize) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; - if (pMediaName[0] != '\0') { - currentWriteSize = snprintf(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_MEDIA_NAME_MARKER "%s" SDP_LINE_SEPARATOR, pMediaName); + CHK(pMediaName != NULL, STATUS_NULL_ARG); - CHK(*ppOutputData == NULL || ((*pBufferSize - *pTotalWritten) >= currentWriteSize), STATUS_BUFFER_TOO_SMALL); - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; - } - } + sdpResult = SdpSerializer_AddBuffer(pCtx, SDP_TYPE_MEDIA, pMediaName, STRNLEN(pMediaName, mediaNameSize)); + + retStatus = convertSdpErrorCode(sdpResult); CleanUp: @@ -138,23 +148,35 @@ STATUS serializeMediaName(PCHAR pMediaName, PCHAR* ppOutputData, PUINT32 pTotalW return retStatus; } -STATUS serializeMediaConnectionInformation(PSdpConnectionInformation pSdpConnectionInformation, PCHAR* ppOutputData, PUINT32 pTotalWritten, - PUINT32 pBufferSize) +static STATUS serializeMediaConnectionInformation(SdpSerializerContext_t* pCtx, PSdpConnectionInformation pSdpConnectionInformation) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - UINT32 currentWriteSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpConnectionInfo_t connInfo; + + CHK(pSdpConnectionInformation != NULL, STATUS_NULL_ARG); if (pSdpConnectionInformation->networkType[0] != '\0') { - currentWriteSize = SNPRINTF(*ppOutputData, (*ppOutputData) == NULL ? 0 : *pBufferSize - *pTotalWritten, - SDP_CONNECTION_INFORMATION_MARKER "%s %s %s" SDP_LINE_SEPARATOR, pSdpConnectionInformation->networkType, - pSdpConnectionInformation->addressType, pSdpConnectionInformation->connectionAddress); - - CHK(*ppOutputData == NULL || ((*pBufferSize - *pTotalWritten) >= currentWriteSize), STATUS_BUFFER_TOO_SMALL); - *pTotalWritten += currentWriteSize; - if (*ppOutputData != NULL) { - *ppOutputData += currentWriteSize; + /* Append connection info */ + CHK(STRCMP(pSdpConnectionInformation->networkType, "IN") == 0, STATUS_INVALID_ARG); + connInfo.networkType = SDP_NETWORK_IN; + + CHK(STRCMP(pSdpConnectionInformation->addressType, "IP4") == 0 || STRCMP(pSdpConnectionInformation->addressType, "IP6") == 0, + STATUS_INVALID_ARG); + + if (STRCMP(pSdpConnectionInformation->addressType, "IP4") == 0) { + connInfo.addressType = SDP_ADDRESS_IPV4; + } else { + connInfo.addressType = SDP_ADDRESS_IPV6; } + + connInfo.pAddress = pSdpConnectionInformation->connectionAddress; + connInfo.addressLength = STRNLEN(pSdpConnectionInformation->connectionAddress, MAX_SDP_CONNECTION_ADDRESS_LENGTH); + + sdpResult = SdpSerializer_AddConnectionInfo(pCtx, SDP_TYPE_CONNINFO, &connInfo); + + retStatus = convertSdpErrorCode(sdpResult); } CleanUp: @@ -167,34 +189,59 @@ STATUS serializeSessionDescription(PSessionDescription pSessionDescription, PCHA { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - PCHAR curr = sdpBytes; - UINT32 i, j, bufferSize = 0; + SdpResult_t sdpResult = SDP_RESULT_OK; + SdpSerializerContext_t ctx; + char* pSdpMessage; + SIZE_T sdpMessageLength; + UINT32 i, j; + + sdpResult = SdpSerializer_Init(&ctx, sdpBytes, *sdpBytesLength); + CHK(sdpResult == SDP_RESULT_OK, convertSdpErrorCode(sdpResult)); - CHK(pSessionDescription != NULL && sdpBytesLength != NULL, STATUS_NULL_ARG); + /* Append version. */ + CHK_STATUS(serializeVersion(&ctx, pSessionDescription->version)); - bufferSize = *sdpBytesLength; - *sdpBytesLength = 0; + /* Append originator. */ + CHK_STATUS(serializeOrigin(&ctx, &(pSessionDescription->sdpOrigin))); - CHK_STATUS(serializeVersion(pSessionDescription->version, &curr, sdpBytesLength, &bufferSize)); - CHK_STATUS(serializeOrigin(&pSessionDescription->sdpOrigin, &curr, sdpBytesLength, &bufferSize)); - CHK_STATUS(serializeSessionName(pSessionDescription->sessionName, &curr, sdpBytesLength, &bufferSize)); + /* Append session name. */ + CHK_STATUS(serializeSessionName(&ctx, pSessionDescription->sessionName, MAX_SDP_SESSION_NAME_LENGTH)); + + /* Append time description. */ for (i = 0; i < pSessionDescription->timeDescriptionCount; i++) { - CHK_STATUS(serializeTimeDescription(&pSessionDescription->sdpTimeDescription[i], &curr, sdpBytesLength, &bufferSize)); + CHK_STATUS(serializeTimeDescription(&ctx, &(pSessionDescription->sdpTimeDescription[i]))); } + + /* Append session attributes. */ for (i = 0; i < pSessionDescription->sessionAttributesCount; i++) { - CHK_STATUS(serializeAttribute(&pSessionDescription->sdpAttributes[i], &curr, sdpBytesLength, &bufferSize)); + CHK_STATUS(serializeAttribute(&ctx, &(pSessionDescription->sdpAttributes[i]))); } + /* Append media. */ for (i = 0; i < pSessionDescription->mediaCount; i++) { - CHK_STATUS(serializeMediaName(pSessionDescription->mediaDescriptions[i].mediaName, &curr, sdpBytesLength, &bufferSize)); - CHK_STATUS(serializeMediaConnectionInformation(&(pSessionDescription->mediaDescriptions[i].sdpConnectionInformation), &curr, sdpBytesLength, - &bufferSize)); + CHK_STATUS(serializeMediaName(&ctx, pSessionDescription->mediaDescriptions[i].mediaName, MAX_SDP_MEDIA_NAME_LENGTH)); + CHK_STATUS(serializeMediaConnectionInformation(&ctx, &(pSessionDescription->mediaDescriptions[i].sdpConnectionInformation))); + + /* Append media attributes. */ for (j = 0; j < pSessionDescription->mediaDescriptions[i].mediaAttributesCount; j++) { - CHK_STATUS(serializeAttribute(&pSessionDescription->mediaDescriptions[i].sdpAttributes[j], &curr, sdpBytesLength, &bufferSize)); + CHK_STATUS(serializeAttribute(&ctx, &(pSessionDescription->mediaDescriptions[i].sdpAttributes[j]))); } } - *sdpBytesLength += 1; // NULL terminator + sdpResult = SdpSerializer_Finalize(&ctx, (const char**) &pSdpMessage, (size_t*) &sdpMessageLength); + CHK(sdpResult == SDP_RESULT_OK, convertSdpErrorCode(sdpResult)); + + /* Append NULL terminator. */ + if (*sdpBytesLength >= sdpMessageLength + 1U) { + *(pSdpMessage + sdpMessageLength) = '\0'; + *sdpBytesLength = sdpMessageLength + 1U; + } else if (sdpBytes == NULL) { + /* If buffer is NULL, we don't really need to append null terminator. + * Reserve space for null terminator. */ + *sdpBytesLength = sdpMessageLength + 1U; + } else { + retStatus = STATUS_BUFFER_TOO_SMALL; + } CleanUp: LEAVES(); diff --git a/tst/SdpApiTest.cpp b/tst/SdpApiTest.cpp index 80dabd8efb..0f425a938e 100644 --- a/tst/SdpApiTest.cpp +++ b/tst/SdpApiTest.cpp @@ -736,8 +736,7 @@ a=rtpmap:111 opus/48000/2 a=rtcp-fb:111 transport-cc a=fmtp:111 minptime=10;useinbandfec=1 a=ssrc:331864867 cname:jyxeGEm09Qe6m8dq -a=ssrc:331864867 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 757d07a0-892a-46e7-a13d-b43fc3ef68c7 - )"); +a=ssrc:331864867 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 757d07a0-892a-46e7-a13d-b43fc3ef68c7)"); auto videoSdp = std::string(R"(m=video 9 UDP/TLS/RTP/SAVPF 96 97 102 103 104 105 c=IN IP4 0.0.0.0 @@ -767,8 +766,7 @@ a=ssrc-group:FID 2039979579 916070044 a=ssrc:2039979579 cname:jyxeGEm09Qe6m8dq a=ssrc:2039979579 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 8c1b020b-e6ab-4002-8450-b816ebff0219 a=ssrc:916070044 cname:jyxeGEm09Qe6m8dq -a=ssrc:916070044 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 8c1b020b-e6ab-4002-8450-b816ebff0219 - )"); +a=ssrc:916070044 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 8c1b020b-e6ab-4002-8450-b816ebff0219)"); auto unsupportedVideoSdp = std::string(R"(m=video 9 UDP/TLS/RTP/SAVPF 200 230 250 270 c=IN IP4 0.0.0.0 @@ -789,8 +787,7 @@ a=fmtp:230 apt=0 a=rtpmap:250 xyz/90000 a=rtpmap:270 xyz/90000 a=fmtp:270 apt=100 -a=ssrc:916070099 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 8c1b020b-e6ab-4002-8450-b816ebff0219 - )"); +a=ssrc:916070099 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 8c1b020b-e6ab-4002-8450-b816ebff0219)"); auto unsupportedAudioSdp = std::string(R"(m=audio 9 UDP/TLS/RTP/SAVPF 500 c=IN IP4 0.0.0.0 @@ -811,8 +808,7 @@ a=rtpmap:111 opus/48000/2 a=rtcp-fb:111 transport-cc a=fmtp:111 minptime=10;useinbandfec=1 a=ssrc:331864867 cname:jyxeGEm09Qe6m8dq -a=ssrc:331864867 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 757d07a0-892a-46e7-a13d-b43fc3ef68c7 - )"); +a=ssrc:331864867 msid:2e3ca9ff-0c7e-4b9d-9471-2ce80de74b84 757d07a0-892a-46e7-a13d-b43fc3ef68c7)"); offerBase += "\n"; offerBase += audioSdp;