diff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml index 2c05cc06b..679e07534 100644 --- a/.github/workflows/abi.yml +++ b/.github/workflows/abi.yml @@ -18,6 +18,7 @@ jobs: - uses: actions/checkout@v3 with: path: pull_request + submodules: true - name: configure run: | cd pull_request diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 0af85fda3..37f6ca137 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -19,6 +19,8 @@ jobs: ndk-version: r23 add-to-path: false - uses: actions/checkout@v3 + with: + submodules: true - name: build run: | cd ./scripts/build-android/ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4a337b6ca..58842b1f8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -23,6 +23,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + submodules: true - name: Configure run: cmake -DENABLE_HEAVY_LOGGING=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-fpermissive -DENABLE_BONDING=1 . diff --git a/.github/workflows/cxx11-macos.yaml b/.github/workflows/cxx11-macos.yaml index 0aa9d420c..5d6aec3dd 100644 --- a/.github/workflows/cxx11-macos.yaml +++ b/.github/workflows/cxx11-macos.yaml @@ -15,6 +15,8 @@ jobs: - name: GoogleTest run: brew install googletest - uses: actions/checkout@v3 + with: + submodules: true - name: configure run: | mkdir _build && cd _build diff --git a/.github/workflows/cxx11-ubuntu.yaml b/.github/workflows/cxx11-ubuntu.yaml index aa74e1fce..7ba775a60 100644 --- a/.github/workflows/cxx11-ubuntu.yaml +++ b/.github/workflows/cxx11-ubuntu.yaml @@ -14,6 +14,8 @@ jobs: BUILD_WRAPPER_OUT_DIR: sonar-output # Directory where build-wrapper output will be placed steps: - uses: actions/checkout@v3 + with: + submodules: true - name: Install sonar-scanner and build-wrapper uses: sonarsource/sonarcloud-github-c-cpp@v2 - name: configure diff --git a/.github/workflows/cxx11-win.yaml b/.github/workflows/cxx11-win.yaml index 1a9e10a95..7cbd98f8b 100644 --- a/.github/workflows/cxx11-win.yaml +++ b/.github/workflows/cxx11-win.yaml @@ -14,6 +14,8 @@ jobs: steps: - uses: actions/checkout@v3 + with: + submodules: true - name: configure run: | md _build && cd _build diff --git a/.github/workflows/iOS.yaml b/.github/workflows/iOS.yaml index 0fb11542b..c89e8825d 100644 --- a/.github/workflows/iOS.yaml +++ b/.github/workflows/iOS.yaml @@ -17,6 +17,8 @@ jobs: steps: - uses: actions/checkout@v3 + with: + submodules: true - name: configure run: | mkdir _build && cd _build diff --git a/.github/workflows/s390x-focal.yaml b/.github/workflows/s390x-focal.yaml index f1b6c7508..c3a927de3 100644 --- a/.github/workflows/s390x-focal.yaml +++ b/.github/workflows/s390x-focal.yaml @@ -23,6 +23,8 @@ jobs: " - name: Checkout uses: actions/checkout@v3 + with: + submodules: true - name: configure uses: docker://multiarch/ubuntu-core:s390x-focal with: diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..9d8501cca --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "submodules/fmt"] + path = submodules/fmt + url = git@github.com:ethouris/fmt.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a2fc63d2..788287239 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,8 @@ set_if(NEED_DESTINATION ${CMAKE_VERSION} VERSION_LESS "3.14.0") include(GNUInstallDirs) +add_subdirectory(submodules/fmt) + # The CMAKE_BUILD_TYPE seems not to be always set, weird. if (NOT DEFINED ENABLE_DEBUG) @@ -1025,6 +1027,7 @@ list(INSERT HEADERS_srt 0 "${CMAKE_CURRENT_BINARY_DIR}/version.h") include_directories("${CMAKE_CURRENT_BINARY_DIR}") add_library(srt_virtual OBJECT ${SOURCES_srt} ${SOURCES_srt_extra} ${HEADERS_srt} ${SOURCES_haicrypt} ${SOURCES_common}) +add_dependencies(srt_virtual fmt) if (ENABLE_SHARED) # Set this to sources as well, as it won't be automatically handled @@ -1057,6 +1060,7 @@ if (srt_libspec_shared) set (CMAKE_POSITION_INDEPENDENT_CODE ON) set_property(TARGET ${TARGET_srt}_shared PROPERTY OUTPUT_NAME ${TARGET_srt}) set_target_properties (${TARGET_srt}_shared PROPERTIES VERSION ${SRT_VERSION} SOVERSION ${SRT_VERSION_MAJOR}.${SRT_VERSION_MINOR}) + target_link_libraries(${TARGET_srt}_shared PRIVATE fmt) list (APPEND INSTALL_TARGETS ${TARGET_srt}_shared) if (ENABLE_ENCRYPTION) target_link_libraries(${TARGET_srt}_shared PRIVATE ${SSL_LIBRARIES}) @@ -1082,6 +1086,7 @@ endif() if (srt_libspec_static) add_library(${TARGET_srt}_static STATIC ${OBJECT_LIB_SUPPORT} ${VIRTUAL_srt}) + target_link_libraries(${TARGET_srt}_static PRIVATE fmt) # For Windows, leave the name to be "srt_static.lib". # Windows generates two different library files: @@ -1115,6 +1120,7 @@ if (srt_libspec_static) endif() target_include_directories(srt_virtual PRIVATE ${SSL_INCLUDE_DIRS}) +target_include_directories(srt_virtual PRIVATE submodules/fmt/include) if (MICROSOFT) if (OPENSSL_USE_STATIC_LIBS) @@ -1281,6 +1287,8 @@ macro(srt_add_program_dont_install name) add_executable(${name} ${ARGN}) target_include_directories(${name} PRIVATE apps) target_include_directories(${name} PRIVATE common) + target_include_directories(${name} PRIVATE submodules/fmt/include) + #message(STATUS "PROGRAM: ${name} with apps, common, fmt; SOURCES: ${ARGN}") endmacro() macro(srt_add_program name) @@ -1364,6 +1372,8 @@ if (ENABLE_APPS) # library should be changed into a static one and made useful # for users. add_library(srtsupport_virtual OBJECT ${SOURCES_support}) + add_dependencies(srtsupport_virtual fmt) + target_include_directories(srtsupport_virtual PRIVATE submodules/fmt/include) srt_set_stdcxx(srtsupport_virtual "${USE_CXX_STD_APP}") set (VIRTUAL_srtsupport $) @@ -1404,6 +1414,7 @@ if (ENABLE_APPS) srt_add_testprogram(utility-test) srt_set_stdcxx(utility-test "${USE_CXX_STD_APP}") + target_link_libraries(utility-test PRIVATE fmt) if (NOT WIN32) # This program is symlinked under git-cygwin. # Avoid misleading syntax error. diff --git a/apps/logsupport.cpp b/apps/logsupport.cpp index fbd70c47e..1ecb20c67 100644 --- a/apps/logsupport.cpp +++ b/apps/logsupport.cpp @@ -173,7 +173,9 @@ set SrtParseLogFA(string fa, set* punknown) void ParseLogFASpec(const vector& speclist, string& w_on, string& w_off) { - std::ostringstream son, soff; + using namespace fmt; + + memory_buffer son, soff; for (auto& s: speclist) { @@ -190,13 +192,13 @@ void ParseLogFASpec(const vector& speclist, string& w_on, string& w_off) name = s; if (on) - son << "," << name; + ffwrite(son, ",", name); else - soff << "," << name; + ffwrite(soff, ",", name); } - const string& sons = son.str(); - const string& soffs = soff.str(); + string sons = ffcat(son); + string soffs = ffcat(soff); w_on = sons.empty() ? string() : sons.substr(1); w_off = soffs.empty() ? string() : soffs.substr(1); diff --git a/apps/srt-file-transmit.cpp b/apps/srt-file-transmit.cpp index 327ad6809..254bd14f7 100644 --- a/apps/srt-file-transmit.cpp +++ b/apps/srt-file-transmit.cpp @@ -390,7 +390,7 @@ bool DoUpload(UriParser& ut, string path, string filename, { int st = tar->Write(buf.data() + shift, n, 0, out_stats); Verb() << "Upload: " << n << " --> " << st - << (!shift ? string() : "+" + Sprint(shift)); + << (!shift ? string() : fmt::ffcat("+", shift)); if (st == SRT_ERROR) { cerr << "Upload: SRT error: " << srt_getlasterror_str() diff --git a/apps/transmitmedia.cpp b/apps/transmitmedia.cpp index 275295173..3a4d5b489 100644 --- a/apps/transmitmedia.cpp +++ b/apps/transmitmedia.cpp @@ -198,7 +198,7 @@ void SrtCommon::InitParameters(string host, map par) if (transmit_chunk_size > SRT_LIVE_MAX_PLSIZE) throw std::runtime_error("Chunk size in live mode exceeds 1456 bytes; this is not supported"); - par["payloadsize"] = Sprint(transmit_chunk_size); + par["payloadsize"] = fmt::ffcat(transmit_chunk_size); } // Assign the others here. diff --git a/apps/uriparser.cpp b/apps/uriparser.cpp index 6b8c80713..81d309b02 100644 --- a/apps/uriparser.cpp +++ b/apps/uriparser.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "fmt/format.h" #include "uriparser.hpp" @@ -57,6 +58,7 @@ UriParser::~UriParser(void) string UriParser::makeUri() { + using namespace fmt; // Reassemble parts into the URI string prefix = ""; if (m_proto != "") @@ -64,41 +66,41 @@ string UriParser::makeUri() prefix = m_proto + "://"; } - std::ostringstream out; + memory_buffer out; - out << prefix << m_host; + ffwrite(out, prefix, m_host); if ((m_port == "" || m_port == "0") && m_expect == EXPECT_FILE) { // Do not add port } else { - out << ":" << m_port; + ffwrite(out, ":", m_port); } if (m_path != "") { if (m_path[0] != '/') - out << "/"; - out << m_path; + ffwrite(out, "/"); + ffwrite(out, m_path); } if (!m_mapQuery.empty()) { - out << "?"; + ffwrite(out, "?"); query_it i = m_mapQuery.begin(); for (;;) { - out << i->first << "=" << i->second; + ffwrite(out, i->first, "=", i->second); ++i; if (i == m_mapQuery.end()) break; - out << "&"; + ffwrite(out, "&"); } } - m_origUri = out.str(); + m_origUri = ffcat(out); return m_origUri; } diff --git a/srtcore/ATTIC/srt_sfmt.h b/srtcore/ATTIC/srt_sfmt.h new file mode 100644 index 000000000..e11b0b730 --- /dev/null +++ b/srtcore/ATTIC/srt_sfmt.h @@ -0,0 +1,1056 @@ +// SOURCE NOTE: +// +// This is copied directly from a public-domain library: +// +// URI: https://github.com/ethouris/fmt +// PATH: include/fmt/sfmt.h +// +// with slight modifications. +// +// Formatting library for C++ - C++03 compat version of on-demand tagged format API. +// +// Copyright (c) 2024 - present, Mikołaj Małecki +// All rights reserved. +// +// For the license information refer to format.h. + +// This is a header-only lightweight C++03-compatible formatting library, +// which provides the on-demand tagged format API and iostream-style wrapper +// for FILE type from stdio. It has nothing to do with the rest of the {fmt} +// library, except that it reuses the namespace. + +#ifndef INC_FMT_SFMT_H +#define INC_FMT_SFMT_H + +#include +#include +#include // std::abs +#include // std::div +#include +#include +#include + +namespace srt +{ + +namespace internal +{ + +template +class form_memory_buffer +{ +public: + static const size_t INITIAL_SIZE = PARAM_INITIAL_SIZE; + typedef std::list< std::vector > slices_t; + +private: + char first[INITIAL_SIZE]; + slices_t slices; + + size_t initial; // size used in `first` + size_t reserved; // total size plus slices in reserve + size_t total; // total size in use + +public: + form_memory_buffer(): initial(0), reserved(0), total(0) {} + + // For constants + template + form_memory_buffer(const char (&array)[N]): initial(N-1), reserved(N-1), total(N-1) + { + memcpy(first, array, N); + } + + size_t avail() + { + return reserved - total; + } + + char* get_first() { return first; } + const char* get_first() const { return first; } + size_t first_size() const { return initial; } + const slices_t& get_slices() const { return slices; } + size_t size() const { return total; } + bool empty() const { return total == 0; } + + void append(char c) + { + char wrap[1] = {c}; + append(wrap, 1); + } + + // NOTE: append ignores the reservation. It writes + // where the currently available space is. Use expose() + // and commit() together or not at all. + void append(const char* val, size_t size) + { + if (size == 0) + return; + + if (slices.empty()) + { + if (size < INITIAL_SIZE - initial) + { + // Still free space in first. + memcpy(first + initial, val, size); + initial += size; + total = initial; + if (reserved < total) + reserved = total; + return; + } + } + + slices.push_back(std::vector(val, val+size)); + total += size; + if (reserved < total) + reserved = total; + } + + char* expose(size_t size) + { + // Repeated exposure simply extends the + // reservation, if required more, or is ignored, + // if required less. + + // Note that ort + + size_t already_reserved = reserved - total; + if (already_reserved >= size) + { + // Identify the reserved region + if (slices.empty()) + { + reserved = total + size; + return first + initial; + } + + std::vector& last = slices.back(); + // Exceptionally resize that part if it doesn't + // fit. + if (last.size() != size) + last.resize(size); + reserved = total + size; + return &last[0]; + } + + // Check if you have any size available + // beyond the current reserved space. + // If not, allocate. + if (slices.empty()) + { + // Not yet resolved to use of the slices, + // so check free space in first. The value of + // 'reserved' should be still < INITIAL_SIZE. + if (INITIAL_SIZE - total >= size) + { + char* b = first + total; + reserved = total + size; + return b; + } + } + + // Otherwise allocate a new slice + // Check first if the last slice was already reserved + std::vector* plast = &slices.back(); + if (!already_reserved) + { + slices.push_back( std::vector() ); + plast = &slices.back(); + } + + plast->reserve(size); + plast->resize(size); + reserved = total + size; + return &(*plast)[0]; + } + + // Remove the last 'size' chars from reservation + bool unreserve(size_t size) + { + if (size > reserved - total) + return false; + + if (!slices.empty()) + { + // Check the last slice if it contains that size + std::vector& last = slices.back(); + if (last.size() < size) + return false; + + size_t remain = last.size() - size; + if (!remain) + { + slices.pop_back(); + reserved -= size; + return true; + } + + last.erase(last.begin() + remain, last.end()); + } + // Otherwise the space is in the initial buffer. + + reserved -= size; + return true; + } + + void commit() + { + total = reserved; + if (slices.empty()) + { + // This means we don't use extra slices, so + // this size must be also repeated in initial + initial = reserved; + } + } + + void clear() + { + slices.clear(); + total = 0; + reserved = 0; + initial = 0; + } +}; + +template +struct CheckChar +{ + static bool is(char c, const char (&series)[N]) + { + return c == series[I] || CheckChar::is(c, series); + } +}; + +template +struct CheckChar +{ + // Terminal version - if none interrupted with true, + // eventually return false. + static bool is(char , const char (&)[N]) { return false; } +}; + +template inline +bool isanyof(char c, const char (&series)[N]) +{ + return CheckChar::is(c, series); +} + +template inline +bool isnum_or(char c, const char (&series)[N]) +{ + if (c >= '0' && c <= '9') + return true; + return isanyof(c, series); +} + +template +struct Ensure +{ +}; + +template +struct Ensure +{ + static void CheckIfCharsetNonEmpty() + { + typename AnyType::wrong_condition v = AnyType::wrong_condition; + (void)v; + } +}; + +template inline +form_memory_buffer<> fix_format(const char* fmt, + const char (&allowed)[N1], + const char (&typed)[N2], + const char (&deftype)[N3], + const char* warn) +{ + // All these arrays must contain at least 2 elements, + // that is one character and terminating zero. + //Ensure= 2> c1; + Ensure= 2)> c2; (void)c2; + Ensure= 2)> c3; (void)c3; + + form_memory_buffer<> buf; + buf.append('%'); + + bool warn_error = false; + if (fmt) + { + size_t len = strlen(fmt); + for (size_t i = 0; i < len; ++i) + { + char c = fmt[i]; + if (internal::isnum_or(c, allowed)) + { + buf.append(c); + continue; + } + + if (internal::isanyof(c, typed)) + { + // If you have found any numbase character, + // add first all characters from the default, + // EXCEPT the last one. + buf.append(deftype, N3-2); + + // that's it, and we're done here. + buf.append(c); + return buf; + } + + // If any other character is found, add the warning + warn_error = true; + break; + } + } + + buf.append(deftype, N3); + + if (warn_error && warn) + { + buf.append(warn, strlen(warn)); + } + return buf; +} + + +#define SFMT_FORMAT_FIXER(TYPE, ALLOWED, TYPED, DEFTYPE, WARN) \ +inline form_memory_buffer<> apply_format_fix(TYPE, const char* fmt) \ +{ \ + return fix_format(fmt, ALLOWED, TYPED, DEFTYPE, WARN); \ +} + +#define SFMT_FORMAT_FIXER_TPL(TPAR, TYPE, ALLOWED, TYPED, DEFTYPE, WARN) \ +template\ +inline form_memory_buffer<> apply_format_fix(TYPE, const char* fmt)\ +{\ + return fix_format(fmt, ALLOWED, TYPED, DEFTYPE, WARN); \ +} + + + +// So, format in the format spec is: +// +// (missing): add the default format +// Using: diouxX - specify the numeric base +// Using efg - specify the float style + +// Modifiers like "h", "l", or "L" shall not +// be used. They will be inserted if needed. + +SFMT_FORMAT_FIXER(int, "+- '#", "dioxX", "i", ""); +SFMT_FORMAT_FIXER(short int, "+- '#", "dioxX", "hi", ""); +SFMT_FORMAT_FIXER(long int, "+- '#", "dioxX", "li", ""); +SFMT_FORMAT_FIXER(long long int, "+- '#", "dioxX", "lli", ""); + +SFMT_FORMAT_FIXER(unsigned int, "+- '#", "uoxX", "u", ""); +SFMT_FORMAT_FIXER(unsigned short int, "+- '#", "uoxX", "hu", ""); +SFMT_FORMAT_FIXER(unsigned long int, "+- '#", "uoxX", "lu", ""); +SFMT_FORMAT_FIXER(unsigned long long int, "+- '#", "uoxX", "llu", ""); + +SFMT_FORMAT_FIXER(double, "+- '#.", "EeFfgGaA", "g", ""); +SFMT_FORMAT_FIXER(float, "+- '#.", "EeFfgGaA", "g", ""); +SFMT_FORMAT_FIXER(long double, "+- '#.", "EeFfgGaA", "Lg", ""); + +SFMT_FORMAT_FIXER(char, "-", "c", "c", ""); + +SFMT_FORMAT_FIXER(std::string, "-.", "s", "s", ""); +SFMT_FORMAT_FIXER(const char*, "-.", "s", "s", ""); +SFMT_FORMAT_FIXER(char*, "-.", "s", "s", ""); +SFMT_FORMAT_FIXER_TPL(size_t N, const char (&)[N], "-.", "s", "s", ""); +SFMT_FORMAT_FIXER_TPL(size_t N, char (&)[N], "-.", "s", "s", ""); +SFMT_FORMAT_FIXER_TPL(class Type, Type*, "-", "p", "p", ""); + +#undef SFMT_FORMAT_FIXER_TPL +#undef SFMT_FORMAT_FIXER + +template +struct const_copy +{ + static void copy(char* target, const char *source) + { + *target = *source; + return const_copy::copy(target + 1, source + 1); + } +}; + +template<> +struct const_copy<1> // 1 because the last item is the terminal '\0'. +{ + static void copy(char*, const char *) { } // do nothing, terminal value +}; + +// These maps must cover all allowed values, for safety. +static const char present_int_map[8] = { 'i', 'o', 'x', 'X', 'd', 'd', 'd', 'd'}; +static const char present_float_map[8] = { 'g', 'G', 'a', 'A', 'e', 'E', 'f', 'g' }; + +} + +struct sfmc +{ + enum postype { pos_no, pos_plus, pos_space, pos_invalid }; + enum flavor { + flavor_dec = 0, + flavor_oct = 1, + flavor_hex = 2, + flavor_uhex = 3, + + flavor_general = 0, + flavor_ugeneral = 1, + flavor_fhex = 2, + flavor_ufhex = 3, + flavor_scientific = 4, + flavor_uscientific = 5, + flavor_fixed = 6 + }; + +protected: + short widthval; + short precisionval; + bool widthbit:1; + bool precisionbit:1; + bool altbit:1; + bool leftbit:1; + bool leadzerobit:1; + postype postype:2; + flavor presentation:3; + bool localized:1; + +public: + sfmc(): + widthval(0), + precisionval(6), + widthbit(false), + precisionbit(false), + altbit(false), + leftbit(false), + leadzerobit(false), + postype(pos_no), + presentation(flavor_dec), + localized(false) + { + } + +#define SFMTC_TAG(name, body) sfmc& name () { body; return *this; } +#define SFMTC_TAG_VAL(name, body) sfmc& name (int val) { body; return *this; } + + SFMTC_TAG(alt, altbit = true); + SFMTC_TAG(left, leftbit = true); + SFMTC_TAG(right, (void)0); + SFMTC_TAG_VAL(width, widthbit = true; widthval = std::abs(val)); + SFMTC_TAG_VAL(precision, precisionbit = true; precisionval = std::abs(val)); + SFMTC_TAG(dec, (void)0); + SFMTC_TAG(hex, presentation = flavor_hex); + SFMTC_TAG(oct, presentation = flavor_oct); + SFMTC_TAG(uhex, presentation = flavor_uhex); + SFMTC_TAG(general, (void)0); + SFMTC_TAG(ugeneral, presentation = flavor_ugeneral); + SFMTC_TAG(fhex, presentation = flavor_fhex); + SFMTC_TAG(ufhex, presentation = flavor_ufhex); + SFMTC_TAG(exp, presentation = flavor_scientific); + SFMTC_TAG(uexp, presentation = flavor_uscientific); + SFMTC_TAG(scientific, presentation = flavor_scientific); + SFMTC_TAG(uscientific, presentation = flavor_uscientific); + SFMTC_TAG(fixed, presentation = flavor_fixed); + SFMTC_TAG(nopos, (void)0); + SFMTC_TAG(posspace, postype = pos_space); + SFMTC_TAG(posplus, postype = pos_plus); + SFMTC_TAG(fillzero, leadzerobit = true); + +#undef SFMTC_TAG +#undef SFMTC_TAG_VAL + + // Utility function to store the number for width/precision + // For C++11 it could be constexpr, but this is C++03-compat code. + // It's bound to this structure because it's unsafe. + static std::size_t store_number(char* position, int number) + { + std::size_t shiftpos = 0; + std::div_t dm = std::div(number, 10); + if (dm.quot) + shiftpos = store_number(position, dm.quot); + position[shiftpos] = '0' + dm.rem; + return shiftpos + 1; + } + + template + internal::form_memory_buffer<> create_format_int(const char (&lnspec)[N]) const + { + using namespace internal; + + Ensure= 2)> c3; (void)c3; + + form_memory_buffer<> form; + + // Use reservation as this will be faster and also + // we don't know how many ciphers will be taken by width/precision + // We need to reserve 12 + 12 + 4 + 4 = 32. + char* buf = form.expose(32); + size_t used = 0; + buf[used++] = '%'; + + if (altbit) + buf[used++] = '#'; + + if (leftbit) + buf[used++] = '-'; + + if (localized) + buf[used++] = '\''; + + if (leadzerobit) + buf[used++] = '0'; + + if (widthbit) + { + size_t w = store_number(buf + used, widthval); + used += w; + } + + // That's it, now we copy the type length modifier + const_copy::copy(buf + used, lnspec); + used += (N - 2); + + // And finally the flavor modifier + if (int(presentation) == 0) + buf[used++] = lnspec[N-2]; + else + buf[used++] = present_int_map[presentation]; + buf[used] = '\0'; + + size_t unused = 32 - used; + if (unused > 0) + form.unreserve(unused); + form.commit(); + + return form; + } + + template + internal::form_memory_buffer<> create_format_float(const char (&lnspec)[N]) const + { + using namespace internal; + Ensure= 2> c3; (void)c3; + + form_memory_buffer<> form; + + // Use reservation as this will be faster and also + // we don't know how many ciphers will be taken by width/precision + // We need to reserve 12 + 12 + 4 + 4 = 32. + char* buf = form.expose(32); + size_t used = 0; + buf[used++] = '%'; + + if (altbit) + buf[used++] = '#'; + + if (leftbit) + buf[used++] = '-'; + + if (localized) + buf[used++] = '\''; + + if (leadzerobit) + buf[used++] = '0'; + + if (widthbit) + { + size_t w = store_number(buf + used, widthval); + used += w; + } + + if (precisionbit) + { + buf[used++] = '.'; + size_t w = store_number(buf + used, precisionval); + used += w; + } + + // That's it, now we copy the type length modifier + const_copy::copy(buf + used, lnspec); + used += (N - 2); + + // And finally the flavor modifier + if (int(presentation) == 0) + buf[used++] = lnspec[N-2]; + else + buf[used++] = present_float_map[presentation]; + buf[used] = '\0'; + + size_t unused = 32 - used; + if (unused > 0) + form.unreserve(unused); + form.commit(); + + return form; + } + + internal::form_memory_buffer<> create_format(int) const { return create_format_int("i"); } + internal::form_memory_buffer<> create_format(short int) const { return create_format_int("hi"); }; + internal::form_memory_buffer<> create_format(long int) const { return create_format_int("li"); }; + internal::form_memory_buffer<> create_format(long long int) const { return create_format_int("lli"); }; + + internal::form_memory_buffer<> create_format(unsigned int) const { return create_format_int("u"); }; + internal::form_memory_buffer<> create_format(unsigned short int) const { return create_format_int("hu"); }; + internal::form_memory_buffer<> create_format(unsigned long int) const { return create_format_int("lu"); }; + internal::form_memory_buffer<> create_format(unsigned long long int) const { return create_format_int("llu"); }; + + internal::form_memory_buffer<> create_format(double) const { return create_format_float("g"); }; + internal::form_memory_buffer<> create_format(float) const { return create_format_float("g"); }; + internal::form_memory_buffer<> create_format(long double) const { return create_format_float("Lg"); }; + + internal::form_memory_buffer<> create_format(char) const + { + internal::form_memory_buffer<> form; + form.append("%c", 3); + return form; + } + + internal::form_memory_buffer<> create_format_string() const + { + using namespace internal; + + form_memory_buffer<> form; + + // Use reservation as this will be faster and also + // we don't know how many ciphers will be taken by width/precision + // We need to reserve 12 + 12 + 4 + 4 = 32. + char* buf = form.expose(32); + size_t used = 0; + buf[used++] = '%'; + + if (leftbit) + buf[used++] = '-'; + + if (widthbit) + { + size_t w = store_number(buf + used, widthval); + used += w; + } + + if (precisionbit) + { + buf[used++] = '.'; + size_t w = store_number(buf + used, precisionval); + used += w; + } + + // No modifier supported + // XXX NOTE: wchar_t therefore not supported! + buf[used++] = 's'; + buf[used] = '\0'; + + size_t unused = 32 - used; + if (unused > 0) + form.unreserve(unused); + form.commit(); + + return form; + } + + internal::form_memory_buffer<> create_format(char*) const { return create_format_string(); }; + internal::form_memory_buffer<> create_format(const char*) const { return create_format_string(); }; + internal::form_memory_buffer<> create_format(std::string) const { return create_format_string(); }; +}; + +// fmt(val, sfmc().alt().hex().width(10)) + +namespace internal +{ + +template inline +void write_default(Stream& str, const Value& val); + +} + +class ostdiostream +{ +protected: + mutable FILE* in; + +public: + + FILE* raw() const { return in; } + + ostdiostream(FILE* f): in(f) {} + + ostdiostream& operator<<(const char* t) + { + std::fputs(t, in); + return *this; + } + + ostdiostream& operator<<(const std::string& s) + { + std::fputs(s.c_str(), in); + return *this; + } + + template + ostdiostream& operator<<(const internal::form_memory_buffer& b) + { + using namespace internal; + // Copy all pieces one by one + if (b.size() == 0) + return *this; + + std::fwrite(b.get_first(), 1, b.first_size(), in); + for (form_memory_buffer<>::slices_t::const_iterator i = b.get_slices().begin(); + i != b.get_slices().end(); ++i) + { + const char* data = &(*i)[0]; + std::fwrite(data, 1, i->size(), in); + } + return *this; + } + + template + ostdiostream& operator<<(const Value& v) + { + internal::write_default(*this, v); + return *this; + } +}; + + +class ofilestream: public ostdiostream +{ +public: + + ofilestream(): ostdiostream(0) {} + + ofilestream(const std::string& name, const std::string& mode = "") + : ostdiostream(0) // Set NULL initially, but then override + { + open(name, mode); + } + + bool good() const { return in; } + + void open(const std::string& name, const std::string& mode = "") + { + if (mode == "") + in = std::fopen(name.c_str(), "w"); + else + in = std::fopen(name.c_str(), mode.c_str()); + } + + // For the use of other functions than fopen() that can create the stream, + // but they still create FILE* that should be closed using fclose(). + void attach(FILE* other) + { + in = other; + } + + FILE* detach() + { + FILE* sav = in; + in = 0; + return sav; + } + + int close() + { + int retval = 0; + if (in) + { + retval = std::fclose(in); + in = 0; + } + return retval; + } + + ~ofilestream() + { + if (in) + std::fclose(in); + } +}; + +class obufstream +{ +protected: + internal::form_memory_buffer<> buffer; + +public: + + obufstream() {} + + void clear() + { + buffer.clear(); + } + + obufstream& operator<<(const char* t) + { + size_t len = strlen(t); + buffer.append(t, len); + return *this; + } + + obufstream& operator<<(const std::string& s) + { + buffer.append(s.data(), s.size()); + return *this; + } + + // For unusual manipulation, usually to add NUL termination. + // NOTE: you must make sure that you won't use the extended + // buffers if the intention was to get a string. + void append(char c) + { + buffer.append(c); + } + + const char* bufptr() const + { + return buffer.get_first(); + } + + template + obufstream& operator<<(const internal::form_memory_buffer& b) + { + using namespace internal; + // Copy all pieces one by one + if (b.size() == 0) + return *this; + + buffer.append(b.get_first(), b.first_size()); + for (form_memory_buffer<>::slices_t::const_iterator i = b.get_slices().begin(); + i != b.get_slices().end(); ++i) + { + // Would be tempting to move the blocks, but C++03 doesn't feature moving. + const char* data = &(*i)[0]; + buffer.append(data, i->size()); + } + return *this; + } + + obufstream& operator<<(const obufstream& source) + { + return *this << source.buffer; + } + + template + obufstream& operator<<(const Value& v) + { + internal::write_default(*this, v); + return *this; + } + + std::string str() const + { + using namespace internal; + std::string out; + if (buffer.empty()) + return out; + + out.reserve(buffer.size() + 1); + out.append(buffer.get_first(), buffer.first_size()); + for (form_memory_buffer<>::slices_t::const_iterator i = buffer.get_slices().begin(); + i != buffer.get_slices().end(); ++i) + { + // Would be tempting to move the blocks, but C++03 doesn't feature moving. + const char* data = &(*i)[0]; + out.append(data, i->size()); + } + return out; + } + + size_t size() const { return buffer.size(); } + + template + void copy_to(OutputContainer& out) const + { + using namespace internal; + + std::copy(buffer.get_first(), buffer.get_first() + buffer.first_size(), + std::back_inserter(out)); + + for (form_memory_buffer<>::slices_t::const_iterator i = buffer.get_slices().begin(); + i != buffer.get_slices().end(); ++i) + { + // Would be tempting to move the blocks, but C++03 doesn't feature moving. + const char* data = &(*i)[0]; + std::copy(data, data + i->size(), std::back_inserter(out)); + } + } + + template + size_t copy_to(OutputContainer& out, size_t maxsize) const + { + using namespace internal; + size_t avail = maxsize; + if (avail < buffer.first_size()) + { + std::copy(buffer.get_first(), buffer.get_first() + avail, + std::back_inserter(out)); + return maxsize; + } + + std::copy(buffer.get_first(), buffer.get_first() + buffer.first_size(), + std::back_inserter(out)); + + avail -= buffer.first_size(); + + for (form_memory_buffer<>::slices_t::const_iterator i = buffer.get_slices().begin(); + i != buffer.get_slices().end(); ++i) + { + // Would be tempting to move the blocks, but C++03 doesn't feature moving. + const char* data = &(*i)[0]; + + if (avail < i->size()) + { + std::copy(data, data + avail, std::back_inserter(out)); + return maxsize; + } + std::copy(data, data + i->size(), std::back_inserter(out)); + avail -= i->size(); + } + + return maxsize - avail; + } +}; + +namespace internal +{ +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define FMT_SYM_SNPRINTF _snprintf +#define FMT_SIZE_SNPRINTF(bufsize) (bufsize-1) +#else +#define FMT_SYM_SNPRINTF std::snprintf +#define FMT_SIZE_SNPRINTF(bufsize) bufsize +#endif + +template +static inline size_t SNPrintfOne(char* buf, size_t bufsize, const char* fmt, const ValueType& val) +{ return FMT_SYM_SNPRINTF (buf, FMT_SIZE_SNPRINTF(bufsize), fmt, val); } + +static inline size_t SNPrintfOne(char* buf, size_t bufsize, const char* fmt, const std::string& val) +{ return FMT_SYM_SNPRINTF(buf, FMT_SIZE_SNPRINTF(bufsize), fmt, val.c_str()); } + +#undef FMT_SYM_SNPRINTF +#undef FMT_SIZE_SNPRINTF + +template inline +form_memory_buffer<> sfmt_imp(const Value& val, const form_memory_buffer<>& fstr, size_t bufsize) +{ + form_memory_buffer<> out; + // Reserve the maximum initial first, then shrink. + char* buf = out.expose(bufsize); + + size_t valsize = SNPrintfOne(buf, bufsize, fstr.get_first(), val); + + // Deemed impossible to happen, but still + if (valsize == bufsize) + { + bufsize *= 2; + // Just try again with one extra size, if this won't + // suffice, just add <...> at the end. + buf = out.expose(bufsize); + valsize = SNPrintfOne(buf, bufsize, fstr.get_first(), val); + if (valsize == bufsize) + { + char* end = buf + bufsize - 6; + strcpy(end, "<...>"); + } + } + + size_t unused = bufsize - valsize; + out.unreserve(unused); + out.commit(); + return out; +} +} + +template inline +internal::form_memory_buffer<> sfmt(const Value& val, const char* fmtspec = 0) +{ + using namespace internal; + + form_memory_buffer<> fstr = apply_format_fix(val, fmtspec); + size_t bufsize = form_memory_buffer<>::INITIAL_SIZE; + + // We want to use this buffer as a NUL-terminated string. + // So we need to add NUL character oursevles, form_memory_buffer<> + // doesn't do it an doesn't use the NUL-termination. + fstr.append('\0'); + + return sfmt_imp(val, fstr, bufsize); +} + +template inline +internal::form_memory_buffer<> sfmt(const Value& val, const sfmc& config) +{ + using namespace internal; + + form_memory_buffer<> fstr = config.create_format(val); + size_t bufsize = form_memory_buffer<>::INITIAL_SIZE; + return sfmt_imp(val, fstr, bufsize); +} + + + +namespace internal +{ +template inline +void write_default(Stream& s, const Value& v) +{ + s << sfmt(v, ""); +} + + +inline void sfmts_imp(const internal::form_memory_buffer<>& b, std::string& out) +{ + using namespace internal; + + if (b.size() == 0) + return; + + out.reserve(b.size()); + out.append(b.get_first(), b.first_size()); + for (form_memory_buffer<>::slices_t::const_iterator i = b.get_slices().begin(); + i != b.get_slices().end(); ++i) + { + const char* data = &(*i)[0]; + out.append(data, i->size()); + } +} +} + +template +inline std::string sfmts(const Value& val, const char* fmtspec = 0) +{ + std::string out; + internal::sfmts_imp(sfmt(val, fmtspec), (out)); + return out; +} + +template +inline std::string sfmts(const Value& val, const sfmc& fmtspec) +{ + std::string out; + internal::sfmts_imp(sfmt(val, fmtspec), (out)); + return out; +} + + +// Semi-manipulator to add the end-of-line. +const internal::form_memory_buffer<2> seol ("\n"); + +// Another manipulator. You can add yourself others the same way. +const struct os_flush_manip {} sflush; + +inline ostdiostream& operator<<(ostdiostream& sout, const os_flush_manip&) +{ + std::fflush(sout.raw()); + return sout; +}; + + +} + +#endif diff --git a/srtcore/api.cpp b/srtcore/api.cpp index bb5dd64fe..409785a7f 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -227,10 +227,7 @@ string srt::CUDTUnited::CONID(SRTSOCKET sock) { if (sock == 0) return ""; - - std::ostringstream os; - os << "@" << sock << ":"; - return os.str(); + return fmt::ffcat("@", sock, ":"); } int srt::CUDTUnited::startup() @@ -1207,7 +1204,7 @@ int srt::CUDTUnited::connect(SRTSOCKET u, const sockaddr* srcname, const sockadd if (!srcname || !tarname || namelen < int(sizeof(sockaddr_in))) { LOGC(aclog.Error, - log << "connect(with source): invalid call: srcname=" << srcname << " tarname=" << tarname + log << "connect(with source): invalid call: srcname=" << (void*)srcname << " tarname=" << (void*)tarname << " namelen=" << namelen); throw CUDTException(MJ_NOTSUP, MN_INVAL); } @@ -1251,7 +1248,7 @@ int srt::CUDTUnited::connect(const SRTSOCKET u, const sockaddr* name, int namele { if (!name || namelen < int(sizeof(sockaddr_in))) { - LOGC(aclog.Error, log << "connect(): invalid call: name=" << name << " namelen=" << namelen); + LOGC(aclog.Error, log << "connect(): invalid call: name=" << (void*)name << " namelen=" << namelen); throw CUDTException(MJ_NOTSUP, MN_INVAL); } @@ -1402,8 +1399,8 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i { for (size_t i = 0; i < g.m_config.size(); ++i) { - HLOGC(aclog.Debug, log << "groupConnect: OPTION @" << sid << " #" << g.m_config[i].so); - error_reason = "group-derived option: #" + Sprint(g.m_config[i].so); + HLOGC(aclog.Debug, log << "groupConnect: OPTION @" << sid << " #" << int(g.m_config[i].so)); + error_reason = fmt::ffcat("group-derived option: #", int(g.m_config[i].so)); ns->core().setOpt(g.m_config[i].so, &g.m_config[i].value[0], (int)g.m_config[i].value.size()); } @@ -3325,14 +3322,14 @@ bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) CMultiplexer& m = i->second; #if ENABLE_HEAVY_LOGGING - ostringstream that_muxer; - that_muxer << "id=" << m.m_iID << " port=" << m.m_iPort - << " ip=" << (m.m_iIPversion == AF_INET ? "v4" : "v6"); + fmt::memory_buffer that_muxer; + ffwrite(that_muxer, "id=", m.m_iID, " port=", m.m_iPort + , " ip=", (m.m_iIPversion == AF_INET ? "v4" : "v6")); #endif if (m.m_iPort == port) { - HLOGC(smlog.Debug, log << "updateListenerMux: reusing muxer: " << that_muxer.str()); + HLOGC(smlog.Debug, log << "updateListenerMux: reusing muxer: " << that_muxer); if (m.m_iIPversion == s->m_PeerAddr.family()) { mux = &m; // best match @@ -3346,7 +3343,7 @@ bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) } else { - HLOGC(smlog.Debug, log << "updateListenerMux: SKIPPING muxer: " << that_muxer.str()); + HLOGC(smlog.Debug, log << "updateListenerMux: SKIPPING muxer: " << that_muxer); } } diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 0a4e1e318..e9987dcd7 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -1073,7 +1073,7 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet #endif HLOGC(krlog.Debug, - log << CONID() << "NET ERROR: packet size=" << recv_size << " msg_flags=0x" << hex << msg_flags + log << CONID() << "NET ERROR: packet size=" << recv_size << " msg_flags=0x" << fmt::ffmt(msg_flags, fmt::hex) << ", detected flags:" << flg.str()); #endif status = RST_AGAIN; diff --git a/srtcore/common.cpp b/srtcore/common.cpp index 6d747ecaa..b1bcf8e99 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -277,15 +277,14 @@ void srt::CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const soc } else { - LOGC(inlog.Error, log << "pton: IPE or net error: can't determine IPv4 carryover format: " << std::hex - << peeraddr16[0] << ":" - << peeraddr16[1] << ":" - << peeraddr16[2] << ":" - << peeraddr16[3] << ":" - << peeraddr16[4] << ":" - << peeraddr16[5] << ":" - << peeraddr16[6] << ":" - << peeraddr16[7] << std::dec); + using namespace fmt; + + memory_buffer peeraddr_form; + ffwrite(peeraddr_form, ffmt(peeraddr16[0], "04x")); + for (int i = 1; i < 8; ++i) + ffwrite(peeraddr_form, ":", ffmt(peeraddr16[i], "04x")); + + LOGC(inlog.Error, log << "pton: IPE or net error: can't determine IPv4 carryover format: " << peeraddr_form); *target_ipv4_addr = 0; if (peer.family() != AF_INET) { diff --git a/srtcore/common.h b/srtcore/common.h index 6a8912118..b20fdb37a 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -63,6 +63,10 @@ modified by // #include //#include #endif +#include + +#include "fmt/format.h" +#include "fmt/ostream.h" // use ffprint with ostringstream #include "srt.h" #include "utilities.h" @@ -1437,22 +1441,35 @@ inline bool checkMappedIPv4(const sockaddr_in6& sa) inline std::string FormatLossArray(const std::vector< std::pair >& lra) { + using namespace fmt; std::ostringstream os; - os << "[ "; + ffprint(os, "[ "); + for (std::vector< std::pair >::const_iterator i = lra.begin(); i != lra.end(); ++i) { int len = CSeqNo::seqoff(i->first, i->second); - os << "%" << i->first; + ffprint(os, "%", i->first); if (len > 1) - os << "+" << len; - os << " "; + ffprint(os, "+", len); + ffprint(os, " "); } - os << "]"; + ffprint(os, "]"); return os.str(); } +inline fmt::string_view GroupTypeStr(SRT_GROUP_TYPE gt) +{ + if (gt == SRT_GTYPE_BROADCAST) + return "broadcast"; + + if (gt== SRT_GTYPE_BACKUP) + return "backup"; + + return "undefined"; +} + } // namespace srt #endif diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index b9265c046..1237dc01b 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -595,7 +595,7 @@ class FileCC : public SrtCongestionControlBase { m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval); HLOGC(cclog.Debug, log << "FileCC: CHKTIMER, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (wndsize=" - << setprecision(6) << m_dCWndSize << " RTT=" << m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")"); + << fmt::ffmt(m_dCWndSize, ".6") << " RTT=" << m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")"); } } else diff --git a/srtcore/core.cpp b/srtcore/core.cpp index eca2b2069..557c60635 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -89,9 +89,16 @@ using namespace srt; using namespace srt::sync; using namespace srt_logging; +using fmt::ffmt; + const SRTSOCKET UDT::INVALID_SOCK = srt::CUDT::INVALID_SOCK; const int UDT::ERROR = srt::CUDT::ERROR; +static inline char fmt_onoff(bool val) { return val ? '+' : '-'; } +#if ENABLE_HEAVY_LOGGING +static inline const char* fmt_yesno(bool a) { return a ? "yes" : "no"; } +#endif + //#define SRT_CMD_HSREQ 1 /* SRT Handshake Request (sender) */ #define SRT_CMD_HSREQ_MINSZ 8 /* Minumum Compatible (1.x.x) packet size (bytes) */ #define SRT_CMD_HSREQ_SZ 12 /* Current version packet size */ @@ -412,7 +419,7 @@ void srt::CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) ScopedLock recvguard (m_RecvLock); HLOGC(aclog.Debug, - log << CONID() << "OPTION: #" << optName << " value:" << FormatBinaryString((uint8_t*)optval, optlen)); + log << CONID() << "OPTION: #" << int(optName) << " value:" << FormatBinaryString((uint8_t*)optval, optlen)); if (IsSet(oflags, SRTO_R_PREBIND) && m_bOpened) throw CUDTException(MJ_NOTSUP, MN_ISBOUND, 0); @@ -424,7 +431,7 @@ void srt::CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) const int status = m_config.set(optName, optval, optlen); if (status == -1) { - LOGC(aclog.Error, log << CONID() << "OPTION: #" << optName << " UNKNOWN"); + LOGC(aclog.Error, log << CONID() << "OPTION: #" << int(optName) << " UNKNOWN"); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } @@ -1036,7 +1043,7 @@ size_t srt::CUDT::fillSrtHandshake(uint32_t *aw_srtdata, size_t srtlen, int msgt if (srtlen < SRT_HS_E_SIZE) { LOGC(cnlog.Fatal, - log << CONID() << "IPE: fillSrtHandshake: buffer too small: " << srtlen << " (expected: " << SRT_HS_E_SIZE << ")"); + log << CONID() << "IPE: fillSrtHandshake: buffer too small: " << srtlen << " (expected: " << int(SRT_HS_E_SIZE) << ")"); return 0; } @@ -1774,8 +1781,11 @@ bool srt::CUDT::createSrtHandshake( m_RejectReason = SRT_REJ_IPE; LOGC(cnlog.Error, log << CONID() << "createSrtHandshake: IPE: need to send KM, but CryptoControl does not exist." - << " Socket state: connected=" << boolalpha << m_bConnected << ", connecting=" << m_bConnecting - << ", broken=" << m_bBroken << ", closing=" << m_bClosing << "."); + << " Socket state: " + << fmt_onoff(m_bConnected) << "connected, " + << fmt_onoff(m_bConnecting) << "connecting, " + << fmt_onoff(m_bBroken) << "broken, " + << fmt_onoff(m_bClosing) << "closing."); return false; } @@ -2103,8 +2113,9 @@ int srt::CUDT::processSrtMsg_HSREQ(const uint32_t *srtdata, size_t bytelen, uint } LOGC(cnlog.Debug, log << "HSREQ/rcv: cmd=" << SRT_CMD_HSREQ << "(HSREQ) len=" << bytelen - << hex << " vers=0x" << srtdata[SRT_HS_VERSION] << " opts=0x" << srtdata[SRT_HS_FLAGS] - << dec << " delay=" << SRT_HS_LATENCY_RCV::unwrap(srtdata[SRT_HS_LATENCY])); + << " vers=0x" << ffmt(srtdata[SRT_HS_VERSION], fmt::hex) + << " opts=0x" << ffmt(srtdata[SRT_HS_FLAGS], fmt::hex) + << " delay=" << SRT_HS_LATENCY_RCV::unwrap(srtdata[SRT_HS_LATENCY])); m_uPeerSrtVersion = srtdata[SRT_HS_VERSION]; m_uPeerSrtFlags = srtdata[SRT_HS_FLAGS]; @@ -2338,8 +2349,8 @@ int srt::CUDT::processSrtMsg_HSRSP(const uint32_t *srtdata, size_t bytelen, uint m_uPeerSrtFlags = srtdata[SRT_HS_FLAGS]; HLOGC(cnlog.Debug, log << "HSRSP/rcv: Version: " << SrtVersionString(m_uPeerSrtVersion) - << " Flags: SND:" << setw(8) << setfill('0') << hex << m_uPeerSrtFlags - << setw(0) << " (" << SrtFlagString(m_uPeerSrtFlags) << ")"); + << " Flags: SND:" << ffmt(m_uPeerSrtFlags, "08x") + << " (" << SrtFlagString(m_uPeerSrtFlags) << ")"); // Basic version check if (m_uPeerSrtVersion < m_config.uMinimumPeerSrtVersion) { @@ -2523,7 +2534,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs, m_RejectReason = SRT_REJ_ROGUE; LOGC(cnlog.Error, log << CONID() << "HS-ext HSREQ found but invalid size: " << bytelen - << " (expected: " << SRT_HS_E_SIZE << ")"); + << " (expected: " << int(SRT_HS_E_SIZE) << ")"); return false; // don't interpret } @@ -2549,7 +2560,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs, m_RejectReason = SRT_REJ_ROGUE; LOGC(cnlog.Error, log << CONID() << "HS-ext HSRSP found but invalid size: " << bytelen - << " (expected: " << SRT_HS_E_SIZE << ")"); + << " (expected: " << int(SRT_HS_E_SIZE) << ")"); return false; // don't interpret } @@ -3120,7 +3131,7 @@ bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_A { m_RejectReason = SRT_REJ_GROUP; LOGC(cnlog.Error, - log << CONID() << "HS/GROUP: incorrect group type value " << gtp << " (max is " << SRT_GTYPE_E_END << ")"); + log << CONID() << "HS/GROUP: incorrect group type value " << int(gtp) << " (max is " << int(SRT_GTYPE_E_END) << ")"); return false; } @@ -3140,8 +3151,8 @@ bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_A static const char* hs_side_name[] = {"draw", "initiator", "responder"}; HLOGC(cnlog.Debug, log << CONID() << "interpretGroup: STATE: HsSide=" << hs_side_name[m_SrtHsSide] - << " HS MSG: " << MessageTypeStr(UMSG_EXT, hsreq_type_cmd) << " $" << grpid << " type=" << gtp - << " weight=" << link_weight << " flags=0x" << std::hex << link_flags); + << " HS MSG: " << MessageTypeStr(UMSG_EXT, hsreq_type_cmd) << " $" << grpid << " type=" << GroupTypeStr(gtp) + << " weight=" << link_weight << " flags=0x" << ffmt(link_flags, fmt::hex)); #endif // XXX Here are two separate possibilities: @@ -3294,8 +3305,8 @@ SRTSOCKET srt::CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint3 if (gp->type() != gtp) { LOGC(gmlog.Error, - log << CONID() << "HS: GROUP TYPE COLLISION: peer group=$" << peergroup << " type " << gtp - << " agent group=$" << gp->id() << " type" << gp->type()); + log << CONID() << "HS: GROUP TYPE COLLISION: peer group=$" << peergroup << " type:" << GroupTypeStr(gtp) + << " agent group=$" << gp->id() << " type:" << GroupTypeStr(gp->type())); return -1; } @@ -4016,8 +4027,9 @@ void srt::CUDT::sendRendezvousRejection(const sockaddr_any& serv_addr, CPacket& m_ConnReq.store_to((r_rsppkt.m_pcData), (size)); r_rsppkt.setLength(size); - HLOGC(cnlog.Debug, log << CONID() << "sendRendezvousRejection: using code=" << m_ConnReq.m_iReqType - << " for reject reason code " << m_RejectReason << " (" << srt_rejectreason_str(m_RejectReason) << ")"); + HLOGC(cnlog.Debug, log << CONID() << "sendRendezvousRejection: using code=#" << int(m_ConnReq.m_iReqType) + << " (" << RequestTypeStr(m_ConnReq.m_iReqType) + << ") for reject reason code " << m_RejectReason << " (" << srt_rejectreason_str(m_RejectReason) << ")"); setPacketTS(r_rsppkt, steady_clock::now()); m_pSndQueue->sendto(serv_addr, r_rsppkt, m_SourceAddr); @@ -4102,8 +4114,12 @@ EConnectStatus srt::CUDT::craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatas m_RejectReason = SRT_REJ_IPE; LOGC(cnlog.Error, log << CONID() << "IPE: craftKmResponse needs to send KM, but CryptoControl does not exist." - << " Socket state: connected=" << boolalpha << m_bConnected << ", connecting=" << m_bConnecting - << ", broken=" << m_bBroken << ", opened " << m_bOpened << ", closing=" << m_bClosing << "."); + << " Socket state: " + << fmt_onoff(m_bConnected) << "connected, " + << fmt_onoff(m_bConnecting) << "connecting, " + << fmt_onoff(m_bBroken) << "broken, " + << fmt_onoff(m_bOpened) << "opened, " + << fmt_onoff(m_bClosing) << "closing."); return CONN_REJECT; } // This is a periodic handshake update, so you need to extract the KM data from the @@ -4650,8 +4666,8 @@ EConnectStatus srt::CUDT::processConnectResponse(const CPacket& response, CUDTEx if (m_ConnRes.m_iReqType == URQ_INDUCTION) { HLOGC(cnlog.Debug, - log << CONID() << "processConnectResponse: REQ-TIME LOW; got INDUCTION HS response (cookie:" << hex - << m_ConnRes.m_iCookie << " version:" << dec << m_ConnRes.m_iVersion + log << CONID() << "processConnectResponse: REQ-TIME LOW; got INDUCTION HS response (cookie:" + << ffmt(m_ConnRes.m_iCookie, fmt::hex) << " version:" << m_ConnRes.m_iVersion << "), sending CONCLUSION HS with this cookie"); m_ConnReq.m_iCookie = m_ConnRes.m_iCookie; @@ -4758,7 +4774,8 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, // in rendezvous it's completed before calling this function. if (!rendezvous) { - HLOGC(cnlog.Debug, log << CONID() << boolalpha << "postConnect: packet:" << bool(pResponse) << " rendezvous:" << rendezvous); + HLOGC(cnlog.Debug, log << CONID() << "postConnect: packet:" + << fmt_yesno(pResponse) << " rendezvous:" << fmt_yesno(rendezvous)); // The "local storage depleted" case shouldn't happen here, but // this is a theoretical path that needs prevention. bool ok = pResponse; @@ -5461,14 +5478,14 @@ void * srt::CUDT::tsbpd(void* param) HLOGC(tslog.Debug, log << self->CONID() << "tsbpd: DROPSEQ: up to seqno %" << CSeqNo::decseq(info.seqno) << " (" << iDropCnt << " packets) playable at " << FormatTime(info.tsbpd_time) << " delayed " - << (timediff_us / 1000) << "." << std::setw(3) << std::setfill('0') << (timediff_us % 1000) << " ms"); + << (timediff_us / 1000) << "." << ffmt(timediff_us % 1000, "03") << " ms"); #endif string why; if (self->frequentLogAllowed(FREQLOGFA_RCV_DROPPED, tnow, (why))) { LOGC(brlog.Warn, log << self->CONID() << "RCV-DROPPED " << iDropCnt << " packet(s). Packet seqno %" << info.seqno - << " delayed for " << (timediff_us / 1000) << "." << std::setw(3) << std::setfill('0') - << (timediff_us % 1000) << " ms " << why); + << " delayed for " << (timediff_us / 1000) << "." + << ffmt(timediff_us % 1000, "03") << " ms " << why); } #if SRT_ENABLE_FREQUENT_LOG_TRACE else @@ -5986,12 +6003,12 @@ bool srt::CUDT::frequentLogAllowed(size_t logid, const time_point& tnow, std::st const int supr = m_aSuppressedMsg[logid]; if (supr > 0) - w_why = Sprint("++SUPPRESSED: ", supr); + w_why = fmt::ffcat("++SUPPRESSED: ", supr); m_aSuppressedMsg[logid] = 0; } else { - w_why = Sprint("Too early - last one was ", FormatDuration(tnow - m_tsLogSlowDown[logid].load())); + w_why = fmt::ffcat("Too early - last one was ", FormatDuration(tnow - m_tsLogSlowDown[logid].load())); // Set YOUR OWN bit, atomically. m_LogSlowDownExpired |= uint8_t(BIT(logid)); ++m_aSuppressedMsg[logid]; @@ -7154,7 +7171,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ HLOGC(tslog.Debug, log << CONID() << "receiveMessage: fall asleep up to TS=" << FormatTime(exptime) - << " lock=" << (&m_RecvLock) << " cond=" << (&m_RecvDataCond)); + << " lock=" << ((void*)&m_RecvLock) << " cond=" << ((void*)&m_RecvDataCond)); if (!recv_cond.wait_until(exptime)) { @@ -7772,7 +7789,7 @@ bool srt::CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) HLOGC(rslog.Debug, log << CONID() << "updateCC: updated values from congctl: interval=" << FormatDuration(m_tdSendInterval) << " (cfg:" << m_CongCtl->pktSndPeriod_us() << "us) cgwindow=" - << std::setprecision(3) << cgwindow); + << ffmt(cgwindow, fmt::precision(3))); #endif } @@ -8434,7 +8451,7 @@ void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_ // included, but it also triggers for any other kind of invalid value. // This check MUST BE DONE before making any operation on this number. LOGC(inlog.Error, log << CONID() << "ACK: IPE/EPE: received invalid ACK value: " << ackdata_seqno - << " " << std::hex << ackdata_seqno << " (IGNORED)"); + << " " << ffmt(ackdata_seqno, "x") << " (IGNORED)"); return; } @@ -9166,7 +9183,7 @@ void srt::CUDT::processCtrl(const CPacket &ctrlpkt) m_tsLastRspTime = currtime; HLOGC(inlog.Debug, - log << CONID() << "incoming UMSG:" << ctrlpkt.getType() << " (" + log << CONID() << "incoming UMSG:" << int(ctrlpkt.getType()) << " (" << MessageTypeStr(ctrlpkt.getType(), ctrlpkt.getExtendedType()) << ") socket=%" << ctrlpkt.id()); switch (ctrlpkt.getType()) @@ -9306,7 +9323,7 @@ void srt::CUDT::updateAfterSrtHandshake(int hsv) { ScopedLock glock (uglobal().m_GlobControlLock); grpspec = m_parent->m_GroupOf - ? " group=$" + Sprint(m_parent->m_GroupOf->id()) + ? fmt::ffcat(" group=$", m_parent->m_GroupOf->id()) : string(); } #else @@ -9703,7 +9720,7 @@ bool srt::CUDT::packData(CPacket& w_packet, steady_clock::time_point& w_nexttime #if ENABLE_HEAVY_LOGGING // Required because of referring to MessageFlagStr() HLOGC(qslog.Debug, log << CONID() << "packData: " << reason << " packet seq=" << w_packet.seqno() << " (ACK=" << m_iSndLastAck - << " ACKDATA=" << m_iSndLastDataAck << " MSG/FLAGS: " << w_packet.MessageFlagStr() << ")"); + << " ACKDATA=" << m_iSndLastDataAck << " MSG/FLAGS: " << w_packet.FmtMessageFlag() << ")"); #endif // Fix keepalive @@ -10040,12 +10057,9 @@ int srt::CUDT::checkLazySpawnTsbPdThread() HLOGP(qrlog.Debug, "Spawning Socket TSBPD thread"); #if ENABLE_HEAVY_LOGGING - std::ostringstream tns1, tns2; // Take the last 2 ciphers from the socket ID. - tns1 << setfill('0') << setw(2) << m_SocketID; - std::string s = tns1.str(); - tns2 << "SRT:TsbPd:@" << s.substr(s.size()-2, 2); - const string thname = tns2.str(); + string s = fmt::ffmts(m_SocketID, "02"); + const string thname = fmt::ffcat("SRT:TsbPd:@", s.substr(s.size()-2, 2)); #else const string thname = "SRT:TsbPd"; #endif @@ -10123,7 +10137,7 @@ int srt::CUDT::handleSocketPacketReception(const vector& incoming, bool& HLOGC(qrlog.Debug, log << CONID() << "RECEIVED: %" << rpkt.seqno() << " bufidx=" << bufidx << " (BELATED/" << s_rexmitstat_str[pktrexmitflag] << ") with ACK %" << m_iRcvLastAck - << " FLAGS: " << rpkt.MessageFlagStr()); + << " FLAGS: " << rpkt.FmtMessageFlag()); continue; } @@ -10278,7 +10292,7 @@ int srt::CUDT::handleSocketPacketReception(const vector& incoming, bool& << " RSL=" << expectspec.str() << " SN=" << s_rexmitstat_str[pktrexmitflag] << " FLAGS: " - << rpkt.MessageFlagStr()); + << rpkt.FmtMessageFlag()); #endif // Decryption should have made the crypto flags EK_NOENC. @@ -11093,7 +11107,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) int32_t cookie_val = bake(addr); - HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: new cookie: " << hex << cookie_val); + HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: new cookie: " << ffmt(cookie_val, fmt::hex)); // Remember the incoming destination address here and use it as a source // address when responding. It's not possible to record this address yet @@ -11173,7 +11187,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) if (hs.m_iCookie != cookie_val) { m_RejectReason = SRT_REJ_RDVCOOKIE; - HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ...wrong cookie " << hex << cookie_val << ". Ignoring."); + HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ...wrong cookie " << ffmt(cookie_val, fmt::hex) << ". Ignoring."); return m_RejectReason; } @@ -11258,7 +11272,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) if (result == -1) { hs.m_iReqType = URQFailure(error); - LOGC(cnlog.Warn, log << "processConnectRequest: rsp(REJECT): " << hs.m_iReqType << " - " << srt_rejectreason_str(error)); + LOGC(cnlog.Warn, log << "processConnectRequest: rsp(REJECT): " << int(hs.m_iReqType) << " - " << srt_rejectreason_str(error)); } // The `acpu` not NULL means connection exists, the `result` should be 0. It is not checked here though. @@ -11362,7 +11376,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) } } } - LOGC(cnlog.Debug, log << CONID() << "listen ret: " << hs.m_iReqType << " - " << RequestTypeStr(hs.m_iReqType)); + LOGC(cnlog.Debug, log << CONID() << "listen ret: " << int(hs.m_iReqType) << " - " << RequestTypeStr(hs.m_iReqType)); return RejectReasonForURQ(hs.m_iReqType); } diff --git a/srtcore/fec.cpp b/srtcore/fec.cpp index fd762b88b..3ac286b19 100644 --- a/srtcore/fec.cpp +++ b/srtcore/fec.cpp @@ -533,13 +533,14 @@ void FECFilterBuiltin::ClipPacket(Group& g, const CPacket& pkt) ClipData(g, length_net, kflg, timestamp_hw, pkt.data(), pkt.size()); - HLOGC(pflog.Debug, log << "FEC DATA PKT CLIP: " << hex - << "FLAGS=" << unsigned(kflg) << " LENGTH[ne]=" << (length_net) - << " TS[he]=" << timestamp_hw - << " CLIP STATE: FLAGS=" << unsigned(g.flag_clip) - << " LENGTH[ne]=" << g.length_clip - << " TS[he]=" << g.timestamp_clip - << " PL4=" << (*(uint32_t*)&g.payload_clip[0])); + HLOGC(pflog.Debug, log << "FEC DATA PKT CLIP: " + << "FLAGS=" << fmt::ffmt(kflg, fmt::hex) + << " LENGTH[ne]=" << fmt::ffmt(length_net, fmt::hex) + << " TS[he]=" << fmt::ffmt(timestamp_hw, fmt::hex) + << " CLIP STATE: FLAGS=" << fmt::ffmt(g.flag_clip, fmt::hex) + << " LENGTH[ne]=" << fmt::ffmt(g.length_clip, fmt::hex) + << " TS[he]=" << fmt::ffmt(g.timestamp_clip, fmt::hex) + << " PL4=" << fmt::ffmt(*(uint32_t*)&g.payload_clip[0], fmt::hex)); } // Clipping a control packet does merely the same, just the packet has @@ -560,13 +561,14 @@ void FECFilterBuiltin::ClipControlPacket(Group& g, const CPacket& pkt) ClipData(g, *length_clip, *flag_clip, timestamp_hw, payload, payload_clip_len); - HLOGC(pflog.Debug, log << "FEC/CTL CLIP: " << hex - << "FLAGS=" << unsigned(*flag_clip) << " LENGTH[ne]=" << (*length_clip) - << " TS[he]=" << timestamp_hw - << " CLIP STATE: FLAGS=" << unsigned(g.flag_clip) - << " LENGTH[ne]=" << g.length_clip - << " TS[he]=" << g.timestamp_clip - << " PL4=" << (*(uint32_t*)&g.payload_clip[0])); + HLOGC(pflog.Debug, log << "FEC/CTL CLIP: " + << "FLAGS=" << fmt::ffmt(*flag_clip, fmt::hex) + << " LENGTH[ne]=" << fmt::ffmt(*length_clip, fmt::hex) + << " TS[he]=" << fmt::ffmt(timestamp_hw, fmt::hex) + << " CLIP STATE: FLAGS=" << fmt::ffmt(g.flag_clip, fmt::hex) + << " LENGTH[ne]=" << fmt::ffmt(g.length_clip, fmt::hex) + << " TS[he]=" << fmt::ffmt(g.timestamp_clip, fmt::hex) + << " PL4=" << fmt::ffmt(*(uint32_t*)&g.payload_clip[0], fmt::hex)); } void FECFilterBuiltin::ClipRebuiltPacket(Group& g, Receive::PrivPacket& pkt) @@ -582,13 +584,14 @@ void FECFilterBuiltin::ClipRebuiltPacket(Group& g, Receive::PrivPacket& pkt) ClipData(g, length_net, kflg, timestamp_hw, pkt.buffer, pkt.length); - HLOGC(pflog.Debug, log << "FEC REBUILT DATA CLIP: " << hex - << "FLAGS=" << unsigned(kflg) << " LENGTH[ne]=" << (length_net) - << " TS[he]=" << timestamp_hw - << " CLIP STATE: FLAGS=" << unsigned(g.flag_clip) - << " LENGTH[ne]=" << g.length_clip - << " TS[he]=" << g.timestamp_clip - << " PL4=" << (*(uint32_t*)&g.payload_clip[0])); + HLOGC(pflog.Debug, log << "FEC REBUILT DATA CLIP: " + << "FLAGS=" << fmt::ffmt(kflg, fmt::hex) + << " LENGTH[ne]=" << fmt::ffmt(length_net, fmt::hex) + << " TS[he]=" << fmt::ffmt(timestamp_hw, fmt::hex) + << " CLIP STATE: FLAGS=" << fmt::ffmt(g.flag_clip, fmt::hex) + << " LENGTH[ne]=" << fmt::ffmt(g.length_clip, fmt::hex) + << " TS[he]=" << fmt::ffmt(g.timestamp_clip, fmt::hex) + << " PL4=" << fmt::ffmt(*(uint32_t*)&g.payload_clip[0], fmt::hex)); } void FECFilterBuiltin::ClipData(Group& g, uint16_t length_net, uint8_t kflg, @@ -765,11 +768,11 @@ void FECFilterBuiltin::PackControl(const Group& g, signed char index, SrtPacket& HLOGC(pflog.Debug, log << "FEC: PackControl: hdr(" << (total_size - g.payload_clip.size()) << "): INDEX=" - << int(index) << " LENGTH[ne]=" << hex << g.length_clip - << " FLAGS=" << int(g.flag_clip) << " TS=" << g.timestamp_clip - << " PL(" << dec << g.payload_clip.size() << ")[0-4]=" << hex - << (*(uint32_t*)&g.payload_clip[0])); - + << int(index) << " LENGTH[ne]=" << fmt::ffmt(g.length_clip, fmt::hex) + << " FLAGS=" << fmt::ffmt(g.flag_clip, fmt::hex) + << " TS=" << fmt::ffmt(g.timestamp_clip, fmt::hex) + << " PL(" << g.payload_clip.size() << ")[0-4]=" + << fmt::ffmt(*(uint32_t*)&g.payload_clip[0], fmt::hex)); } bool FECFilterBuiltin::receive(const CPacket& rpkt, loss_seqs_t& loss_seqs) @@ -1463,8 +1466,8 @@ void FECFilterBuiltin::RcvRebuild(Group& g, int32_t seqno, Group::Type tp) HLOGC(pflog.Debug, log << "FEC: REBUILT: %" << seqno << " msgno=" << MSGNO_SEQ::unwrap(p.hdr[SRT_PH_MSGNO]) - << " flags=" << PacketMessageFlagStr(p.hdr[SRT_PH_MSGNO]) - << " TS=" << p.hdr[SRT_PH_TIMESTAMP] << " ID=" << dec << p.hdr[SRT_PH_ID] + << " flags=" << FmtPacketMessageFlag(p.hdr[SRT_PH_MSGNO]) + << " TS=" << p.hdr[SRT_PH_TIMESTAMP] << " ID=" << p.hdr[SRT_PH_ID] << " size=" << length_hw << " !" << BufferStamp(p.buffer, p.length)); diff --git a/srtcore/group.cpp b/srtcore/group.cpp index 5601cdeee..318f56adc 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -15,6 +15,8 @@ extern const int32_t SRT_DEF_VERSION; namespace srt { +static inline char fmt_onoff(bool val) { return val ? '+' : '-'; } + int32_t CUDTGroup::s_tokenGen = 0; // [[using locked(this->m_GroupLock)]]; @@ -342,7 +344,7 @@ void CUDTGroup::GroupContainer::erase(CUDTGroup::gli_t it) void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) { HLOGC(gmlog.Debug, - log << "GROUP $" << id() << " OPTION: #" << optName + log << "GROUP $" << id() << " OPTION: #" << int(optName) << " value:" << FormatBinaryString((uint8_t*)optval, optlen)); switch (optName) @@ -1096,7 +1098,7 @@ int CUDTGroup::send(const char* buf, int len, SRT_MSGCTRL& w_mc) switch (m_type) { default: - LOGC(gslog.Error, log << "CUDTGroup::send: not implemented for type #" << m_type); + LOGC(gslog.Error, log << "CUDTGroup::send: not implemented for type #" << (int)m_type); throw CUDTException(MJ_SETUP, MN_INVAL, 0); case SRT_GTYPE_BROADCAST: @@ -2279,8 +2281,8 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) if (!m_bOpened || !m_bConnected) { LOGC(grlog.Error, - log << boolalpha << "grp/recv: $" << id() << ": ABANDONING: opened=" << m_bOpened - << " connected=" << m_bConnected); + log << "grp/recv: $" << id() << ": ABANDONING: opened" << fmt_onoff(m_bOpened) + << " connected" << fmt_onoff(m_bConnected)); throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); } diff --git a/srtcore/logging.cpp b/srtcore/logging.cpp index d0ba3fd4a..eb6b9bb67 100644 --- a/srtcore/logging.cpp +++ b/srtcore/logging.cpp @@ -17,8 +17,9 @@ written by #include "srt_compat.h" #include "logging.h" -using namespace std; +using namespace std; +using namespace fmt; namespace srt_logging { @@ -43,7 +44,7 @@ LogDispatcher::Proxy LogDispatcher::operator()() return Proxy(*this); } -void LogDispatcher::CreateLogLinePrefix(std::ostringstream& serr) +void LogDispatcher::CreateLogLinePrefix(fmt::memory_buffer& serr) { using namespace std; using namespace srt; @@ -60,7 +61,7 @@ void LogDispatcher::CreateLogLinePrefix(std::ostringstream& serr) if (strftime(tmp_buf, sizeof(tmp_buf), "%X.", &tm)) { - serr << tmp_buf << setw(6) << setfill('0') << tv.tv_usec; + ffwrite(serr, tmp_buf, ffmt(tv.tv_usec, fillzero, width(6))); } } @@ -73,11 +74,11 @@ void LogDispatcher::CreateLogLinePrefix(std::ostringstream& serr) // Note: ThreadName::get needs a buffer of size min. ThreadName::BUFSIZE if ( !isset(SRT_LOGF_DISABLE_THREADNAME) && ThreadName::get(tmp_buf) ) { - serr << "/" << tmp_buf << out_prefix << ": "; + ffwrite(serr, "/", tmp_buf, out_prefix, ": "); } else { - serr << out_prefix << ": "; + ffwrite(serr, out_prefix, ": "); } } diff --git a/srtcore/logging.h b/srtcore/logging.h index 3f4efb286..57082235e 100644 --- a/srtcore/logging.h +++ b/srtcore/logging.h @@ -20,7 +20,6 @@ written by #include #include #include -#include #include #ifdef _WIN32 #include "win/wintime.h" @@ -34,6 +33,7 @@ written by #include "threadname.h" #include "logging_api.h" #include "sync.h" +#include "fmt/format.h" #ifdef __GNUC__ #define PRINTF_LIKE __attribute__((format(printf,2,3))) @@ -192,7 +192,7 @@ struct SRT_API LogDispatcher bool CheckEnabled(); - void CreateLogLinePrefix(std::ostringstream&); + void CreateLogLinePrefix(fmt::memory_buffer&); void SendLogLine(const char* file, int line, const std::string& area, const std::string& sl); // log.Debug("This is the ", nth, " time"); <--- C++11 only. @@ -284,8 +284,7 @@ struct SRT_API LogDispatcher struct LogDispatcher::Proxy { LogDispatcher& that; - - std::ostringstream os; + fmt::memory_buffer os; // Cache the 'enabled' state in the beginning. If the logging // becomes enabled or disabled in the middle of the log, we don't @@ -331,18 +330,55 @@ struct LogDispatcher::Proxy { if ( that_enabled ) { - os << arg; + fmt::ffwrite(os, arg); + } + return *this; + } + + // Special case for atomics, as passing them to snprintf() call + // requires unpacking the real underlying value. + template + Proxy& operator<<(const srt::sync::atomic& arg) + { + if (that_enabled) + { + fmt::ffwrite(os, arg.load()); } return *this; } + +#if HAVE_CXX11 + + void dispatch() {} + + template + void dispatch(const Arg1& a1, const Args&... others) + { + *this << a1; + dispatch(others...); + } + + // Special dispatching for atomics must be provided here. + // By some reason, "*this << a1" expression gets dispatched + // to the general version of operator<<, not the overload for + // atomic. Even though the compiler shows Arg1 type as atomic. + template + void dispatch(const srt::sync::atomic& a1, const Args&... others) + { + *this << a1.load(); + dispatch(others...); + } + +#endif + ~Proxy() { - if ( that_enabled ) + if (that_enabled) { - if ( (flags & SRT_LOGF_DISABLE_EOL) == 0 ) - os << std::endl; - that.SendLogLine(i_file, i_line, area, os.str()); + if ((flags & SRT_LOGF_DISABLE_EOL) == 0) + fmt::ffwrite(os, "\n"); + that.SendLogLine(i_file, i_line, area, fmt::ffcat(os)); } // Needed in destructor? //os.clear(); @@ -381,7 +417,7 @@ struct LogDispatcher::Proxy buf[len-1] = '\0'; } - os << buf; + fmt::ffwrite(os, buf); return *this; } }; @@ -437,12 +473,20 @@ inline bool LogDispatcher::CheckEnabled() //extern std::mutex Debug_mutex; -inline void PrintArgs(std::ostream&) {} +inline void PrintArgs(fmt::memory_buffer&) {} template -inline void PrintArgs(std::ostream& serr, Arg1&& arg1, Args&&... args) +inline void PrintArgs(fmt::memory_buffer& serr, Arg1&& arg1, Args&&... args) { - serr << std::forward(arg1); + fmt::ffwrite(serr, std::forward(arg1)); + PrintArgs(serr, args...); +} + +// Add exceptional handling for sync::atomic +template +inline void PrintArgs(fmt::memory_buffer& serr, const srt::sync::atomic& arg1, Args&&... args) +{ + fmt::ffwrite(serr, arg1.load()); PrintArgs(serr, args...); } @@ -450,15 +494,7 @@ template inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, Args&&... args SRT_ATR_UNUSED) { #ifdef ENABLE_LOGGING - std::ostringstream serr; - CreateLogLinePrefix(serr); - PrintArgs(serr, args...); - - if ( !isset(SRT_LOGF_DISABLE_EOL) ) - serr << std::endl; - - // Not sure, but it wasn't ever used. - SendLogLine(file, line, area, serr.str()); + Proxy(*this).dispatch(args...); #endif } @@ -468,15 +504,7 @@ template inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, const Arg& arg SRT_ATR_UNUSED) { #ifdef ENABLE_LOGGING - std::ostringstream serr; - CreateLogLinePrefix(serr); - serr << arg; - - if ( !isset(SRT_LOGF_DISABLE_EOL) ) - serr << std::endl; - - // Not sure, but it wasn't ever used. - SendLogLine(file, line, area, serr.str()); + Proxy(*this) << arg; #endif } diff --git a/srtcore/packet.cpp b/srtcore/packet.cpp index 180623039..3ff849b67 100644 --- a/srtcore/packet.cpp +++ b/srtcore/packet.cpp @@ -557,59 +557,59 @@ CPacket* CPacket::clone() const } // Useful for debugging -std::string PacketMessageFlagStr(uint32_t msgno_field) +fmt::memory_buffer FmtPacketMessageFlag(uint32_t msgno_field) { - using namespace std; + using namespace fmt; - stringstream out; + memory_buffer out; static const char* const boundary[] = {"PB_SUBSEQUENT", "PB_LAST", "PB_FIRST", "PB_SOLO"}; static const char* const order[] = {"ORD_RELAXED", "ORD_REQUIRED"}; static const char* const crypto[] = {"EK_NOENC", "EK_EVEN", "EK_ODD", "EK*ERROR"}; static const char* const rexmit[] = {"SN_ORIGINAL", "SN_REXMIT"}; - out << boundary[MSGNO_PACKET_BOUNDARY::unwrap(msgno_field)] << " "; - out << order[MSGNO_PACKET_INORDER::unwrap(msgno_field)] << " "; - out << crypto[MSGNO_ENCKEYSPEC::unwrap(msgno_field)] << " "; - out << rexmit[MSGNO_REXMIT::unwrap(msgno_field)]; + ffwrite(out, boundary[MSGNO_PACKET_BOUNDARY::unwrap(msgno_field)], " ", + order[MSGNO_PACKET_INORDER::unwrap(msgno_field)], " ", + crypto[MSGNO_ENCKEYSPEC::unwrap(msgno_field)], " ", + rexmit[MSGNO_REXMIT::unwrap(msgno_field)]); - return out.str(); + return out; } -inline void SprintSpecialWord(std::ostream& os, int32_t val) +inline void SprintSpecialWord(fmt::memory_buffer& os, int32_t val) { if (val & LOSSDATA_SEQNO_RANGE_FIRST) - os << "<" << (val & (~LOSSDATA_SEQNO_RANGE_FIRST)) << ">"; + ffwrite(os, "<", (val & (~LOSSDATA_SEQNO_RANGE_FIRST)), ">"); else - os << val; + ffwrite(os, val); } #if ENABLE_LOGGING -std::string CPacket::Info() +fmt::memory_buffer CPacket::Info() { - std::ostringstream os; - os << "TARGET=@" << id() << " "; + using namespace fmt; + + memory_buffer os; + ffwrite(os, "TARGET=@", id(), " "); if (isControl()) { - os << "CONTROL: size=" << getLength() << " type=" << MessageTypeStr(getType(), getExtendedType()); + ffwrite(os, "CONTROL: size=", getLength(), " type=", MessageTypeStr(getType(), getExtendedType())); if (getType() == UMSG_HANDSHAKE) { - os << " HS: "; + ffwrite(os, " HS: "); // For handshake we already have a parsing method CHandShake hs; hs.load_from(m_pcData, getLength()); - os << hs.show(); + ffwrite(os, hs.show()); } else { // This is a value that some messages use for some purposes. // The "ack seq no" is one of the purposes, used by UMSG_ACK and UMSG_ACKACK. // This is simply the SRT_PH_MSGNO field used as a message number in data packets. - os << " ARG: 0x"; - os << std::hex << getAckSeqNo() << " "; - os << std::dec << getAckSeqNo(); + ffwrite(os, " ARG: 0x", ffmt(getAckSeqNo(), hex), " ", getAckSeqNo()); // It would be nice to see the extended packet data, but this // requires strictly a message-dependent interpreter. So let's simply @@ -618,13 +618,13 @@ std::string CPacket::Info() // - sign flag will be cleared before displaying, with additional mark size_t wordlen = getLength() / 4; // drop any remainder if present int32_t* array = (int32_t*)m_pcData; - os << " [ "; + ffwrite(os, " [ "); for (size_t i = 0; i < wordlen; ++i) { SprintSpecialWord(os, array[i]); - os << " "; + ffwrite(os, " "); } - os << "]"; + ffwrite(os, "]"); } } else @@ -633,11 +633,11 @@ std::string CPacket::Info() // This is only a log, nothing crucial, so we can risk displaying incorrect message number. // Declaring that the peer supports rexmit flag cuts off the highest bit from // the displayed number. - os << "DATA: size=" << getLength() << " " << BufferStamp(m_pcData, getLength()) << " #" << getMsgSeq(true) - << " %" << getSeqNo() << " " << MessageFlagStr(); + ffwrite(os, "DATA: size=", getLength(), " ", BufferStamp(m_pcData, getLength()), " #", getMsgSeq(true), + " %", getSeqNo(), " ", FmtMessageFlag()); } - return os.str(); + return os; } #endif diff --git a/srtcore/packet.h b/srtcore/packet.h index 5a6d6eb15..63618854e 100644 --- a/srtcore/packet.h +++ b/srtcore/packet.h @@ -215,7 +215,7 @@ inline EncryptionKeySpec GetEncryptionKeySpec(int32_t msgno) const int32_t PUMASK_SEQNO_PROBE = 0xF; -std::string PacketMessageFlagStr(uint32_t msgno_field); +fmt::memory_buffer FmtPacketMessageFlag(uint32_t msgno_field); class CPacket { @@ -391,11 +391,11 @@ class CPacket uint32_t header(SrtPktHeaderFields field) const { return m_nHeader[field]; } #if ENABLE_LOGGING - std::string MessageFlagStr() { return PacketMessageFlagStr(m_nHeader[SRT_PH_MSGNO]); } - std::string Info(); + fmt::memory_buffer FmtMessageFlag() { return FmtPacketMessageFlag(m_nHeader[SRT_PH_MSGNO]); } + fmt::memory_buffer Info(); #else - std::string MessageFlagStr() { return std::string(); } - std::string Info() { return std::string(); } + fmt::memory_buffer FmtMessageFlag() { return fmt::memory_buffer(); } + fmt::memory_buffer Info() { return fmt::memory_buffer(); } #endif }; diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 6cb4faeb1..64b2d0241 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -455,7 +455,7 @@ void srt::CSndQueue::init(CChannel* c, CTimer* t) #if ENABLE_LOGGING ++m_counter; - const std::string thrname = "SRT:SndQ:w" + Sprint(m_counter); + const std::string thrname = fmt::ffcat("SRT:SndQ:w", m_counter.load()); const char* thname = thrname.c_str(); #else const char* thname = "SRT:SndQ"; @@ -1106,8 +1106,8 @@ bool srt::CRendezvousQueue::qualifyToHandle(EReadStatus rst, else { HLOGC(cnlog.Debug, - log << "RID: socket @" << i->m_iID << " still active (remaining " << std::fixed - << (count_microseconds(i->m_tsTTL - tsNow) / 1000000.0) << "s of TTL)..."); + log << "RID: socket @" << i->m_iID << " still active (remaining " + << fmt::ffmt(count_microseconds(i->m_tsTTL - tsNow) / 1000000.0, "f") << "s of TTL)..."); } const steady_clock::time_point tsLastReq = i->m_pUDT->m_tsLastReqTime; @@ -1217,7 +1217,7 @@ void srt::CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CCh #if ENABLE_LOGGING const int cnt = ++m_counter; - const std::string thrname = "SRT:RcvQ:w" + Sprint(cnt); + const std::string thrname = fmt::ffcat("SRT:RcvQ:w", cnt); #else const std::string thrname = "SRT:RcvQ:w"; #endif diff --git a/srtcore/queue.h b/srtcore/queue.h index 132b670b3..48bedd9af 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -591,6 +591,10 @@ struct CMultiplexer , m_pRcvQueue(NULL) , m_pChannel(NULL) , m_pTimer(NULL) + , m_iPort(0) + , m_iIPversion(0) + , m_iRefCount(1) + , m_iID(-1) { } diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index 1c067d059..0dc18580d 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -735,8 +735,8 @@ struct CSrtConfigSetter { co.uKmPreAnnouncePkt = (km_refresh - 1) / 2; LOGC(aclog.Warn, - log << "SRTO_KMREFRESHRATE=0x" << std::hex << km_refresh << ": setting SRTO_KMPREANNOUNCE=0x" - << std::hex << co.uKmPreAnnouncePkt); + log << "SRTO_KMREFRESHRATE=0x" << fmt::ffmt(km_refresh, "x") << ": setting SRTO_KMPREANNOUNCE=0x" + << fmt::ffmt(co.uKmPreAnnouncePkt, "x")); } } }; @@ -761,7 +761,8 @@ struct CSrtConfigSetter if (km_preanno > (kmref - 1) / 2) { LOGC(aclog.Error, - log << "SRTO_KMPREANNOUNCE=0x" << std::hex << km_preanno << " exceeds KmRefresh/2, 0x" << ((kmref - 1) / 2) + log << "SRTO_KMPREANNOUNCE=0x" << fmt::ffmt(km_preanno, "x") + << " exceeds KmRefresh/2, 0x" << fmt::ffmt((kmref - 1) / 2, "x") << " - OPTION REJECTED."); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index bfe153657..7a8e6ae2f 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "fmt/format.h" #include "sync.h" #include "srt.h" #include "srt_compat.h" @@ -31,6 +32,8 @@ namespace srt_logging using namespace srt_logging; using namespace std; +using fmt::ffmt; + namespace srt { namespace sync @@ -38,6 +41,7 @@ namespace sync std::string FormatTime(const steady_clock::time_point& timestamp) { + using namespace fmt; if (is_zero(timestamp)) { // Use special string for 0 @@ -50,18 +54,23 @@ std::string FormatTime(const steady_clock::time_point& timestamp) const uint64_t hours = total_sec / (60 * 60) - days * 24; const uint64_t minutes = total_sec / 60 - (days * 24 * 60) - hours * 60; const uint64_t seconds = total_sec - (days * 24 * 60 * 60) - hours * 60 * 60 - minutes * 60; - ostringstream out; + steady_clock::time_point frac = timestamp - seconds_from(total_sec); + memory_buffer out; if (days) - out << days << "D "; - out << setfill('0') << setw(2) << hours << ":" - << setfill('0') << setw(2) << minutes << ":" - << setfill('0') << setw(2) << seconds << "." - << setfill('0') << setw(decimals) << (timestamp - seconds_from(total_sec)).time_since_epoch().count() << " [STDY]"; - return out.str(); + ffwrite(out, days, "D "); + + ffwrite(out, ffmt(hours, fillzero, width(2)), ":", + ffmt(minutes, fillzero, width(2)), ":", + ffmt(seconds, fillzero, width(2)), ".", + ffmt(frac.time_since_epoch().count(), + fmt::fillzero, fmt::width(decimals)), + " [STDY]"); + return fmt::ffcat(out); } std::string FormatTimeSys(const steady_clock::time_point& timestamp) { + using namespace fmt; const time_t now_s = ::time(NULL); // get current time in seconds const steady_clock::time_point now_timestamp = steady_clock::now(); const int64_t delta_us = count_microseconds(timestamp - now_timestamp); @@ -72,9 +81,9 @@ std::string FormatTimeSys(const steady_clock::time_point& timestamp) char tmp_buf[512]; strftime(tmp_buf, 512, "%X.", &tm); - ostringstream out; - out << tmp_buf << setfill('0') << setw(6) << (count_microseconds(timestamp.time_since_epoch()) % 1000000) << " [SYST]"; - return out.str(); + return ffcat(tmp_buf, + ffmt(count_microseconds(timestamp.time_since_epoch()) % 1000000, fillzero, width(6)), + " [SYST]"); } diff --git a/srtcore/sync.h b/srtcore/sync.h index 9d282304c..3ac157a5f 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -56,7 +56,6 @@ #include "utilities.h" #include "srt_attr_defs.h" - namespace srt { @@ -895,7 +894,11 @@ struct DurationUnitName template inline std::string FormatDuration(const steady_clock::duration& dur) { - return Sprint(std::fixed, DurationUnitName::count(dur)) + DurationUnitName::name(); + using namespace fmt; + + // Required fmt::fixed because it conflicts with std::fixed by unknown reason + // (namespace std isn't explicitly imported anywhere???) + return ffcat(ffmt(DurationUnitName::count(dur), fmt::fixed), DurationUnitName::name()); } inline std::string FormatDuration(const steady_clock::duration& dur) diff --git a/srtcore/utilities.h b/srtcore/utilities.h index 1786cf0ae..a4d1aa2fd 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -34,7 +34,6 @@ written by #include #include #include -#include #include #if HAVE_CXX11 @@ -46,6 +45,8 @@ written by #include #include +#include "fmt/format.h" + // -------------- UTILITIES ------------------------ // --- ENDIAN --- @@ -484,9 +485,7 @@ class FixedArray void throw_invalid_index(int i) const { - std::stringstream ss; - ss << "Index " << i << "out of range"; - throw std::runtime_error(ss.str()); + throw std::runtime_error(fmt::ffcat("Index ", i, "out of range")); } private: @@ -530,8 +529,8 @@ struct explicit_t // but this function has a different definition for C++11 and C++03. namespace srt_pair_op { - template - std::ostream& operator<<(std::ostream& s, const std::pair& v) + template + Stream& operator<<(Stream& s, const std::pair& v) { s << "{" << v.first << " " << v.second << "}"; return s; @@ -571,53 +570,12 @@ namespace any_op template inline auto Move(In& i) -> decltype(std::move(i)) { return std::move(i); } -// Gluing string of any type, wrapper for operator << - -template -inline Stream& Print(Stream& in) { return in;} - -template -inline Stream& Print(Stream& sout, Arg1&& arg1, Args&&... args) -{ - sout << std::forward(arg1); - return Print(sout, args...); -} - -template -inline std::string Sprint(Args&&... args) -{ - std::ostringstream sout; - Print(sout, args...); - return sout.str(); -} - // We need to use UniquePtr, in the form of C++03 it will be a #define. // Naturally will be used std::move() so that it can later painlessly // switch to C++11. template using UniquePtr = std::unique_ptr; -template inline -std::string Printable(const Container& in, Value /*pseudoargument*/, Args&&... args) -{ - using namespace srt_pair_op; - std::ostringstream os; - Print(os, args...); - os << "[ "; - for (auto i: in) - os << Value(i) << " "; - os << "]"; - return os.str(); -} - -template inline -std::string Printable(const Container& in) -{ - using namespace srt_pair_op; - using Value = typename Container::value_type; - return Printable(in, Value()); -} - template auto map_get(Map& m, const Key& key, typename Map::mapped_type def = typename Map::mapped_type()) -> typename Map::mapped_type { @@ -689,38 +647,6 @@ class UniquePtr: public std::auto_ptr operator bool () const { return 0!= get(); } }; -// A primitive one-argument versions of Sprint and Printable -template -inline std::string Sprint(const Arg1& arg) -{ - std::ostringstream sout; - sout << arg; - return sout.str(); -} - -// Ok, let it be 2-arg, in case when a manipulator is needed -template -inline std::string Sprint(const Arg1& arg1, const Arg2& arg2) -{ - std::ostringstream sout; - sout << arg1 << arg2; - return sout.str(); -} - -template inline -std::string Printable(const Container& in) -{ - using namespace srt_pair_op; - typedef typename Container::value_type Value; - std::ostringstream os; - os << "[ "; - for (typename Container::const_iterator i = in.begin(); i != in.end(); ++i) - os << Value(*i) << " "; - os << "]"; - - return os.str(); -} - template typename Map::mapped_type map_get(Map& m, const Key& key, typename Map::mapped_type def = typename Map::mapped_type()) { @@ -751,19 +677,57 @@ typename Map::mapped_type const* map_getp(const Map& m, const Key& key) #endif +template inline +std::string Printable(const Container& in, Value /*pseudoargument*/, const char* fmt = "") +{ + using namespace fmt; + memory_buffer os; + ffwrite(os, "[ "); + typedef typename Container::const_iterator it_t; + for (it_t i = in.begin(); i != in.end(); ++i) + ffwrite(os,ffmt(*i, fmt), " "); + ffwrite(os, "]"); + return ffcat(os); +} + +// Separate version for pairs, used for std::map +template inline +std::string Printable(const Container& in, std::pair/*pseudoargument*/, const char* fmtk = "", const char* fmtv = "") +{ + using namespace srt_pair_op; + using namespace fmt; + memory_buffer os; + ffwrite(os, "[ "); + typedef typename Container::const_iterator it_t; + for (it_t i = in.begin(); i != in.end(); ++i) + ffwrite(os, ffmt(i->first, fmtk), ":", ffmt(i->second, fmtv), " "); + ffwrite(os, "]"); + return ffcat(os); +} + + +template inline +std::string Printable(const Container& in) +{ + using namespace srt_pair_op; + typedef typename Container::value_type Value; + return Printable(in, Value()); +} + // Printable with prefix added for every element. // Useful when printing a container of sockets or sequence numbers. template inline std::string PrintableMod(const Container& in, const std::string& prefix) { using namespace srt_pair_op; + using namespace fmt; typedef typename Container::value_type Value; - std::ostringstream os; - os << "[ "; + fmt::memory_buffer os; + ffwrite(os, "[ "); for (typename Container::const_iterator y = in.begin(); y != in.end(); ++y) - os << prefix << Value(*y) << " "; - os << "]"; - return os.str(); + ffwrite(os, prefix, Value(*y), " "); + ffwrite(os, "]"); + return ffcat(os); } template @@ -978,36 +942,17 @@ inline void AccumulatePassFilterParallel(const int* p, size_t size, PassFilter(bytes[i], fillzero, width(2), uhex)); } - return os.str(); + return ffcat(os); } @@ -1171,10 +1116,7 @@ inline std::string BufferStamp(const char* mem, size_t size) } // Convert to hex string - ostringstream os; - os << hex << uppercase << setfill('0') << setw(8) << sum; - - return os.str(); + return fmt::ffmts(sum, fmt::uhex, fmt::fillzero, fmt::width(8)); } template diff --git a/submodules/fmt b/submodules/fmt new file mode 160000 index 000000000..e779a68aa --- /dev/null +++ b/submodules/fmt @@ -0,0 +1 @@ +Subproject commit e779a68aabcd097ac7aa2ee9fe36acb15aa80046 diff --git a/testing/srt-test-file.cpp b/testing/srt-test-file.cpp index 3dd8fe998..c3ea2da4b 100644 --- a/testing/srt-test-file.cpp +++ b/testing/srt-test-file.cpp @@ -260,7 +260,7 @@ bool DoUpload(UriParser& ut, string path, string filename) while (n > 0) { int st = srt_send(ss, buf.data()+shift, int(n)); - Verb() << "Upload: " << n << " --> " << st << (!shift ? string() : "+" + Sprint(shift)); + Verb() << "Upload: " << n << " --> " << st << (!shift ? string() : fmt::ffcat("+", shift)); if (st == SRT_ERROR) { cerr << "Upload: SRT error: " << srt_getlasterror_str() << endl; diff --git a/testing/srt-test-live.cpp b/testing/srt-test-live.cpp index 1811220c8..12478e461 100644 --- a/testing/srt-test-live.cpp +++ b/testing/srt-test-live.cpp @@ -301,7 +301,7 @@ extern "C" int SrtCheckGroupHook(void* , SRTSOCKET acpsock, int , const sockaddr size = sizeof gt; if (-1 != srt_getsockflag(acpsock, SRTO_GROUPTYPE, >, &size)) { - if (gt < Size(gtypes)) + if (size_t(gt) < Size(gtypes)) Verb(" type=", gtypes[gt], VerbNoEOL); else Verb(" type=", int(gt), VerbNoEOL); diff --git a/testing/testactivemedia.cpp b/testing/testactivemedia.cpp index 96344f0b2..6ca2bffa9 100644 --- a/testing/testactivemedia.cpp +++ b/testing/testactivemedia.cpp @@ -3,6 +3,11 @@ using namespace std; +#if ENABLE_LOGGING +namespace { +const char* fmt_yesno(bool b) { return b ? "yes" : "no"; } +} +#endif void SourceMedium::Runner() { @@ -17,7 +22,8 @@ void SourceMedium::Runner() Verb() << VerbLock << "Exiting SourceMedium: " << this; return; } - LOGP(applog.Debug, "SourceMedium(", typeid(*med).name(), "): [", input.payload.size(), "] MEDIUM -> BUFFER. signal(", &ready, ")"); + LOGP(applog.Debug, "SourceMedium(", typeid(*med).name(), "): [", input.payload.size(), + "] MEDIUM -> BUFFER. signal(", (void*)&ready, ")"); lock_guard g(buffer_lock); buffer.push_back(input); @@ -84,7 +90,7 @@ void TargetMedium::Runner() bool gotsomething = ready.wait_for(lg, chrono::seconds(1), [this] { return !running || !buffer.empty(); } ); LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): [", val.payload.size(), "] BUFFER update (timeout:", - boolalpha, gotsomething, " running: ", running, ")"); + fmt_yesno(!gotsomething), " running: ", running, ")"); if (::transmit_int_state || !running || !med || med->Broken()) { LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): buffer empty, medium ", @@ -120,4 +126,20 @@ void TargetMedium::Runner() } } +bool TargetMedium::Schedule(const MediaPacket& data) +{ + LOGP(applog.Debug, "TargetMedium::Schedule LOCK ... "); + std::lock_guard lg(buffer_lock); + LOGP(applog.Debug, "TargetMedium::Schedule LOCKED - checking: running=", running, " interrupt=", ::transmit_int_state); + if (!running || ::transmit_int_state) + { + LOGP(applog.Debug, "TargetMedium::Schedule: not running, discarding packet"); + return false; + } + + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): Schedule: [", data.payload.size(), "] CLIENT -> BUFFER"); + buffer.push_back(data); + ready.notify_one(); + return true; +} diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp index 011dcbfe7..e92abbe0c 100644 --- a/testing/testactivemedia.hpp +++ b/testing/testactivemedia.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "testmedia.hpp" @@ -29,7 +28,7 @@ struct Medium std::mutex buffer_lock; std::thread thr; std::condition_variable ready; - std::atomic running = {false}; + srt::sync::atomic running {false}; std::exception_ptr xp; // To catch exception thrown by a thread virtual void Runner() = 0; @@ -147,22 +146,7 @@ struct TargetMedium: Medium { void Runner() override; - bool Schedule(const MediaPacket& data) - { - LOGP(applog.Debug, "TargetMedium::Schedule LOCK ... "); - std::lock_guard lg(buffer_lock); - LOGP(applog.Debug, "TargetMedium::Schedule LOCKED - checking: running=", running, " interrupt=", ::transmit_int_state); - if (!running || ::transmit_int_state) - { - LOGP(applog.Debug, "TargetMedium::Schedule: not running, discarding packet"); - return false; - } - - LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): Schedule: [", data.payload.size(), "] CLIENT -> BUFFER"); - buffer.push_back(data); - ready.notify_one(); - return true; - } + bool Schedule(const MediaPacket& data); void Clear() { diff --git a/testing/testmedia.cpp b/testing/testmedia.cpp index b9d8a0413..8032109f9 100755 --- a/testing/testmedia.cpp +++ b/testing/testmedia.cpp @@ -20,11 +20,11 @@ #include #include #include -#include #include #if !defined(_WIN32) #include #endif +#include "fmt/format.h" // SRT protected includes #include "netinet_any.h" @@ -50,8 +50,8 @@ using srt_logging::SockStatusStr; using srt_logging::MemberStatusStr; #endif -std::atomic transmit_throw_on_interrupt {false}; -std::atomic transmit_int_state {false}; +srt::sync::atomic transmit_throw_on_interrupt {false}; +srt::sync::atomic transmit_int_state {false}; int transmit_bw_report = 0; unsigned transmit_stats_report = 0; size_t transmit_chunk_size = SRT_LIVE_DEF_PLSIZE; @@ -453,7 +453,7 @@ void SrtCommon::InitParameters(string host, string path, map par) if (transmit_chunk_size > SRT_LIVE_MAX_PLSIZE) throw std::runtime_error("Chunk size in live mode exceeds 1456 bytes; this is not supported"); - par["payloadsize"] = Sprint(transmit_chunk_size); + par["payloadsize"] = fmt::ffcat(transmit_chunk_size); } } @@ -474,10 +474,10 @@ void SrtCommon::InitParameters(string host, string path, map par) int version = srt::SrtParseVersion(v.c_str()); if (version == 0) { - throw std::runtime_error(Sprint("Value for 'minversion' doesn't specify a valid version: ", v)); + throw std::runtime_error(fmt::ffcat("Value for 'minversion' doesn't specify a valid version: ", v)); } - par["minversion"] = Sprint(version); - Verb() << "\tFIXED: minversion = 0x" << std::hex << std::setfill('0') << std::setw(8) << version << std::dec; + par["minversion"] = fmt::ffmts(version); + Verb() << "\tFIXED: minversion = 0x" << fmt::ffmt(version, fmt::hex, fmt::fillzero, fmt::width(8)); } } @@ -1051,7 +1051,7 @@ void SrtCommon::OpenGroupClient() Verb() << "\t[" << c.token << "] " << c.host << ":" << c.port << VerbNoEOL; vector extras; if (c.weight) - extras.push_back(Sprint("weight=", c.weight)); + extras.push_back(fmt::ffcat("weight=", c.weight)); if (!c.source.empty()) extras.push_back("source=" + c.source.str()); diff --git a/testing/testmedia.hpp b/testing/testmedia.hpp index be72471d1..470e825ef 100644 --- a/testing/testmedia.hpp +++ b/testing/testmedia.hpp @@ -15,7 +15,8 @@ #include #include #include -#include + +#include // use srt::sync::atomic instead of std::atomic for the sake of logging #include "apputil.hpp" #include "statswriter.hpp" @@ -25,7 +26,7 @@ extern srt_listen_callback_fn* transmit_accept_hook_fn; extern void* transmit_accept_hook_op; -extern std::atomic transmit_int_state; +extern srt::sync::atomic transmit_int_state; extern std::shared_ptr transmit_stats_writer; diff --git a/testing/testmediabase.hpp b/testing/testmediabase.hpp index 04a85d435..686198787 100644 --- a/testing/testmediabase.hpp +++ b/testing/testmediabase.hpp @@ -11,17 +11,17 @@ #ifndef INC_SRT_COMMON_TRANMITBASE_HPP #define INC_SRT_COMMON_TRANMITBASE_HPP -#include #include #include #include #include #include +#include "sync.h" #include "uriparser.hpp" typedef std::vector bytevector; -extern std::atomic transmit_throw_on_interrupt; +extern srt::sync::atomic transmit_throw_on_interrupt; extern int transmit_bw_report; extern unsigned transmit_stats_report; extern size_t transmit_chunk_size;